Skip to content

Commit

Permalink
feat: preserve code block meta for code highlighting
Browse files Browse the repository at this point in the history
close: #30
  • Loading branch information
zce committed Jan 25, 2024
1 parent 5aaf84f commit aa704be
Show file tree
Hide file tree
Showing 9 changed files with 854 additions and 899 deletions.
94 changes: 93 additions & 1 deletion docs/guide/code-highlighting.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,85 @@
# Code Highlighter
# Code Highlighting

Considering that not all content contains code, and that syntax highlighting often comes with custom styles, Velite doesn't want to subjectively determine the final presentation of your content. So we don't include built-in code highlighting features.

If you think code highlighting is necessary for your content, you can implement if by referring to the following methods.

## rehype-pretty-code

> [rehype-pretty-code](https://rehype-pretty-code.netlify.app) is a rehype plugin to format code blocks.
::: code-group

```sh [npm]
$ npm install rehype-pretty-code shikiji
```

```sh [pnpm]
$ pnpm add rehype-pretty-code shikiji
```

```sh [yarn]
$ yarn add rehype-pretty-code shikiji
```

:::

In your `velite.config.js`:

```js
import rehypePrettyCode from 'rehype-pretty-code'
import { defineConfig } from 'velite'

export default defineConfig({
markdown: {
// https://rehype-pretty-code.netlify.app/
rehypePlugins: [rehypePrettyCode]
}
})
```

Add some necessary styles, such as:

```css
[data-rehype-pretty-code-figure] pre {
@apply px-0;
}

[data-rehype-pretty-code-figure] code {
@apply text-sm !leading-loose md:text-base;
}

[data-rehype-pretty-code-figure] code[data-line-numbers] {
counter-reset: line;
}

[data-rehype-pretty-code-figure] code[data-line-numbers] > [data-line]::before {
counter-increment: line;
content: counter(line);
@apply mr-4 inline-block w-4 text-right text-gray-500;
}

[data-rehype-pretty-code-figure] pre [data-line] {
@apply border-l-2 border-l-transparent px-3;
}

[data-rehype-pretty-code-figure] [data-highlighted-line] {
background: rgba(200, 200, 255, 0.1);
@apply border-l-blue-400;
}

[data-rehype-pretty-code-figure] [data-highlighted-chars] {
@apply rounded bg-zinc-600/50;
box-shadow: 0 0 0 4px rgb(82 82 91 / 0.5);
}

[data-rehype-pretty-code-figure] [data-chars-id] {
@apply border-b-2 p-1 shadow-none;
}
```

refer to [examples](https://github.com/zce/velite/blob/main/examples/nextjs/velite.config.ts) for more details.

## rehype-shikiji

> [Shikiji](https://github.com/antfu/shikiji) is a improved version of [Shiki](https://shiki.matsu.io)
Expand Down Expand Up @@ -92,3 +168,19 @@ export default defineConfig({
## Client-side

Code highlighting in Client-side. You can use [prismjs](https://prismjs.com) or [shiki](https://shiki.matsu.io) to highlight code in client-side.

for example:

```js
import { codeToHtml } from 'https://esm.sh/shikiji'

Array.from(document.querySelectorAll('pre code[class*="language-"]')).map(async block => {
block.parentElement.outerHTML = await codeToHtml(block.textContent, { lang: block.className.slice(9), theme: 'nord' })
})
```

::: tip

This method is most recommended if there are a large number of documents that need to be processed frequently. Because syntax highlighting and parsing is very time-consuming, it will greatly affect the construction speed of Velite.

:::
38 changes: 38 additions & 0 deletions examples/nextjs/app/globals.css
Original file line number Diff line number Diff line change
@@ -1,3 +1,41 @@
@tailwind base;
@tailwind components;
@tailwind utilities;

@layer base {
[data-rehype-pretty-code-figure] pre {
@apply px-0;
}

[data-rehype-pretty-code-figure] code {
@apply text-sm !leading-loose md:text-base;
}

[data-rehype-pretty-code-figure] code[data-line-numbers] {
counter-reset: line;
}

[data-rehype-pretty-code-figure] code[data-line-numbers] > [data-line]::before {
counter-increment: line;
content: counter(line);
@apply mr-4 inline-block w-4 text-right text-gray-500;
}

[data-rehype-pretty-code-figure] pre [data-line] {
@apply border-l-2 border-l-transparent px-3;
}

[data-rehype-pretty-code-figure] [data-highlighted-line] {
background: rgba(200, 200, 255, 0.1);
@apply border-l-blue-400;
}

[data-rehype-pretty-code-figure] [data-highlighted-chars] {
@apply rounded bg-zinc-600/50;
box-shadow: 0 0 0 4px rgb(82 82 91 / 0.5);
}

[data-rehype-pretty-code-figure] [data-chars-id] {
@apply border-b-2 p-1 shadow-none;
}
}
2 changes: 1 addition & 1 deletion examples/nextjs/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ interface RootLayoutProps {

export default function RootLayout({ children }: RootLayoutProps) {
return (
<html lang="en">
<html lang="en" suppressHydrationWarning>
<body className={`min-h-screen bg-white text-slate-900 antialiased dark:bg-slate-950 dark:text-slate-50 ${inter.className}`}>
<ThemeProvider attribute="class" defaultTheme="system" enableSystem>
<div className="mx-auto max-w-2xl px-4 py-10">
Expand Down
2 changes: 1 addition & 1 deletion examples/nextjs/app/posts/[slug]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export default function PostPage({ params }: PostProps) {
if (post == null) notFound()

return (
<article className="prose dark:prose-invert py-6">
<article className="prose lg:prose-lg dark:prose-invert py-6">
<h1 className="mb-2">{post.title}</h1>
{post.description && <p className="mt-0 text-xl text-slate-700 dark:text-slate-200">{post.description}</p>}
{post.cover && <Image src={post.cover} alt={post.title} placeholder="blur" />}
Expand Down
48 changes: 34 additions & 14 deletions examples/nextjs/content/posts/1970-01-01-style-guide/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -159,10 +159,10 @@ If you want to embed table, this is how you do it:
| Division 1 | Division 2 | Division 3 |
| Division 1 | Division 2 | Division 3 |

| Name | Age | Sex | Location |
| ------ | ------- | --- | -------- | ------ |
| Naruto | Uzumaki | 16 | Male | Konoha |
| Sakura | Haruno | 16 | Female | Konoha |
| Name | | Age | Sex | Location |
| ------ | ------- | --- | ------ | -------- |
| Naruto | Uzumaki | 16 | Male | Konoha |
| Sakura | Haruno | 16 | Female | Konoha |

---

Expand All @@ -182,16 +182,36 @@ Code can be presented inline, like `<?php bloginfo('stylesheet_url'); ?>`, or wi
}
```

```js
import React from 'react'

import { Wrapper } from '../components'

export default () => (
<Wrapper title="Hello world">
<h1>Hello world</h1>
</Wrapper>
)
```js {6,20} showLineNumbers /velite/
import { defineConfig, s } from 'velite'

// `s` is extended from Zod with some custom schemas,
// you can also import re-exported `z` from `velite` if you don't need these extension schemas.

export default defineConfig({
collections: {
posts: {
name: 'Post', // collection type name
pattern: 'posts/**/*.md', // content files glob pattern
schema: s
.object({
title: s.string().max(99), // Zod primitive type
slug: s.slug('posts'), // validate format, unique in posts collection
date: s.isodate(), // input Date-like string, output ISO Date string.
cover: s.image().optional(), // input image relpath, output image object with blurImage.
video: s.file().optional(), // input file relpath, output file public path.
metadata: s.metadata(), // extract markdown reading-time, word-count, etc.
excerpt: s.excerpt(), // excerpt of markdown content
content: s.markdown() // transform markdown to html
})
// more additional fields (computed fields)
.transform(data => ({ ...data, permalink: `/blog/${data.slug}` }))
},
others: {
// other collection schema options
}
}
})
```

---
Expand Down
3 changes: 2 additions & 1 deletion examples/nextjs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,11 @@
"eslint-config-next": "latest",
"next": "latest",
"next-themes": "latest",
"npm-run-all": "latest",
"postcss": "latest",
"react": "latest",
"react-dom": "latest",
"rehype-pretty-code": "latest",
"shikiji": "latest",
"tailwindcss": "latest",
"typescript": "latest",
"velite": "workspace:*"
Expand Down
5 changes: 5 additions & 0 deletions examples/nextjs/velite.config.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import rehypePrettyCode from 'rehype-pretty-code'
import { defineConfig, s } from 'velite'

const slugify = (input: string) =>
Expand Down Expand Up @@ -102,6 +103,10 @@ export default defineConfig({
.transform(data => ({ ...data, permalink: `/blog/${data.slug}` }))
}
},
markdown: {
// https://rehype-pretty-code.netlify.app/
rehypePlugins: [rehypePrettyCode]
},
prepare: ({ categories, tags, posts }) => {
const docs = posts.filter(i => process.env.NODE_ENV !== 'production' || !i.draft)

Expand Down
Loading

0 comments on commit aa704be

Please sign in to comment.