Skip to content

Commit

Permalink
added images example
Browse files Browse the repository at this point in the history
  • Loading branch information
schickling committed Jun 29, 2023
1 parent c03c03a commit a783196
Show file tree
Hide file tree
Showing 24 changed files with 379 additions and 6 deletions.
20 changes: 16 additions & 4 deletions .github/workflows/ci.yml
Expand Up @@ -20,7 +20,7 @@ jobs:
test:
strategy:
matrix:
node-version: [14, 16, 17, 18, 19, 20]
node-version: [16, 17, 18, 19, 20]
os: [ubuntu-latest, windows-latest]
runs-on: ${{ matrix.os }}
steps:
Expand Down Expand Up @@ -52,10 +52,22 @@ jobs:
- run: yarn build
working-directory: examples/next-rsc-dynamic

build-example-next-images-example:
strategy:
matrix:
node-version: [17, 18, 19, 20] # `app` dir requires 17+
os: [ubuntu-latest, windows-latest]
runs-on: ${{ matrix.os }}
steps:
- uses: schickling-actions/checkout-and-install@main
- run: yarn build
- run: yarn build
working-directory: examples/next-images

build-example-node-script:
strategy:
matrix:
node-version: [14, 16, 17, 18, 19, 20]
node-version: [16, 17, 18, 19, 20]
os: [ubuntu-latest, windows-latest]
runs-on: ${{ matrix.os }}
steps:
Expand All @@ -67,7 +79,7 @@ jobs:
build-example-node-script-mdx:
strategy:
matrix:
node-version: [14, 16, 17, 18, 19, 20]
node-version: [16, 17, 18, 19, 20]
os: [ubuntu-latest, windows-latest]
runs-on: ${{ matrix.os }}
steps:
Expand All @@ -79,7 +91,7 @@ jobs:
build-example-node-script-remote-content:
strategy:
matrix:
node-version: [14, 16, 17, 18, 19, 20]
node-version: [16, 17, 18, 19, 20]
os: [ubuntu-latest, windows-latest]
runs-on: ${{ matrix.os }}
steps:
Expand Down
16 changes: 16 additions & 0 deletions examples/next-images/.gitignore
@@ -0,0 +1,16 @@
# dependencies
node_modules

# next
dist
.next

# contentlayer
.contentlayer

# yarn
yarn.lock
yarn-error.log

# mac
.DS_Store
18 changes: 18 additions & 0 deletions examples/next-images/app/layout.tsx
@@ -0,0 +1,18 @@
import '../styles/globals.css'

import { Header } from '../components/Header'

export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html>
<head>
<title>Contentlayer Next.js Example</title>
<link rel="icon" type="image/x-icon" href="/favicon.png" />
</head>
<body>
<Header />
<div className="px-6">{children}</div>
</body>
</html>
)
}
43 changes: 43 additions & 0 deletions examples/next-images/app/page.tsx
@@ -0,0 +1,43 @@
import Link from "next/link";
import { compareDesc, format, parseISO } from "date-fns";
import { allPosts, Post } from "contentlayer/generated";
import { getMDXComponent } from "next-contentlayer/hooks";

function PostCard(post: Post) {
const Content = getMDXComponent(post.body.code);

return (
<div className="mb-8">
<h2 className="text-xl">
<Link
href={post.url}
className="text-blue-700 hover:text-blue-900"
legacyBehavior>
{post.title}
</Link>
</h2>
<time dateTime={post.date} className="block mb-2 text-xs text-gray-600">
{format(parseISO(post.date), "LLLL d, yyyy")}
</time>
<div className="text-sm">
<Content />
</div>
</div>
);
}

export default function Home() {
const posts = allPosts.sort((a, b) =>
compareDesc(new Date(a.date), new Date(b.date))
);

return (
<div className="max-w-xl py-8 mx-auto">
<h1 className="mb-8 text-3xl font-bold text-center">Next.js Example</h1>

{posts.map((post, idx) => (
<PostCard key={idx} {...post} />
))}
</div>
);
}
40 changes: 40 additions & 0 deletions examples/next-images/app/posts/[slug]/page.tsx
@@ -0,0 +1,40 @@
import { format, parseISO } from 'date-fns'
import { allPosts } from 'contentlayer/generated'
import { getMDXComponent } from 'next-contentlayer/hooks'
import Image from 'next/image'

export const generateStaticParams = async () => allPosts.map((post) => ({ slug: post._raw.flattenedPath }))

export const generateMetadata = ({ params }) => {
const post = allPosts.find((post) => post._raw.flattenedPath === params.slug)
return { title: post.title }
}

const PostLayout = ({ params }: { params: { slug: string } }) => {
const post = allPosts.find((post) => post._raw.flattenedPath === params.slug)

const Content = getMDXComponent(post.body.code)

return (
<article className="py-8 mx-auto max-w-xl space-y-4">
{post.cover && (
<Image
src={post.cover.filePath.replace('../public', '')}
alt=""
width={500}
height={500 / post.cover.aspectRatio}
blurDataURL={post.cover.blurhashDataUrl}
/>
)}
<div className="mb-8 text-center">
<time dateTime={post.date} className="mb-1 text-xs text-gray-600">
{format(parseISO(post.date), 'LLLL d, yyyy')}
</time>
<h1>{post.title}</h1>
</div>
<Content />
</article>
)
}

export default PostLayout
11 changes: 11 additions & 0 deletions examples/next-images/components/Button.tsx
@@ -0,0 +1,11 @@
import { FC } from 'react'
import React from 'react'

export const Button: FC<{ title: string }> = ({ title }) => (
<div
style={{ padding: 10, backgroundColor: '#333', color: '#fff', display: 'inline-block', borderRadius: 4 }}
onClick={() => alert('Hi')}
>
{title}
</div>
)
35 changes: 35 additions & 0 deletions examples/next-images/components/Header.tsx
@@ -0,0 +1,35 @@
import Link from 'next/link'

function Icon() {
return (
<svg width="22" height="24" viewBox="0 0 22 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
fillRule="evenodd"
clipRule="evenodd"
d="M10.43 0.92268C11.1426 0.398115 12.1177 0.407491 12.82 0.945665L19.9928 6.44198C21.0266 7.23419 21.0266 8.78771 19.9928 9.57992L17.2573 11.6761L20.0379 13.9037C21.0493 14.7139 21.022 16.2574 19.9826 17.0315L12.62 22.5153C11.8634 23.0788 10.8134 23.0332 10.1089 22.4063L4.34789 17.2802L3.54224 16.5903C-0.0530112 13.5114 0.390183 7.84094 4.41274 5.35212L10.43 0.92268ZM16.1955 10.8254L12.8515 8.14659C12.1375 7.57457 11.1235 7.56365 10.3972 8.12017L7.92298 10.0161C6.88913 10.8084 6.88913 12.3619 7.92298 13.1541L10.4154 15.064C11.129 15.6108 12.1224 15.6108 12.836 15.064L16.1773 12.5036L19.2086 14.932C19.5457 15.2021 19.5366 15.7166 19.1901 15.9747L11.8275 21.4585C11.5753 21.6463 11.2253 21.6311 10.9905 21.4221L5.2248 16.2918L4.40495 15.5895C1.48255 13.0869 1.84941 8.47338 5.13088 6.46078L5.15471 6.44617L11.2165 1.98398C11.454 1.80913 11.779 1.81225 12.0132 1.99164L19.1859 7.48796C19.5305 7.75203 19.5305 8.26987 19.1859 8.53394L16.1955 10.8254ZM15.1155 11.653L12.0291 14.018C11.7913 14.2003 11.4601 14.2003 11.2223 14.018L8.72984 12.1081C8.38523 11.844 8.38523 11.3262 8.72984 11.0621L11.2041 9.16615C11.4462 8.98065 11.7842 8.98429 12.0222 9.17496L15.1155 11.653Z"
fill="#7C3AED"
stroke="#7C3AED"
strokeWidth="0.5"
></path>
</svg>
)
}

function Logo() {
return (
<Link href="/" className="inline-flex justify-center items-center">
<span className="mr-2">
<Icon />
</span>
<span className="font-bold">Contentlayer</span>
</Link>
)
}

export function Header() {
return (
<header className="p-8 flex justify-center">
<Logo />
</header>
)
}
34 changes: 34 additions & 0 deletions examples/next-images/contentlayer.config.ts
@@ -0,0 +1,34 @@
import { defineDocumentType, makeSource } from 'contentlayer/source-files'

const Post = defineDocumentType(() => ({
name: 'Post',
filePathPattern: `**/*.mdx`,
contentType: 'mdx',
fields: {
title: {
type: 'string',
description: 'The title of the post',
required: true,
},
date: {
type: 'date',
description: 'The date of the post',
required: true,
},
cover: {
type: 'image',
required: false,
},
},
computedFields: {
url: {
type: 'string',
resolve: (doc) => `/posts/${doc._raw.flattenedPath}`,
},
},
}))

export default makeSource({
contentDirPath: 'posts',
documentTypes: [Post],
})
5 changes: 5 additions & 0 deletions examples/next-images/next-env.d.ts
@@ -0,0 +1,5 @@
/// <reference types="next" />
/// <reference types="next/image-types/global" />

// NOTE: This file should not be edited
// see https://nextjs.org/docs/basic-features/typescript for more information.
10 changes: 10 additions & 0 deletions examples/next-images/next.config.js
@@ -0,0 +1,10 @@
const { withContentlayer } = require("next-contentlayer");

/** @type {import('next').NextConfig} */
const nextConfig = {
experimental: {
appDir: true,
},
};

module.exports = withContentlayer(nextConfig);
25 changes: 25 additions & 0 deletions examples/next-images/package.json
@@ -0,0 +1,25 @@
{
"name": "next-images",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start"
},
"dependencies": {
"contentlayer": "latest",
"date-fns": "2.30.0",
"next": "13.4.7",
"next-contentlayer": "latest",
"react": "18.2.0",
"react-dom": "18.2.0"
},
"devDependencies": {
"@types/react": "18.2.7",
"autoprefixer": "^10.4.14",
"postcss": "^8.4.24",
"tailwindcss": "^3.3.2",
"typescript": "5.1.5"
}
}
6 changes: 6 additions & 0 deletions examples/next-images/postcss.config.js
@@ -0,0 +1,6 @@
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
}
7 changes: 7 additions & 0 deletions examples/next-images/posts/change-me.mdx
@@ -0,0 +1,7 @@
---
title: Change me!
date: 2022-03-11
cover: '../public/images/mark-neal-unsplash.jpg'
---

When you change a source file, Contentlayer automatically updates the content cache, which prompts Next.js to reload the content on screen.
6 changes: 6 additions & 0 deletions examples/next-images/posts/click-me.mdx
@@ -0,0 +1,6 @@
---
title: Click me!
date: 2022-02-28
---

Blog posts have their own pages. The content source is a markdown file, parsed to HTML by Contentlayer.
6 changes: 6 additions & 0 deletions examples/next-images/posts/what-is-contentlayer.mdx
@@ -0,0 +1,6 @@
---
title: What is Contentlayer?
date: 2022-02-22
---

**Contentlayer makes working with content easy.** It is a content preprocessor that validates and transforms your content into type-safe JSON you can easily import into your application.
Binary file added examples/next-images/public/images/favicon.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
27 changes: 27 additions & 0 deletions examples/next-images/styles/globals.css
@@ -0,0 +1,27 @@
@import url("https://fonts.googleapis.com/css2?family=Inter:wght@300;400;700&display=swap");

@tailwind base;
@tailwind components;
@tailwind utilities;

p {
@apply mb-4;
}

h1,
h2,
h3,
h4,
h5,
h6 {
@apply font-bold
mb-1;
}

h1 {
@apply text-3xl;
}

h2 {
@apply text-xl;
}
17 changes: 17 additions & 0 deletions examples/next-images/tailwind.config.js
@@ -0,0 +1,17 @@
const defaultTheme = require("tailwindcss/defaultTheme");

module.exports = {
content: [
"./app/**/*.{js,ts,jsx,tsx}",
"./pages/**/*.{js,ts,jsx,tsx}",
"./components/**/*.{js,ts,jsx,tsx}",
],
theme: {
extend: {
fontFamily: {
sans: ["Inter", ...defaultTheme.fontFamily.sans],
},
},
},
plugins: [],
};

0 comments on commit a783196

Please sign in to comment.