diff --git a/api-routes-starter/pages/posts/[id].js b/api-routes-starter/pages/posts/[id].js
index 8dfa98b..b45c6b4 100644
--- a/api-routes-starter/pages/posts/[id].js
+++ b/api-routes-starter/pages/posts/[id].js
@@ -37,5 +37,3 @@ export async function getStaticProps({ params }) {
}
}
}
-
-export default Post
diff --git a/typescript-final/.gitignore b/typescript-final/.gitignore
new file mode 100644
index 0000000..922d92a
--- /dev/null
+++ b/typescript-final/.gitignore
@@ -0,0 +1,25 @@
+# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
+
+# dependencies
+/node_modules
+/.pnp
+.pnp.js
+
+# testing
+/coverage
+
+# next.js
+/.next/
+/out/
+
+# production
+/build
+
+# misc
+.DS_Store
+.env*
+
+# debug
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
diff --git a/typescript-final/README.md b/typescript-final/README.md
new file mode 100644
index 0000000..02695bc
--- /dev/null
+++ b/typescript-final/README.md
@@ -0,0 +1 @@
+This is a starter template for [Learn Next.js](https://nextjs.org/learn).
\ No newline at end of file
diff --git a/typescript-final/components/Date.tsx b/typescript-final/components/Date.tsx
new file mode 100644
index 0000000..70662ea
--- /dev/null
+++ b/typescript-final/components/Date.tsx
@@ -0,0 +1,6 @@
+import { parseISO, format } from 'date-fns'
+
+export default function Date({ dateString }: { dateString: string }) {
+ const date = parseISO(dateString)
+ return
+}
diff --git a/typescript-final/components/Layout.module.css b/typescript-final/components/Layout.module.css
new file mode 100644
index 0000000..d0e3a8f
--- /dev/null
+++ b/typescript-final/components/Layout.module.css
@@ -0,0 +1,25 @@
+.container {
+ max-width: 36rem;
+ padding: 0 1rem;
+ margin: 3rem auto 6rem;
+}
+
+.header {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+}
+
+.headerImage {
+ width: 6rem;
+ height: 6rem;
+}
+
+.headerHomeImage {
+ width: 8rem;
+ height: 8rem;
+}
+
+.backToHome {
+ margin: 3rem 0 0;
+}
diff --git a/typescript-final/components/Layout.tsx b/typescript-final/components/Layout.tsx
new file mode 100644
index 0000000..22f7b79
--- /dev/null
+++ b/typescript-final/components/Layout.tsx
@@ -0,0 +1,70 @@
+import Head from 'next/head'
+import styles from './Layout.module.css'
+import utilStyles from '../styles/utils.module.css'
+import Link from 'next/link'
+
+const name = '[Your Name]'
+export const siteTitle = 'Next.js Sample Website'
+
+export default function Layout({
+ children,
+ home
+}: {
+ children: React.ReactNode
+ home?: boolean
+}) {
+ return (
+
+
+
+
+
+
+
+ {home ? (
+ <>
+
+ {name}
+ >
+ ) : (
+ <>
+
+
+
+
+
+
+ >
+ )}
+
+
{children}
+ {!home && (
+
+ )}
+
+ )
+}
diff --git a/typescript-final/global.d.ts b/typescript-final/global.d.ts
new file mode 100644
index 0000000..b681c31
--- /dev/null
+++ b/typescript-final/global.d.ts
@@ -0,0 +1,4 @@
+declare module 'remark-html' {
+ const html: any
+ export default html
+}
diff --git a/typescript-final/lib/posts.ts b/typescript-final/lib/posts.ts
new file mode 100644
index 0000000..a7d4db7
--- /dev/null
+++ b/typescript-final/lib/posts.ts
@@ -0,0 +1,69 @@
+import fs from 'fs'
+import path from 'path'
+import matter from 'gray-matter'
+import remark from 'remark'
+import html from 'remark-html'
+
+const postsDirectory = path.join(process.cwd(), 'posts')
+
+export function getSortedPostsData() {
+ // Get file names under /posts
+ const fileNames = fs.readdirSync(postsDirectory)
+ const allPostsData = fileNames.map(fileName => {
+ // Remove ".md" from file name to get id
+ const id = fileName.replace(/\.md$/, '')
+
+ // Read markdown file as string
+ const fullPath = path.join(postsDirectory, fileName)
+ const fileContents = fs.readFileSync(fullPath, 'utf8')
+
+ // Use gray-matter to parse the post metadata section
+ const matterResult = matter(fileContents)
+
+ // Combine the data with the id
+ return {
+ id,
+ ...(matterResult.data as { date: string; title: string })
+ }
+ })
+ // Sort posts by date
+ return allPostsData.sort((a, b) => {
+ if (a.date < b.date) {
+ return 1
+ } else {
+ return -1
+ }
+ })
+}
+
+export function getAllPostIds() {
+ const fileNames = fs.readdirSync(postsDirectory)
+ return fileNames.map(fileName => {
+ return {
+ params: {
+ id: fileName.replace(/\.md$/, '')
+ }
+ }
+ })
+}
+
+export async function getPostData(id: string) {
+ const fullPath = path.join(postsDirectory, `${id}.md`)
+ const fileContents = fs.readFileSync(fullPath, 'utf8')
+
+ // Use gray-matter to parse the post metadata section
+ const matterResult = matter(fileContents)
+
+ // Use remark to convert markdown into HTML string
+ const processedContent = await remark()
+ .use(html)
+ .process(matterResult.content)
+ const contentHtml = processedContent.toString()
+
+ // Combine the data with the id and contentHtml
+ return {
+ id,
+ contentHtml,
+ ...(matterResult.data as { date: string; title: string })
+ }
+}
diff --git a/typescript-final/next-env.d.ts b/typescript-final/next-env.d.ts
new file mode 100644
index 0000000..7b7aa2c
--- /dev/null
+++ b/typescript-final/next-env.d.ts
@@ -0,0 +1,2 @@
+///
+///
diff --git a/typescript-final/package.json b/typescript-final/package.json
new file mode 100644
index 0000000..9dace70
--- /dev/null
+++ b/typescript-final/package.json
@@ -0,0 +1,24 @@
+{
+ "name": "my-app",
+ "version": "0.1.0",
+ "private": true,
+ "scripts": {
+ "dev": "next dev",
+ "build": "next build",
+ "start": "next start"
+ },
+ "dependencies": {
+ "date-fns": "^2.11.1",
+ "gray-matter": "^4.0.2",
+ "next": "9.3.4",
+ "react": "16.13.1",
+ "react-dom": "16.13.1",
+ "remark": "^12.0.0",
+ "remark-html": "^11.0.1"
+ },
+ "devDependencies": {
+ "@types/node": "^13.11.0",
+ "@types/react": "^16.9.32",
+ "typescript": "^3.8.3"
+ }
+}
diff --git a/typescript-final/pages/_app.tsx b/typescript-final/pages/_app.tsx
new file mode 100644
index 0000000..6cdcdc2
--- /dev/null
+++ b/typescript-final/pages/_app.tsx
@@ -0,0 +1,6 @@
+import '../styles/global.css'
+import { AppProps } from 'next/app'
+
+export default function App({ Component, pageProps }: AppProps) {
+ return
+}
diff --git a/typescript-final/pages/api/hello.ts b/typescript-final/pages/api/hello.ts
new file mode 100644
index 0000000..7cf37be
--- /dev/null
+++ b/typescript-final/pages/api/hello.ts
@@ -0,0 +1,5 @@
+import { NextApiRequest, NextApiResponse } from 'next'
+
+export default (_: NextApiRequest, res: NextApiResponse) => {
+ res.status(200).json({ text: 'Hello' })
+}
diff --git a/typescript-final/pages/index.tsx b/typescript-final/pages/index.tsx
new file mode 100644
index 0000000..3cf86b2
--- /dev/null
+++ b/typescript-final/pages/index.tsx
@@ -0,0 +1,57 @@
+import Head from 'next/head'
+import Layout, { siteTitle } from '../components/Layout'
+import utilStyles from '../styles/utils.module.css'
+import { getSortedPostsData } from '../lib/posts'
+import Link from 'next/link'
+import Date from '../components/Date'
+import { GetStaticProps } from 'next'
+
+export default function Home({
+ allPostsData
+}: {
+ allPostsData: {
+ date: string
+ title: string
+ id: string
+ }[]
+}) {
+ return (
+
+
+ {siteTitle}
+
+
+ [Your Self Introduction]
+
+ (This is a sample website - you’ll be building a site like this on{' '}
+ our Next.js tutorial.)
+
+
+
+ Blog
+
+ {allPostsData.map(({ id, date, title }) => (
+ -
+
+ {title}
+
+
+
+
+
+
+ ))}
+
+
+
+ )
+}
+
+export const getStaticProps: GetStaticProps = async () => {
+ const allPostsData = getSortedPostsData()
+ return {
+ props: {
+ allPostsData
+ }
+ }
+}
diff --git a/typescript-final/pages/posts/[id].tsx b/typescript-final/pages/posts/[id].tsx
new file mode 100644
index 0000000..86e551f
--- /dev/null
+++ b/typescript-final/pages/posts/[id].tsx
@@ -0,0 +1,48 @@
+import Layout from '../../components/Layout'
+import { getAllPostIds, getPostData } from '../../lib/posts'
+import Head from 'next/head'
+import Date from '../../components/Date'
+import utilStyles from '../../styles/utils.module.css'
+import { GetStaticProps, GetStaticPaths } from 'next'
+
+export default function Post({
+ postData
+}: {
+ postData: {
+ title: string
+ date: string
+ contentHtml: string
+ }
+}) {
+ return (
+
+
+ {postData.title}
+
+
+ {postData.title}
+
+
+
+
+
+
+ )
+}
+
+export const getStaticPaths: GetStaticPaths = async () => {
+ const paths = getAllPostIds()
+ return {
+ paths,
+ fallback: false
+ }
+}
+
+export const getStaticProps: GetStaticProps = async ({ params }) => {
+ const postData = await getPostData(params.id as string)
+ return {
+ props: {
+ postData
+ }
+ }
+}
diff --git a/typescript-final/posts/dps.md b/typescript-final/posts/dps.md
new file mode 100644
index 0000000..878a33d
--- /dev/null
+++ b/typescript-final/posts/dps.md
@@ -0,0 +1,12 @@
+---
+title: "DPS: Develop, Preview, Ship"
+date: "2020-01-02"
+---
+
+[ZEIT Now](https://zeit.co/) supports the **DPS** workflow: **D**evelop, **P**review, and **S**hip:
+
+- **Develop**: Write code in Next.js. Keep the development server running and take advantage of its hot code reloading feature.
+- **Preview**: Every time you push changes to a branch on GitHub / GitLab / BitBucket, ZEIT Now automatically creates a new deployment with a unique URL.
+- **Ship**: When you’re ready to ship, merge the pull request to your default branch (e.g. `master`). ZEIT Now will automatically create a production deployment.
+
+By using the DPS workflow, in addition to doing code reviews, you can do *deployment previews*. Each deployment creates a unique URL that can be shared or used for integration tests.
\ No newline at end of file
diff --git a/typescript-final/posts/pre-rendering.md b/typescript-final/posts/pre-rendering.md
new file mode 100644
index 0000000..78cc081
--- /dev/null
+++ b/typescript-final/posts/pre-rendering.md
@@ -0,0 +1,11 @@
+---
+title: "Two Forms of Pre-rendering"
+date: "2020-01-01"
+---
+
+[Next.js](https://nextjs.org/) has two forms of pre-rendering: **Static Generation** and **Server-side Rendering**. The difference is in **when** it generates the HTML for a page.
+
+- **Static Generation (Recommended)**: The HTML is generated at **build time** and will be reused on each request.
+- **Server-side Rendering**: The HTML is generated on **each request**.
+
+Importantly, Next.js lets you **choose** which pre-rendering form you'd like to use for each page. You can create a "hybrid" Next.js app by using Static Generation for most pages and using Server-side Rendering for others.
\ No newline at end of file
diff --git a/typescript-final/public/favicon.ico b/typescript-final/public/favicon.ico
new file mode 100644
index 0000000..4965832
Binary files /dev/null and b/typescript-final/public/favicon.ico differ
diff --git a/typescript-final/public/images/profile.jpg b/typescript-final/public/images/profile.jpg
new file mode 100644
index 0000000..798aba3
Binary files /dev/null and b/typescript-final/public/images/profile.jpg differ
diff --git a/typescript-final/styles/global.css b/typescript-final/styles/global.css
new file mode 100644
index 0000000..9e1b0fb
--- /dev/null
+++ b/typescript-final/styles/global.css
@@ -0,0 +1,27 @@
+html,
+body {
+ padding: 0;
+ margin: 0;
+ font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen,
+ Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;
+ line-height: 1.6;
+ font-size: 18px;
+}
+
+* {
+ box-sizing: border-box;
+}
+
+a {
+ color: #0070f3;
+ text-decoration: none;
+}
+
+a:hover {
+ text-decoration: underline;
+}
+
+img {
+ max-width: 100%;
+ display: block;
+}
diff --git a/typescript-final/styles/utils.module.css b/typescript-final/styles/utils.module.css
new file mode 100644
index 0000000..37f545e
--- /dev/null
+++ b/typescript-final/styles/utils.module.css
@@ -0,0 +1,52 @@
+.heading2Xl {
+ font-size: 2.5rem;
+ line-height: 1.2;
+ font-weight: 800;
+ letter-spacing: -0.05rem;
+ margin: 1rem 0;
+}
+
+.headingXl {
+ font-size: 2rem;
+ line-height: 1.3;
+ font-weight: 800;
+ letter-spacing: -0.05rem;
+ margin: 1rem 0;
+}
+
+.headingLg {
+ font-size: 1.5rem;
+ line-height: 1.4;
+ margin: 1rem 0;
+}
+
+.headingMd {
+ font-size: 1.2rem;
+ line-height: 1.5;
+}
+
+.borderCircle {
+ border-radius: 9999px;
+}
+
+.colorInherit {
+ color: inherit;
+}
+
+.padding1px {
+ padding-top: 1px;
+}
+
+.list {
+ list-style: none;
+ padding: 0;
+ margin: 0;
+}
+
+.listItem {
+ margin: 0 0 1.25rem;
+}
+
+.lightText {
+ color: #666;
+}
diff --git a/typescript-final/tsconfig.json b/typescript-final/tsconfig.json
new file mode 100644
index 0000000..48ca14a
--- /dev/null
+++ b/typescript-final/tsconfig.json
@@ -0,0 +1,29 @@
+{
+ "compilerOptions": {
+ "target": "es5",
+ "lib": [
+ "dom",
+ "dom.iterable",
+ "esnext"
+ ],
+ "allowJs": true,
+ "skipLibCheck": true,
+ "strict": false,
+ "forceConsistentCasingInFileNames": true,
+ "noEmit": true,
+ "esModuleInterop": true,
+ "module": "esnext",
+ "moduleResolution": "node",
+ "resolveJsonModule": true,
+ "isolatedModules": true,
+ "jsx": "preserve"
+ },
+ "exclude": [
+ "node_modules"
+ ],
+ "include": [
+ "next-env.d.ts",
+ "**/*.ts",
+ "**/*.tsx"
+ ]
+}
diff --git a/typescript-starter/pages/posts/[id].js b/typescript-starter/pages/posts/[id].js
index 8dfa98b..b45c6b4 100644
--- a/typescript-starter/pages/posts/[id].js
+++ b/typescript-starter/pages/posts/[id].js
@@ -37,5 +37,3 @@ export async function getStaticProps({ params }) {
}
}
}
-
-export default Post