diff --git a/README.md b/README.md new file mode 100644 index 0000000..588278e --- /dev/null +++ b/README.md @@ -0,0 +1,5 @@ +# next-learn-starter + +This repository contains starter templates for [Learn Next.js](https://nextjs.org/learn). + +The final result for the basics lesson can be found in the [basics-final](basics-final) directory and is available at: [https://next-learn-starter.now.sh/](https://next-learn-starter.now.sh/). \ No newline at end of file diff --git a/api-routes-starter/.gitignore b/api-routes-starter/.gitignore new file mode 100644 index 0000000..922d92a --- /dev/null +++ b/api-routes-starter/.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/api-routes-starter/README.md b/api-routes-starter/README.md new file mode 100644 index 0000000..02695bc --- /dev/null +++ b/api-routes-starter/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/api-routes-starter/components/date.js b/api-routes-starter/components/date.js new file mode 100644 index 0000000..0ec71d3 --- /dev/null +++ b/api-routes-starter/components/date.js @@ -0,0 +1,6 @@ +import { parseISO, format } from 'date-fns' + +export default function Date({ dateString }) { + const date = parseISO(dateString) + return +} diff --git a/api-routes-starter/components/layout.js b/api-routes-starter/components/layout.js new file mode 100644 index 0000000..cff0cca --- /dev/null +++ b/api-routes-starter/components/layout.js @@ -0,0 +1,64 @@ +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 }) { + return ( +
+ + + + + +
+ {home ? ( + <> + {name} +

{name}

+ + ) : ( + <> + + + {name} + + +

+ + {name} + +

+ + )} +
+
{children}
+ {!home && ( +
+ + ← Back to home + +
+ )} +
+ ) +} diff --git a/api-routes-starter/components/layout.module.css b/api-routes-starter/components/layout.module.css new file mode 100644 index 0000000..d0e3a8f --- /dev/null +++ b/api-routes-starter/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/api-routes-starter/lib/posts.js b/api-routes-starter/lib/posts.js new file mode 100644 index 0000000..53d8653 --- /dev/null +++ b/api-routes-starter/lib/posts.js @@ -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 + } + }) + // 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) { + 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 + } +} diff --git a/api-routes-starter/package.json b/api-routes-starter/package.json new file mode 100644 index 0000000..b879f50 --- /dev/null +++ b/api-routes-starter/package.json @@ -0,0 +1,19 @@ +{ + "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" + } +} diff --git a/api-routes-starter/pages/_app.js b/api-routes-starter/pages/_app.js new file mode 100644 index 0000000..7e66efc --- /dev/null +++ b/api-routes-starter/pages/_app.js @@ -0,0 +1,5 @@ +import '../styles/global.css' + +export default function App({ Component, pageProps }) { + return +} diff --git a/api-routes-starter/pages/index.js b/api-routes-starter/pages/index.js new file mode 100644 index 0000000..0f9494b --- /dev/null +++ b/api-routes-starter/pages/index.js @@ -0,0 +1,48 @@ +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' + +export default function Home({ allPostsData }) { + 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 async function getStaticProps() { + const allPostsData = getSortedPostsData() + return { + props: { + allPostsData + } + } +} diff --git a/api-routes-starter/pages/posts/[id].js b/api-routes-starter/pages/posts/[id].js new file mode 100644 index 0000000..28faaad --- /dev/null +++ b/api-routes-starter/pages/posts/[id].js @@ -0,0 +1,39 @@ +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' + +export default function Post({ postData }) { + return ( + + + {postData.title} + +
+

{postData.title}

+
+ +
+
+
+
+ ) +} + +export async function getStaticPaths() { + const paths = getAllPostIds() + return { + paths, + fallback: false + } +} + +export async function getStaticProps({ params }) { + const postData = await getPostData(params.id) + return { + props: { + postData + } + } +} diff --git a/api-routes-starter/posts/dps.md b/api-routes-starter/posts/dps.md new file mode 100644 index 0000000..878a33d --- /dev/null +++ b/api-routes-starter/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/api-routes-starter/posts/pre-rendering.md b/api-routes-starter/posts/pre-rendering.md new file mode 100644 index 0000000..78cc081 --- /dev/null +++ b/api-routes-starter/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/api-routes-starter/public/favicon.ico b/api-routes-starter/public/favicon.ico new file mode 100644 index 0000000..4965832 Binary files /dev/null and b/api-routes-starter/public/favicon.ico differ diff --git a/api-routes-starter/public/images/profile.jpg b/api-routes-starter/public/images/profile.jpg new file mode 100644 index 0000000..798aba3 Binary files /dev/null and b/api-routes-starter/public/images/profile.jpg differ diff --git a/api-routes-starter/styles/global.css b/api-routes-starter/styles/global.css new file mode 100644 index 0000000..9e1b0fb --- /dev/null +++ b/api-routes-starter/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/api-routes-starter/styles/utils.module.css b/api-routes-starter/styles/utils.module.css new file mode 100644 index 0000000..37f545e --- /dev/null +++ b/api-routes-starter/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/assets-metadata-css-starter/.gitignore b/assets-metadata-css-starter/.gitignore new file mode 100644 index 0000000..922d92a --- /dev/null +++ b/assets-metadata-css-starter/.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/assets-metadata-css-starter/README.md b/assets-metadata-css-starter/README.md new file mode 100644 index 0000000..02695bc --- /dev/null +++ b/assets-metadata-css-starter/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/assets-metadata-css-starter/package.json b/assets-metadata-css-starter/package.json new file mode 100644 index 0000000..899e758 --- /dev/null +++ b/assets-metadata-css-starter/package.json @@ -0,0 +1,15 @@ +{ + "name": "my-app", + "version": "0.1.0", + "private": true, + "scripts": { + "dev": "next dev", + "build": "next build", + "start": "next start" + }, + "dependencies": { + "next": "9.3.4", + "react": "16.13.1", + "react-dom": "16.13.1" + } +} diff --git a/assets-metadata-css-starter/pages/index.js b/assets-metadata-css-starter/pages/index.js new file mode 100644 index 0000000..33a0627 --- /dev/null +++ b/assets-metadata-css-starter/pages/index.js @@ -0,0 +1,207 @@ +import Link from 'next/link' +import Head from 'next/head' + +const Home = () => ( +
+ + Create Next App + + + +
+

+ Read{' '} + + this page! + +

+ +

+ Get started by editing pages/index.js +

+ +
+ +

Documentation →

+

Find in-depth information about Next.js features and API.

+
+ + +

Learn →

+

Learn about Next.js in an interactive course with quizzes!

+
+ + +

Examples →

+

Discover and deploy boilerplate example Next.js projects.

+
+ + +

Deploy →

+

+ Instantly deploy your Next.js site to a public URL with ZEIT Now. +

+
+
+
+ + + + + + +
+) + +export default Home diff --git a/assets-metadata-css-starter/pages/posts/first-post.js b/assets-metadata-css-starter/pages/posts/first-post.js new file mode 100644 index 0000000..7f840e5 --- /dev/null +++ b/assets-metadata-css-starter/pages/posts/first-post.js @@ -0,0 +1,14 @@ +import Link from 'next/link' + +export default function FirstPost() { + return ( + <> +

First Post

+

+ + Back to home + +

+ + ) +} diff --git a/assets-metadata-css-starter/public/favicon.ico b/assets-metadata-css-starter/public/favicon.ico new file mode 100644 index 0000000..4965832 Binary files /dev/null and b/assets-metadata-css-starter/public/favicon.ico differ diff --git a/assets-metadata-css-starter/public/zeit.svg b/assets-metadata-css-starter/public/zeit.svg new file mode 100644 index 0000000..dd3916c --- /dev/null +++ b/assets-metadata-css-starter/public/zeit.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/basics-final/.gitignore b/basics-final/.gitignore new file mode 100644 index 0000000..922d92a --- /dev/null +++ b/basics-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/basics-final/README.md b/basics-final/README.md new file mode 100644 index 0000000..02695bc --- /dev/null +++ b/basics-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/basics-final/components/date.js b/basics-final/components/date.js new file mode 100644 index 0000000..0ec71d3 --- /dev/null +++ b/basics-final/components/date.js @@ -0,0 +1,6 @@ +import { parseISO, format } from 'date-fns' + +export default function Date({ dateString }) { + const date = parseISO(dateString) + return +} diff --git a/basics-final/components/layout.js b/basics-final/components/layout.js new file mode 100644 index 0000000..1cf9c69 --- /dev/null +++ b/basics-final/components/layout.js @@ -0,0 +1,64 @@ +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 = 'Shu Uesugi' +export const siteTitle = 'Next.js Sample Website' + +export default function Layout({ children, home }) { + return ( +
+ + + + + +
+ {home ? ( + <> + {name} +

{name}

+ + ) : ( + <> + + + {name} + + +

+ + {name} + +

+ + )} +
+
{children}
+ {!home && ( +
+ + ← Back to home + +
+ )} +
+ ) +} diff --git a/basics-final/components/layout.module.css b/basics-final/components/layout.module.css new file mode 100644 index 0000000..d0e3a8f --- /dev/null +++ b/basics-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/basics-final/lib/posts.js b/basics-final/lib/posts.js new file mode 100644 index 0000000..53d8653 --- /dev/null +++ b/basics-final/lib/posts.js @@ -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 + } + }) + // 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) { + 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 + } +} diff --git a/basics-final/package.json b/basics-final/package.json new file mode 100644 index 0000000..b879f50 --- /dev/null +++ b/basics-final/package.json @@ -0,0 +1,19 @@ +{ + "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" + } +} diff --git a/basics-final/pages/_app.js b/basics-final/pages/_app.js new file mode 100644 index 0000000..7e66efc --- /dev/null +++ b/basics-final/pages/_app.js @@ -0,0 +1,5 @@ +import '../styles/global.css' + +export default function App({ Component, pageProps }) { + return +} diff --git a/basics-final/pages/api/hello.js b/basics-final/pages/api/hello.js new file mode 100644 index 0000000..2e22ab3 --- /dev/null +++ b/basics-final/pages/api/hello.js @@ -0,0 +1,3 @@ +export default (req, res) => { + res.status(200).json({ text: 'Hello' }) +} diff --git a/basics-final/pages/index.js b/basics-final/pages/index.js new file mode 100644 index 0000000..1f4acc0 --- /dev/null +++ b/basics-final/pages/index.js @@ -0,0 +1,54 @@ +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' + +export default function Home({ allPostsData }) { + return ( + + + {siteTitle} + +
+

+ Hello, I’m Shu. I write code at{' '} + ZEIT, the team behind{' '} + Next.js. You can contact me via{' '} + Twitter or{' '} + email. +

+

+ (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 async function getStaticProps() { + const allPostsData = getSortedPostsData() + return { + props: { + allPostsData + } + } +} diff --git a/basics-final/pages/posts/[id].js b/basics-final/pages/posts/[id].js new file mode 100644 index 0000000..28faaad --- /dev/null +++ b/basics-final/pages/posts/[id].js @@ -0,0 +1,39 @@ +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' + +export default function Post({ postData }) { + return ( + + + {postData.title} + +
+

{postData.title}

+
+ +
+
+
+
+ ) +} + +export async function getStaticPaths() { + const paths = getAllPostIds() + return { + paths, + fallback: false + } +} + +export async function getStaticProps({ params }) { + const postData = await getPostData(params.id) + return { + props: { + postData + } + } +} diff --git a/basics-final/posts/dps.md b/basics-final/posts/dps.md new file mode 100644 index 0000000..878a33d --- /dev/null +++ b/basics-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/basics-final/posts/pre-rendering.md b/basics-final/posts/pre-rendering.md new file mode 100644 index 0000000..78cc081 --- /dev/null +++ b/basics-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/basics-final/public/favicon.ico b/basics-final/public/favicon.ico new file mode 100644 index 0000000..4965832 Binary files /dev/null and b/basics-final/public/favicon.ico differ diff --git a/basics-final/public/images/profile.jpg b/basics-final/public/images/profile.jpg new file mode 100644 index 0000000..928d903 Binary files /dev/null and b/basics-final/public/images/profile.jpg differ diff --git a/basics-final/styles/global.css b/basics-final/styles/global.css new file mode 100644 index 0000000..9e1b0fb --- /dev/null +++ b/basics-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/basics-final/styles/utils.module.css b/basics-final/styles/utils.module.css new file mode 100644 index 0000000..37f545e --- /dev/null +++ b/basics-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/data-fetching-starter/.gitignore b/data-fetching-starter/.gitignore new file mode 100644 index 0000000..922d92a --- /dev/null +++ b/data-fetching-starter/.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/data-fetching-starter/README.md b/data-fetching-starter/README.md new file mode 100644 index 0000000..02695bc --- /dev/null +++ b/data-fetching-starter/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/data-fetching-starter/components/layout.js b/data-fetching-starter/components/layout.js new file mode 100644 index 0000000..cff0cca --- /dev/null +++ b/data-fetching-starter/components/layout.js @@ -0,0 +1,64 @@ +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 }) { + return ( +
+ + + + + +
+ {home ? ( + <> + {name} +

{name}

+ + ) : ( + <> + + + {name} + + +

+ + {name} + +

+ + )} +
+
{children}
+ {!home && ( +
+ + ← Back to home + +
+ )} +
+ ) +} diff --git a/data-fetching-starter/components/layout.module.css b/data-fetching-starter/components/layout.module.css new file mode 100644 index 0000000..d0e3a8f --- /dev/null +++ b/data-fetching-starter/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/data-fetching-starter/package.json b/data-fetching-starter/package.json new file mode 100644 index 0000000..899e758 --- /dev/null +++ b/data-fetching-starter/package.json @@ -0,0 +1,15 @@ +{ + "name": "my-app", + "version": "0.1.0", + "private": true, + "scripts": { + "dev": "next dev", + "build": "next build", + "start": "next start" + }, + "dependencies": { + "next": "9.3.4", + "react": "16.13.1", + "react-dom": "16.13.1" + } +} diff --git a/data-fetching-starter/pages/_app.js b/data-fetching-starter/pages/_app.js new file mode 100644 index 0000000..a508286 --- /dev/null +++ b/data-fetching-starter/pages/_app.js @@ -0,0 +1,7 @@ +import '../styles/global.css' + +export default function App({ Component, pageProps }) { + return +} + +export default App diff --git a/data-fetching-starter/pages/index.js b/data-fetching-starter/pages/index.js new file mode 100644 index 0000000..be1afc7 --- /dev/null +++ b/data-fetching-starter/pages/index.js @@ -0,0 +1,20 @@ +import Head from 'next/head' +import Layout, { siteTitle } from '../components/layout' +import utilStyles from '../styles/utils.module.css' + +export default function Home() { + return ( + + + {siteTitle} + +
+

[Your Self Introduction]

+

+ (This is a sample website - you’ll be building a site like this on{' '} + our Next.js tutorial.) +

+
+
+ ) +} diff --git a/data-fetching-starter/pages/posts/first-post.js b/data-fetching-starter/pages/posts/first-post.js new file mode 100644 index 0000000..887057f --- /dev/null +++ b/data-fetching-starter/pages/posts/first-post.js @@ -0,0 +1,19 @@ +import Head from 'next/head' +import Link from 'next/link' +import Layout from '../../components/layout' + +export default function FirstPost() { + return ( + + + First Post + +

First Post

+

+ + Back to home + +

+
+ ) +} diff --git a/data-fetching-starter/public/favicon.ico b/data-fetching-starter/public/favicon.ico new file mode 100644 index 0000000..4965832 Binary files /dev/null and b/data-fetching-starter/public/favicon.ico differ diff --git a/data-fetching-starter/public/images/profile.jpg b/data-fetching-starter/public/images/profile.jpg new file mode 100644 index 0000000..798aba3 Binary files /dev/null and b/data-fetching-starter/public/images/profile.jpg differ diff --git a/data-fetching-starter/public/zeit.svg b/data-fetching-starter/public/zeit.svg new file mode 100644 index 0000000..dd3916c --- /dev/null +++ b/data-fetching-starter/public/zeit.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/data-fetching-starter/styles/global.css b/data-fetching-starter/styles/global.css new file mode 100644 index 0000000..9e1b0fb --- /dev/null +++ b/data-fetching-starter/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/data-fetching-starter/styles/utils.module.css b/data-fetching-starter/styles/utils.module.css new file mode 100644 index 0000000..37f545e --- /dev/null +++ b/data-fetching-starter/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/dynamic-routes-starter/.gitignore b/dynamic-routes-starter/.gitignore new file mode 100644 index 0000000..922d92a --- /dev/null +++ b/dynamic-routes-starter/.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/dynamic-routes-starter/README.md b/dynamic-routes-starter/README.md new file mode 100644 index 0000000..02695bc --- /dev/null +++ b/dynamic-routes-starter/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/dynamic-routes-starter/components/layout.js b/dynamic-routes-starter/components/layout.js new file mode 100644 index 0000000..cff0cca --- /dev/null +++ b/dynamic-routes-starter/components/layout.js @@ -0,0 +1,64 @@ +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 }) { + return ( +
+ + + + + +
+ {home ? ( + <> + {name} +

{name}

+ + ) : ( + <> + + + {name} + + +

+ + {name} + +

+ + )} +
+
{children}
+ {!home && ( +
+ + ← Back to home + +
+ )} +
+ ) +} diff --git a/dynamic-routes-starter/components/layout.module.css b/dynamic-routes-starter/components/layout.module.css new file mode 100644 index 0000000..d0e3a8f --- /dev/null +++ b/dynamic-routes-starter/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/dynamic-routes-starter/lib/posts.js b/dynamic-routes-starter/lib/posts.js new file mode 100644 index 0000000..46d820c --- /dev/null +++ b/dynamic-routes-starter/lib/posts.js @@ -0,0 +1,35 @@ +import fs from 'fs' +import path from 'path' +import matter from 'gray-matter' + +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 + } + }) + // Sort posts by date + return allPostsData.sort((a, b) => { + if (a.date < b.date) { + return 1 + } else { + return -1 + } + }) +} diff --git a/dynamic-routes-starter/package.json b/dynamic-routes-starter/package.json new file mode 100644 index 0000000..bc4c8b5 --- /dev/null +++ b/dynamic-routes-starter/package.json @@ -0,0 +1,16 @@ +{ + "name": "my-app", + "version": "0.1.0", + "private": true, + "scripts": { + "dev": "next dev", + "build": "next build", + "start": "next start" + }, + "dependencies": { + "gray-matter": "^4.0.2", + "next": "9.3.4", + "react": "16.13.1", + "react-dom": "16.13.1" + } +} diff --git a/dynamic-routes-starter/pages/_app.js b/dynamic-routes-starter/pages/_app.js new file mode 100644 index 0000000..a508286 --- /dev/null +++ b/dynamic-routes-starter/pages/_app.js @@ -0,0 +1,7 @@ +import '../styles/global.css' + +export default function App({ Component, pageProps }) { + return +} + +export default App diff --git a/dynamic-routes-starter/pages/index.js b/dynamic-routes-starter/pages/index.js new file mode 100644 index 0000000..24ba2c6 --- /dev/null +++ b/dynamic-routes-starter/pages/index.js @@ -0,0 +1,40 @@ +import Head from 'next/head' +import Layout, { siteTitle } from '../components/layout' +import utilStyles from '../styles/utils.module.css' +import { getSortedPostsData } from '../lib/posts' + +export default function Home({ allPostsData }) { + return ( + + + {siteTitle} + +
+

[Your Self Introduction]

+
+
+

Blog

+
    + {allPostsData.map(({ id, date, title }) => ( +
  • + {title} +
    + {id} +
    + {date} +
  • + ))} +
+
+
+ ) +} + +export async function getStaticProps() { + const allPostsData = getSortedPostsData() + return { + props: { + allPostsData + } + } +} diff --git a/dynamic-routes-starter/pages/posts/first-post.js b/dynamic-routes-starter/pages/posts/first-post.js new file mode 100644 index 0000000..887057f --- /dev/null +++ b/dynamic-routes-starter/pages/posts/first-post.js @@ -0,0 +1,19 @@ +import Head from 'next/head' +import Link from 'next/link' +import Layout from '../../components/layout' + +export default function FirstPost() { + return ( + + + First Post + +

First Post

+

+ + Back to home + +

+
+ ) +} diff --git a/dynamic-routes-starter/posts/dps.md b/dynamic-routes-starter/posts/dps.md new file mode 100644 index 0000000..878a33d --- /dev/null +++ b/dynamic-routes-starter/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/dynamic-routes-starter/posts/pre-rendering.md b/dynamic-routes-starter/posts/pre-rendering.md new file mode 100644 index 0000000..78cc081 --- /dev/null +++ b/dynamic-routes-starter/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/dynamic-routes-starter/public/favicon.ico b/dynamic-routes-starter/public/favicon.ico new file mode 100644 index 0000000..4965832 Binary files /dev/null and b/dynamic-routes-starter/public/favicon.ico differ diff --git a/dynamic-routes-starter/public/images/profile.jpg b/dynamic-routes-starter/public/images/profile.jpg new file mode 100644 index 0000000..798aba3 Binary files /dev/null and b/dynamic-routes-starter/public/images/profile.jpg differ diff --git a/dynamic-routes-starter/styles/global.css b/dynamic-routes-starter/styles/global.css new file mode 100644 index 0000000..9e1b0fb --- /dev/null +++ b/dynamic-routes-starter/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/dynamic-routes-starter/styles/utils.module.css b/dynamic-routes-starter/styles/utils.module.css new file mode 100644 index 0000000..37f545e --- /dev/null +++ b/dynamic-routes-starter/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/license.md b/license.md new file mode 100644 index 0000000..4a8b342 --- /dev/null +++ b/license.md @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2016-present ZEIT, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/navigate-between-pages-starter/.gitignore b/navigate-between-pages-starter/.gitignore new file mode 100644 index 0000000..922d92a --- /dev/null +++ b/navigate-between-pages-starter/.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/navigate-between-pages-starter/README.md b/navigate-between-pages-starter/README.md new file mode 100644 index 0000000..02695bc --- /dev/null +++ b/navigate-between-pages-starter/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/navigate-between-pages-starter/package.json b/navigate-between-pages-starter/package.json new file mode 100644 index 0000000..899e758 --- /dev/null +++ b/navigate-between-pages-starter/package.json @@ -0,0 +1,15 @@ +{ + "name": "my-app", + "version": "0.1.0", + "private": true, + "scripts": { + "dev": "next dev", + "build": "next build", + "start": "next start" + }, + "dependencies": { + "next": "9.3.4", + "react": "16.13.1", + "react-dom": "16.13.1" + } +} diff --git a/navigate-between-pages-starter/pages/index.js b/navigate-between-pages-starter/pages/index.js new file mode 100644 index 0000000..25715fb --- /dev/null +++ b/navigate-between-pages-starter/pages/index.js @@ -0,0 +1,203 @@ +import Head from 'next/head' + +const Home = () => ( +
+ + Create Next App + + + +
+

+ Learn Next.js! +

+ +

+ Get started by editing pages/index.js +

+ + +
+ + + + + + +
+) + +export default Home diff --git a/navigate-between-pages-starter/public/favicon.ico b/navigate-between-pages-starter/public/favicon.ico new file mode 100644 index 0000000..4965832 Binary files /dev/null and b/navigate-between-pages-starter/public/favicon.ico differ diff --git a/navigate-between-pages-starter/public/zeit.svg b/navigate-between-pages-starter/public/zeit.svg new file mode 100644 index 0000000..dd3916c --- /dev/null +++ b/navigate-between-pages-starter/public/zeit.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/package.json b/package.json new file mode 100644 index 0000000..7a8dc16 --- /dev/null +++ b/package.json @@ -0,0 +1,14 @@ +{ + "private": true, + "license": "MIT", + "husky": { + "hooks": { + "pre-commit": "pretty-quick --staged" + } + }, + "devDependencies": { + "prettier": "^2.0.2", + "pretty-quick": "2.0.1", + "husky": "4.2.3" + } +} 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..428a0d3 --- /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} +

{name}

+ + ) : ( + <> + + + {name} + + +

+ + {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..39d4bd1 --- /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..ffe4bdd --- /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/.gitignore b/typescript-starter/.gitignore new file mode 100644 index 0000000..922d92a --- /dev/null +++ b/typescript-starter/.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-starter/README.md b/typescript-starter/README.md new file mode 100644 index 0000000..02695bc --- /dev/null +++ b/typescript-starter/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-starter/components/date.js b/typescript-starter/components/date.js new file mode 100644 index 0000000..0ec71d3 --- /dev/null +++ b/typescript-starter/components/date.js @@ -0,0 +1,6 @@ +import { parseISO, format } from 'date-fns' + +export default function Date({ dateString }) { + const date = parseISO(dateString) + return +} diff --git a/typescript-starter/components/layout.js b/typescript-starter/components/layout.js new file mode 100644 index 0000000..cff0cca --- /dev/null +++ b/typescript-starter/components/layout.js @@ -0,0 +1,64 @@ +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 }) { + return ( +
+ + + + + +
+ {home ? ( + <> + {name} +

{name}

+ + ) : ( + <> + + + {name} + + +

+ + {name} + +

+ + )} +
+
{children}
+ {!home && ( + + )} +
+ ) +} diff --git a/typescript-starter/components/layout.module.css b/typescript-starter/components/layout.module.css new file mode 100644 index 0000000..d0e3a8f --- /dev/null +++ b/typescript-starter/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-starter/lib/posts.js b/typescript-starter/lib/posts.js new file mode 100644 index 0000000..53d8653 --- /dev/null +++ b/typescript-starter/lib/posts.js @@ -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 + } + }) + // 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) { + 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 + } +} diff --git a/typescript-starter/package.json b/typescript-starter/package.json new file mode 100644 index 0000000..b879f50 --- /dev/null +++ b/typescript-starter/package.json @@ -0,0 +1,19 @@ +{ + "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" + } +} diff --git a/typescript-starter/pages/_app.js b/typescript-starter/pages/_app.js new file mode 100644 index 0000000..7e66efc --- /dev/null +++ b/typescript-starter/pages/_app.js @@ -0,0 +1,5 @@ +import '../styles/global.css' + +export default function App({ Component, pageProps }) { + return +} diff --git a/typescript-starter/pages/api/hello.js b/typescript-starter/pages/api/hello.js new file mode 100644 index 0000000..2e22ab3 --- /dev/null +++ b/typescript-starter/pages/api/hello.js @@ -0,0 +1,3 @@ +export default (req, res) => { + res.status(200).json({ text: 'Hello' }) +} diff --git a/typescript-starter/pages/index.js b/typescript-starter/pages/index.js new file mode 100644 index 0000000..0f9494b --- /dev/null +++ b/typescript-starter/pages/index.js @@ -0,0 +1,48 @@ +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' + +export default function Home({ allPostsData }) { + 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 async function getStaticProps() { + const allPostsData = getSortedPostsData() + return { + props: { + allPostsData + } + } +} diff --git a/typescript-starter/pages/posts/[id].js b/typescript-starter/pages/posts/[id].js new file mode 100644 index 0000000..28faaad --- /dev/null +++ b/typescript-starter/pages/posts/[id].js @@ -0,0 +1,39 @@ +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' + +export default function Post({ postData }) { + return ( + + + {postData.title} + +
+

{postData.title}

+
+ +
+
+
+
+ ) +} + +export async function getStaticPaths() { + const paths = getAllPostIds() + return { + paths, + fallback: false + } +} + +export async function getStaticProps({ params }) { + const postData = await getPostData(params.id) + return { + props: { + postData + } + } +} diff --git a/typescript-starter/posts/dps.md b/typescript-starter/posts/dps.md new file mode 100644 index 0000000..878a33d --- /dev/null +++ b/typescript-starter/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-starter/posts/pre-rendering.md b/typescript-starter/posts/pre-rendering.md new file mode 100644 index 0000000..78cc081 --- /dev/null +++ b/typescript-starter/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-starter/public/favicon.ico b/typescript-starter/public/favicon.ico new file mode 100644 index 0000000..4965832 Binary files /dev/null and b/typescript-starter/public/favicon.ico differ diff --git a/typescript-starter/public/images/profile.jpg b/typescript-starter/public/images/profile.jpg new file mode 100644 index 0000000..798aba3 Binary files /dev/null and b/typescript-starter/public/images/profile.jpg differ diff --git a/typescript-starter/styles/global.css b/typescript-starter/styles/global.css new file mode 100644 index 0000000..9e1b0fb --- /dev/null +++ b/typescript-starter/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-starter/styles/utils.module.css b/typescript-starter/styles/utils.module.css new file mode 100644 index 0000000..37f545e --- /dev/null +++ b/typescript-starter/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; +}