upstream #1
137
README.md
137
README.md
@ -251,18 +251,7 @@ See [Next.js on Netlify](https://docs.netlify.com/integrations/frameworks/next-j
|
|||||||
|
|
||||||
1. Add `output: 'export'` in `next.config.js`. See [static exports documentation](https://nextjs.org/docs/app/building-your-application/deploying/static-exports#configuration) for more information.
|
1. Add `output: 'export'` in `next.config.js`. See [static exports documentation](https://nextjs.org/docs/app/building-your-application/deploying/static-exports#configuration) for more information.
|
||||||
2. Comment out `headers()` from `next.config.js`.
|
2. Comment out `headers()` from `next.config.js`.
|
||||||
3. Change `components/Image.tsx` to use a standard `<img>` tag instead of `next/image`:
|
3. Add `unoptimized: true` to the `images` key in `next.config.js`:
|
||||||
|
|
||||||
```ts
|
|
||||||
/* eslint-disable jsx-a11y/alt-text */
|
|
||||||
/* eslint-disable @next/next/no-img-element */
|
|
||||||
import NextImage, { ImageProps } from 'next/image'
|
|
||||||
|
|
||||||
// @ts-ignore
|
|
||||||
const Image = ({ ...rest }: ImageProps) => <img {...rest} />
|
|
||||||
|
|
||||||
export default Image
|
|
||||||
```
|
|
||||||
|
|
||||||
Alternatively, to continue using `next/image`, you can use an alternative image optimization provider such as Imgix, Cloudinary or Akamai. See [image optimization documentation](https://nextjs.org/docs/app/building-your-application/deploying/static-exports#image-optimization) for more details.
|
Alternatively, to continue using `next/image`, you can use an alternative image optimization provider such as Imgix, Cloudinary or Akamai. See [image optimization documentation](https://nextjs.org/docs/app/building-your-application/deploying/static-exports#image-optimization) for more details.
|
||||||
|
|
||||||
@ -270,127 +259,13 @@ See [Next.js on Netlify](https://docs.netlify.com/integrations/frameworks/next-j
|
|||||||
5. Run `yarn build`. The generated static content is in the `out` folder.
|
5. Run `yarn build`. The generated static content is in the `out` folder.
|
||||||
6. Deploy the `out` folder to your hosting service of choice or run `npx serve out` to view the website locally.
|
6. Deploy the `out` folder to your hosting service of choice or run `npx serve out` to view the website locally.
|
||||||
|
|
||||||
|
__Note__: Deploying on Github pages require addition modifications to the base path. Please refer to the FAQ for more information.
|
||||||
|
|
||||||
## Frequently Asked Questions
|
## Frequently Asked Questions
|
||||||
|
|
||||||
### How can I add a custom MDX component?
|
[How can I add a custom MDX component?](/faq/custom-mdx-component.md)
|
||||||
|
[How can I customize the `kbar` search?](/faq/customize-kbar-search.md)
|
||||||
Here's an example on how to create a donut chart from Chart.js (assuming you already have the dependencies installed) and use it in MDX posts. First, create a new `DonutChart.tsx` component in `components`:
|
[How do I deploy on Github pages](/faq/github-pages-deployment.md)
|
||||||
|
|
||||||
```tsx
|
|
||||||
'use client'
|
|
||||||
|
|
||||||
import { Doughnut } from 'react-chartjs-2'
|
|
||||||
import { Chart as ChartJS, ArcElement, Tooltip, Legend } from 'chart.js'
|
|
||||||
|
|
||||||
ChartJS.register(ArcElement, Tooltip, Legend)
|
|
||||||
|
|
||||||
const DonutChart = ({ data }) => {
|
|
||||||
return <Doughnut data={data} />
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Doughnut
|
|
||||||
```
|
|
||||||
|
|
||||||
Since the underlying `Doughnut` component uses React hooks, we add the `'use client'` directive to specify that it is a client side component. Also, there is an existing issue which prevents named components from being used, so we need to export the component as the default export.
|
|
||||||
|
|
||||||
Next, add the component to `MDXComponents.tsx`:
|
|
||||||
|
|
||||||
```diff
|
|
||||||
...
|
|
||||||
+ import DonutChart from './DonutChart'
|
|
||||||
|
|
||||||
export const components: MDXComponents = {
|
|
||||||
Image,
|
|
||||||
TOCInline,
|
|
||||||
a: CustomLink,
|
|
||||||
pre: Pre,
|
|
||||||
+ DonutChart,
|
|
||||||
BlogNewsletterForm,
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
You can now use the component in `.mdx` files:
|
|
||||||
|
|
||||||
```mdx
|
|
||||||
## Example Donut Chart
|
|
||||||
|
|
||||||
export const data = {
|
|
||||||
labels: ['Red', 'Blue', 'Yellow'],
|
|
||||||
datasets: [
|
|
||||||
{
|
|
||||||
label: '# of Votes',
|
|
||||||
data: [12, 19, 3],
|
|
||||||
backgroundColor: [
|
|
||||||
'rgba(255, 99, 132, 0.2)',
|
|
||||||
'rgba(54, 162, 235, 0.2)',
|
|
||||||
'rgba(255, 206, 86, 0.2)',
|
|
||||||
],
|
|
||||||
borderColor: ['rgba(255, 99, 132, 1)', 'rgba(54, 162, 235, 1)', 'rgba(255, 206, 86, 1)'],
|
|
||||||
borderWidth: 1,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}
|
|
||||||
|
|
||||||
<DonutChart data={data} />
|
|
||||||
```
|
|
||||||
|
|
||||||
### How can I customize the `kbar` search?
|
|
||||||
|
|
||||||
Add a `SearchProvider` component such as the one shown below and use it in place of the default `SearchProvider` component in `app/layout.tsx`.
|
|
||||||
|
|
||||||
`defaultActions` are the initial list of actions.
|
|
||||||
|
|
||||||
`onSearchDocumentsLoad` is a callback function that is called when the documents specified by `searchDocumentsPath` are loaded. Set `searchDocumentsPath` to `false` to disable the dynamically loaded search feature.
|
|
||||||
|
|
||||||
```tsx
|
|
||||||
'use client'
|
|
||||||
|
|
||||||
import { KBarSearchProvider } from 'pliny/search/KBar'
|
|
||||||
import { useRouter } from 'next/navigation'
|
|
||||||
import { CoreContent } from 'pliny/utils/contentlayer'
|
|
||||||
import { Blog } from 'contentlayer/generated'
|
|
||||||
|
|
||||||
export const SearchProvider = ({ children }) => {
|
|
||||||
const router = useRouter()
|
|
||||||
return (
|
|
||||||
<KBarSearchProvider
|
|
||||||
kbarConfig={{
|
|
||||||
searchDocumentsPath: 'search.json',
|
|
||||||
defaultActions: [
|
|
||||||
{
|
|
||||||
id: 'homepage',
|
|
||||||
name: 'Homepage',
|
|
||||||
keywords: '',
|
|
||||||
shortcut: ['h', 'h'],
|
|
||||||
section: 'Home',
|
|
||||||
perform: () => router.push('/'),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'projects',
|
|
||||||
name: 'Projects',
|
|
||||||
keywords: '',
|
|
||||||
shortcut: ['p'],
|
|
||||||
section: 'Home',
|
|
||||||
perform: () => router.push('/projects'),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
onSearchDocumentsLoad(json) {
|
|
||||||
return json.map((post: CoreContent<Blog>) => ({
|
|
||||||
id: post.path,
|
|
||||||
name: post.title,
|
|
||||||
keywords: post?.summary || '',
|
|
||||||
section: 'Blog',
|
|
||||||
subtitle: post.tags.join(', '),
|
|
||||||
perform: () => router.push(post.path),
|
|
||||||
}))
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{children}
|
|
||||||
</KBarSearchProvider>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Support
|
## Support
|
||||||
|
|
||||||
|
61
faq/custom-mdx-component.md
Normal file
61
faq/custom-mdx-component.md
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
# How can I add a custom MDX component?
|
||||||
|
|
||||||
|
Here's an example on how to create a donut chart from Chart.js (assuming you already have the dependencies installed) and use it in MDX posts. First, create a new `DonutChart.tsx` component in `components`:
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
'use client'
|
||||||
|
|
||||||
|
import { Doughnut } from 'react-chartjs-2'
|
||||||
|
import { Chart as ChartJS, ArcElement, Tooltip, Legend } from 'chart.js'
|
||||||
|
|
||||||
|
ChartJS.register(ArcElement, Tooltip, Legend)
|
||||||
|
|
||||||
|
const DonutChart = ({ data }) => {
|
||||||
|
return <Doughnut data={data} />
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Doughnut
|
||||||
|
```
|
||||||
|
|
||||||
|
Since the underlying `Doughnut` component uses React hooks, we add the `'use client'` directive to specify that it is a client side component. Also, there is an existing issue which prevents named components from being used, so we need to export the component as the default export.
|
||||||
|
|
||||||
|
Next, add the component to `MDXComponents.tsx`:
|
||||||
|
|
||||||
|
```diff
|
||||||
|
...
|
||||||
|
+ import DonutChart from './DonutChart'
|
||||||
|
|
||||||
|
export const components: MDXComponents = {
|
||||||
|
Image,
|
||||||
|
TOCInline,
|
||||||
|
a: CustomLink,
|
||||||
|
pre: Pre,
|
||||||
|
+ DonutChart,
|
||||||
|
BlogNewsletterForm,
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
You can now use the component in `.mdx` files:
|
||||||
|
|
||||||
|
```mdx
|
||||||
|
## Example Donut Chart
|
||||||
|
|
||||||
|
export const data = {
|
||||||
|
labels: ['Red', 'Blue', 'Yellow'],
|
||||||
|
datasets: [
|
||||||
|
{
|
||||||
|
label: '# of Votes',
|
||||||
|
data: [12, 19, 3],
|
||||||
|
backgroundColor: [
|
||||||
|
'rgba(255, 99, 132, 0.2)',
|
||||||
|
'rgba(54, 162, 235, 0.2)',
|
||||||
|
'rgba(255, 206, 86, 0.2)',
|
||||||
|
],
|
||||||
|
borderColor: ['rgba(255, 99, 132, 1)', 'rgba(54, 162, 235, 1)', 'rgba(255, 206, 86, 1)'],
|
||||||
|
borderWidth: 1,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
<DonutChart data={data} />
|
||||||
|
```
|
57
faq/customize-kbar-search.md
Normal file
57
faq/customize-kbar-search.md
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
# How can I customize the `kbar` search?
|
||||||
|
|
||||||
|
Add a `SearchProvider` component such as the one shown below and use it in place of the default `SearchProvider` component in `app/layout.tsx`.
|
||||||
|
|
||||||
|
`defaultActions` are the initial list of actions.
|
||||||
|
|
||||||
|
`onSearchDocumentsLoad` is a callback function that is called when the documents specified by `searchDocumentsPath` are loaded. Set `searchDocumentsPath` to `false` to disable the dynamically loaded search feature.
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
'use client'
|
||||||
|
|
||||||
|
import { KBarSearchProvider } from 'pliny/search/KBar'
|
||||||
|
import { useRouter } from 'next/navigation'
|
||||||
|
import { CoreContent } from 'pliny/utils/contentlayer'
|
||||||
|
import { Blog } from 'contentlayer/generated'
|
||||||
|
|
||||||
|
export const SearchProvider = ({ children }) => {
|
||||||
|
const router = useRouter()
|
||||||
|
return (
|
||||||
|
<KBarSearchProvider
|
||||||
|
kbarConfig={{
|
||||||
|
searchDocumentsPath: 'search.json',
|
||||||
|
defaultActions: [
|
||||||
|
{
|
||||||
|
id: 'homepage',
|
||||||
|
name: 'Homepage',
|
||||||
|
keywords: '',
|
||||||
|
shortcut: ['h', 'h'],
|
||||||
|
section: 'Home',
|
||||||
|
perform: () => router.push('/'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'projects',
|
||||||
|
name: 'Projects',
|
||||||
|
keywords: '',
|
||||||
|
shortcut: ['p'],
|
||||||
|
section: 'Home',
|
||||||
|
perform: () => router.push('/projects'),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
onSearchDocumentsLoad(json) {
|
||||||
|
return json.map((post: CoreContent<Blog>) => ({
|
||||||
|
id: post.path,
|
||||||
|
name: post.title,
|
||||||
|
keywords: post?.summary || '',
|
||||||
|
section: 'Blog',
|
||||||
|
subtitle: post.tags.join(', '),
|
||||||
|
perform: () => router.push(post.path),
|
||||||
|
}))
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</KBarSearchProvider>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
```
|
108
faq/github-pages-deployment.md
Normal file
108
faq/github-pages-deployment.md
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
# How do I deploy on Github pages?
|
||||||
|
|
||||||
|
[Demo](https://timlrx.github.io/tailwind-nextjs-starter-blog/) & [Source](https://github.com/timlrx/tailwind-nextjs-starter-blog/tree/test-gh-pages-static)
|
||||||
|
|
||||||
|
1. Follow the section on creating a static build in the main README and test it locally to ensure that it works.
|
||||||
|
2. Specify the base path in `next.config.js` to match your repository name e.g. `basePath: "/tailwind-nextjs-starter-blog"`.
|
||||||
|
3. Modify `component/Image.tsx` to use the correct base path for the image source:
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
import NextImage, { ImageProps } from 'next/image'
|
||||||
|
|
||||||
|
const Image = ({ src, ...rest }: ImageProps) => (
|
||||||
|
<NextImage src={`/tailwind-nextjs-starter-blog${src}`} {...rest} />
|
||||||
|
)
|
||||||
|
|
||||||
|
export default Image
|
||||||
|
```
|
||||||
|
|
||||||
|
4. To automate deployment, here's a Github action that you could use
|
||||||
|
|
||||||
|
```yml
|
||||||
|
# Sample workflow for building and deploying a Next.js site to GitHub Pages
|
||||||
|
#
|
||||||
|
# To get started with Next.js see: https://nextjs.org/docs/getting-started
|
||||||
|
#
|
||||||
|
name: Deploy Next.js site to Pages
|
||||||
|
|
||||||
|
on:
|
||||||
|
# Runs on pushes targeting the default branch
|
||||||
|
push:
|
||||||
|
branches: ['test-gh-pages-static']
|
||||||
|
|
||||||
|
# Allows you to run this workflow manually from the Actions tab
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
pages: write
|
||||||
|
id-token: write
|
||||||
|
|
||||||
|
# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued.
|
||||||
|
# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete.
|
||||||
|
concurrency:
|
||||||
|
group: 'pages'
|
||||||
|
cancel-in-progress: false
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
# Build job
|
||||||
|
build:
|
||||||
|
name: Build Nextjs Blog
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
- name: Detect package manager
|
||||||
|
id: detect-package-manager
|
||||||
|
run: |
|
||||||
|
if [ -f "${{ github.workspace }}/yarn.lock" ]; then
|
||||||
|
echo "manager=yarn" >> $GITHUB_OUTPUT
|
||||||
|
echo "command=install" >> $GITHUB_OUTPUT
|
||||||
|
echo "runner=yarn" >> $GITHUB_OUTPUT
|
||||||
|
exit 0
|
||||||
|
elif [ -f "${{ github.workspace }}/package.json" ]; then
|
||||||
|
echo "manager=npm" >> $GITHUB_OUTPUT
|
||||||
|
echo "command=ci" >> $GITHUB_OUTPUT
|
||||||
|
echo "runner=npx --no-install" >> $GITHUB_OUTPUT
|
||||||
|
exit 0
|
||||||
|
else
|
||||||
|
echo "Unable to determine package manager"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
- name: Setup Node
|
||||||
|
uses: actions/setup-node@v3
|
||||||
|
with:
|
||||||
|
node-version: '18'
|
||||||
|
cache: ${{ steps.detect-package-manager.outputs.manager }}
|
||||||
|
- name: Restore cache
|
||||||
|
uses: actions/cache@v3
|
||||||
|
with:
|
||||||
|
path: |
|
||||||
|
.next/cache
|
||||||
|
# Generate a new cache whenever packages or source files change.
|
||||||
|
key: ${{ runner.os }}-nextjs-${{ hashFiles('**/package-lock.json', '**/yarn.lock') }}-${{ hashFiles('**.[jt]s', '**.[jt]sx') }}
|
||||||
|
# If source files changed but packages didn't, rebuild from a prior cache.
|
||||||
|
restore-keys: |
|
||||||
|
${{ runner.os }}-nextjs-${{ hashFiles('**/package-lock.json', '**/yarn.lock') }}-
|
||||||
|
- name: Install dependencies
|
||||||
|
run: ${{ steps.detect-package-manager.outputs.manager }} ${{ steps.detect-package-manager.outputs.command }}
|
||||||
|
- name: Build project assets
|
||||||
|
run: ${{ steps.detect-package-manager.outputs.manager }} build
|
||||||
|
- name: Upload artifact
|
||||||
|
uses: actions/upload-pages-artifact@v2
|
||||||
|
with:
|
||||||
|
path: ./out
|
||||||
|
|
||||||
|
# Deployment job
|
||||||
|
deploy:
|
||||||
|
environment:
|
||||||
|
name: github-pages
|
||||||
|
url: ${{ steps.deployment.outputs.page_url }}
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: build
|
||||||
|
steps:
|
||||||
|
- name: Deploy to GitHub Pages
|
||||||
|
id: deployment
|
||||||
|
uses: actions/deploy-pages@v2
|
||||||
|
```
|
Loading…
x
Reference in New Issue
Block a user