forked from vickonrails/next-starter-peacock
-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Migrate to Next.js 14 app directory (#156)
* chore(deps): bump ini from 1.3.5 to 1.3.8 Bumps [ini](https://github.com/isaacs/ini) from 1.3.5 to 1.3.8. - [Release notes](https://github.com/isaacs/ini/releases) - [Commits](npm/ini@v1.3.5...v1.3.8) Signed-off-by: dependabot[bot] <[email protected]> * chore(deps): bump y18n from 4.0.0 to 4.0.3 Bumps [y18n](https://github.com/yargs/y18n) from 4.0.0 to 4.0.3. - [Release notes](https://github.com/yargs/y18n/releases) - [Changelog](https://github.com/yargs/y18n/blob/y18n-v4.0.3/CHANGELOG.md) - [Commits](yargs/y18n@v4.0.0...y18n-v4.0.3) Signed-off-by: dependabot[bot] <[email protected]> * chore(deps): bump ssri from 6.0.1 to 6.0.2 Bumps [ssri](https://github.com/npm/ssri) from 6.0.1 to 6.0.2. - [Release notes](https://github.com/npm/ssri/releases) - [Changelog](https://github.com/npm/ssri/blob/v6.0.2/CHANGELOG.md) - [Commits](npm/ssri@v6.0.1...v6.0.2) Signed-off-by: dependabot[bot] <[email protected]> * chore(deps): bump elliptic from 6.5.3 to 6.5.4 Bumps [elliptic](https://github.com/indutny/elliptic) from 6.5.3 to 6.5.4. - [Release notes](https://github.com/indutny/elliptic/releases) - [Commits](indutny/elliptic@v6.5.3...v6.5.4) Signed-off-by: dependabot[bot] <[email protected]> * Add renovate.json * fix(deps): pin dependencies * chore(deps): update dependency @types/node to v14.14.43 * Add pinned dependencies * Add pins to dependencies * feat: add plausible analytics * fix: use url for post id instead of randomly generated id. fixes #10 * chore: remove plausible analysis ��♂️ * fix: use url for post id instead of randomly generated id. fixed #10 * Fix typo * Change react-tilt to react-parallax-tilt * Revert to double quotes * Update options * chore: upgrade packages * refactor: remove <a> tags from <Link> * fix: add eslint-config-next and fix linting issues * fix: breaking build * chore: install tailwindcss deps * refactor: remove emotion styled from codebase * chore: remove emotion packages * refactor: bring in global css to tailwind base * chore: migrate articles to app router * chore: move all pages to app router * refactor: mobile navigation * refactor: support tags page * feat: statically generate all content * chore: add alias for component imports * refactor: add alias for utils, various refactors * Switch Emotion to Tailwind CSS * chore: various layout changes and refactor * chore: more ui refactors * feat: various ui improvements * feat: switch to feed for rss * feat: generate rss for articles at build time * fix: perfect mobile navigation * fix: correct dark mode * chore: upgrade to next 14 * chore: implement seo and social images * fix: social previews * chore: various refactors, add dummy content * chore: update documentation * Switch Emotion to Tailwind CSS * chore: update documentation * Fix merge conflicts * Fix merge conflicts * Update dependencies * Update config, package.json, remove css duplication * Add Prettier changes * Update Readme * Update Playwright test * Add highlight.js * Fix imports * Fix imports, Prettier changes * Fix postcss for Tailwind * Refactor import statements and variable names * Refactor key values in components * Fix TypeScript errors * Add data-test-ids * Remove .eslintrc.json and fix minor TS errors * Add line break * Remove empty line * Remove empty line * Refactor test, remove data-test-id * Update lockfile --------- Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Renovate Bot <[email protected]> Co-authored-by: José Fernando Höwer Barbosa <[email protected]> Co-authored-by: Josehower <[email protected]> Co-authored-by: Victor Ofoegbu <[email protected]> Co-authored-by: Karl Horky <[email protected]>
- Loading branch information
1 parent
1c511f2
commit a1af9f5
Showing
123 changed files
with
3,116 additions
and
3,375 deletions.
There are no files selected for viewing
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -34,6 +34,8 @@ yarn-error.log* | |
# vercel | ||
.vercel | ||
|
||
public/rss.xml | ||
|
||
.eslintcache | ||
*.tsbuildinfo | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
'use client'; | ||
import hljs from 'highlight.js/lib/core'; | ||
import javascript from 'highlight.js/lib/languages/javascript'; | ||
import { useEffect } from 'react'; | ||
|
||
export default function Content({ html }: { html: string }) { | ||
useEffect(() => { | ||
hljs.registerLanguage('javascript', javascript); | ||
hljs.highlightAll(); | ||
}, []); | ||
|
||
return ( | ||
<div | ||
className="content-body mb-8" | ||
dangerouslySetInnerHTML={{ __html: html }} | ||
/> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,189 @@ | ||
import { Metadata } from 'next'; | ||
import Image from 'next/image'; | ||
import { notFound } from 'next/navigation'; | ||
import { Chips, Container } from '../../../components'; | ||
import BackButton from '../../../components/back-button'; | ||
import { author, site } from '../../../config/index.json'; | ||
import { | ||
getContentData, | ||
getContentList, | ||
getContentTypes, | ||
IContentType, | ||
} from '../../../utils/content'; | ||
import { contentTypesMap } from '../../../utils/content-types'; | ||
import Content from './content'; | ||
|
||
export async function generateMetadata({ | ||
params, | ||
}: { | ||
params: Params; | ||
}): Promise<Metadata> { | ||
const { title, previewImage, description } = await getContentData( | ||
params.slug, | ||
params.contentType, | ||
); | ||
return { | ||
title: `${title} | ${site.siteTitle}`, | ||
description: description ?? site.siteDescription, | ||
openGraph: { | ||
title: `${title} | ${site.siteName}`, | ||
description: description ?? site.siteDescription, | ||
url: site.siteUrl, | ||
images: previewImage ?? site.siteImage, | ||
siteName: site.siteName, | ||
}, | ||
twitter: { | ||
card: 'summary_large_image', | ||
creator: author.twitterHandle, | ||
images: previewImage ?? site.siteImage, | ||
}, | ||
}; | ||
} | ||
|
||
/** | ||
* statically generate all content pages | ||
*/ | ||
export function generateStaticParams() { | ||
const contentTypes = getContentTypes(); | ||
|
||
return contentTypes.flatMap((contentType) => { | ||
const contentList = getContentList(contentType); | ||
return contentList.map(({ slug }) => { | ||
return { | ||
contentType, | ||
slug, | ||
}; | ||
}); | ||
}); | ||
} | ||
|
||
/** | ||
* Renders articles markdown posts | ||
*/ | ||
|
||
async function fetchContentData(slug: string, contentType: IContentType) { | ||
return await getContentData(slug, contentType); | ||
} | ||
|
||
type Params = { | ||
slug: string; | ||
contentType: IContentType; | ||
}; | ||
|
||
export default async function ContentPage({ params }: { params: Params }) { | ||
const { slug, contentType } = params; | ||
|
||
if (!contentTypesMap.has(contentType)) { | ||
return notFound(); | ||
} | ||
|
||
const content = await fetchContentData(slug, contentType); | ||
if (content.draft) return notFound(); | ||
|
||
if (contentType === 'works') return <WorkPage work={content} />; | ||
|
||
return ( | ||
<Container width="narrow"> | ||
<header> | ||
<section className="pt-16"> | ||
<h1 className="my-0 font-bold font-display mb-2 text-2xl/normal md:text-4xl max-w-xl"> | ||
{content.title} | ||
</h1> | ||
<time className="block text-accent-4 mb-8"> | ||
{content.date.toString()} | ||
</time> | ||
{content.previewImage && ( | ||
<Image | ||
className="pb-8 block object-cover" | ||
src={content.previewImage} | ||
height={550} | ||
width={1200} | ||
alt="" | ||
/> | ||
)} | ||
</section> | ||
</header> | ||
|
||
<Content html={content.contentHtml} /> | ||
{content.tags && <Chips items={content.tags} />} | ||
</Container> | ||
); | ||
} | ||
|
||
function WorkPage({ work }: { work: IContentData }) { | ||
return ( | ||
<Container className="flex flex-col lg:flex-row gap-4 pt-12"> | ||
<section className="w-full lg:w-1/3 border-r border-accent-8 p-2 pr-8"> | ||
<div className="mb-8 flex flex-col items-start gap-5"> | ||
<BackButton /> | ||
<h1 className="text-4xl font-bold font-display text-accent-3"> | ||
{work.title} | ||
</h1> | ||
<p className="text-accent-4">{work.description}</p> | ||
<button>Se Demo</button> | ||
</div> | ||
|
||
<ul> | ||
<TechStack techStack={work.techStack ?? []} /> | ||
<MetadataListItem item="Date" value={work.date.toString()} /> | ||
{Boolean(work.problem) && ( | ||
<MetadataListItem item="Problem" value={work.problem ?? ''} /> | ||
)} | ||
</ul> | ||
</section> | ||
|
||
<section className="w-full lg:w-2/3 p-2"> | ||
<Image | ||
src={work.previewImage ?? ''} | ||
height={1000} | ||
width={1000} | ||
alt="" | ||
className="mb-4" | ||
/> | ||
<Content html={work.contentHtml} /> | ||
</section> | ||
</Container> | ||
); | ||
} | ||
|
||
function MetadataListItem({ item, value }: { item: string; value: string }) { | ||
return ( | ||
<li className="list-none flex gap-4 border-b border-accent-8 py-3 text-sm"> | ||
<span className="text-accent-4 w-1/3">{item}</span> | ||
<span className="w-2/3 text-accent-2">{value}</span> | ||
</li> | ||
); | ||
} | ||
|
||
function TechStack({ techStack }: { techStack: string[] }) { | ||
if (!techStack.length) return null; | ||
return ( | ||
<li className="list-none flex gap-4 border-b border-accent-8 py-3 text-sm"> | ||
<span className="text-accent-4 w-1/3 flex-shrink-0">Tech Stack</span> | ||
|
||
<ul className="flex flex-wrap gap-2 flex-grow-0"> | ||
{techStack.map((tech) => ( | ||
<li | ||
key={`techStack-${tech}`} | ||
className="select-none bg-accent-8 text-accent-2 px-2 py-1 rounded-md" | ||
> | ||
{tech} | ||
</li> | ||
))} | ||
</ul> | ||
</li> | ||
); | ||
} | ||
|
||
export interface IContentData { | ||
id: string; | ||
contentHtml: string; | ||
date: Date; | ||
title: string; | ||
previewImage?: string; | ||
description?: string; | ||
tags?: string[]; | ||
category?: string; | ||
problem?: string; | ||
techStack?: string[]; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
import { Metadata } from 'next'; | ||
import { notFound } from 'next/navigation'; | ||
import { Container, ContentList } from '../../components'; | ||
import { site } from '../../config/index.json'; | ||
import { | ||
getContentList, | ||
getContentTypes, | ||
IContentType, | ||
} from '../../utils/content'; | ||
import { contentTypesMap } from '../../utils/content-types'; | ||
import { generateRSS } from '../../utils/rss'; | ||
|
||
type Params = { | ||
contentType: IContentType; | ||
}; | ||
|
||
/** generate list page metadata */ | ||
export function generateMetadata({ params }: { params: Params }): Metadata { | ||
const contentType = contentTypesMap.get(params.contentType); | ||
return { | ||
title: `${contentType.title} | ${site.siteTitle}`, | ||
description: contentType.description, | ||
}; | ||
} | ||
|
||
export function generateStaticParams() { | ||
generateRSS(); | ||
|
||
const contentTypes = getContentTypes(); | ||
return Array.from(contentTypes).map((contentType) => ({ | ||
contentType, | ||
})); | ||
} | ||
|
||
/** | ||
* Index page `/index` | ||
*/ | ||
export default function ContentListPage({ params }: { params: Params }) { | ||
const contentType = params.contentType; | ||
|
||
// redirect to 404 with wrong contentType | ||
if (!contentTypesMap.has(contentType)) { | ||
return notFound(); | ||
} | ||
|
||
const content = getContentList(contentType); | ||
const isNotes = contentType.toLowerCase() === 'notes'; | ||
const { title, path, description } = contentTypesMap.get(contentType); | ||
|
||
return ( | ||
<Container width={isNotes ? 'narrow' : 'default'}> | ||
<section className="flex flex-col py-20 gap-2 max-w-2xl"> | ||
<h1 className="text-4xl font-bold font-display">{title}</h1> | ||
<p className="text-accent-4 text-lg">{description}</p> | ||
</section> | ||
|
||
<ContentList basePath={path} items={content} contentType={contentType} /> | ||
</Container> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
import { Container, ContentList } from '../../../../components'; | ||
import { getContentWithTag, IContentType } from '../../../../utils/content'; | ||
import { contentTypesMap } from '../../../../utils/content-types'; | ||
|
||
// TODO: I need to rethink the tags page. I don't think I want to have a page for each tag. | ||
// /notes/tags/programming & /articles/tags/programming. Instead I want to have a single page for all tags | ||
// /tags/programming. I think this will be easier to manage and will be more intuitive for readers. | ||
|
||
/** | ||
* Index page `/index` | ||
*/ | ||
export default function ContentListPage({ | ||
params, | ||
}: { | ||
params: { | ||
contentType: IContentType; | ||
tag: IContentType; | ||
}; | ||
}) { | ||
const contentType = params.contentType; | ||
const tag = params.tag; | ||
|
||
const content = getContentWithTag(tag, contentType); | ||
const isNotes = contentType.toLowerCase() === 'notes'; | ||
const { title, path, description } = contentTypesMap.get(contentType); | ||
|
||
return ( | ||
<Container width={isNotes ? 'narrow' : 'default'}> | ||
<section className="flex flex-col py-20 gap-2 max-w-2xl"> | ||
<h1 className="text-4xl font-bold font-display">{title} Tags</h1> | ||
<p className="text-accent-4 text-lg">{description}</p> | ||
</section> | ||
<ContentList contentType={contentType} items={content} basePath={path} /> | ||
</Container> | ||
); | ||
} |
Oops, something went wrong.