feat(site): add shiki notation transformers (#937)

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Darius Cepulis
2026-03-13 09:46:27 -05:00
committed by GitHub
co-authored by Claude Opus 4.6
parent 62a8c389e1
commit 2c2610f168
8 changed files with 173 additions and 4 deletions
+3 -1
View File
@@ -1,6 +1,7 @@
import clsx from 'clsx';
import type { BundledLanguage, Highlighter } from 'shiki';
import { hastToHtml } from 'shiki';
import { shikiNotationTransformers } from '@/utils/shikiNotationTransformers';
export interface SharedProps {
code: string;
@@ -15,6 +16,7 @@ export default function Shared({ code, lang, highlighter }: SharedProps) {
light: 'gruvbox-dark-hard',
dark: 'gruvbox-dark-soft',
},
transformers: shikiNotationTransformers,
});
// shiki gives us a root > pre > code > text structure
@@ -39,7 +41,7 @@ export default function Shared({ code, lang, highlighter }: SharedProps) {
const { class: codeClassName } = codeProps;
return (
<pre className={clsx('shiki text-manila-light', preClassName)}>
<pre className={clsx('shiki astro-code text-manila-light', preClassName)}>
<code className={clsx('font-mono text-code', codeClassName)} dangerouslySetInnerHTML={{ __html: html }} />
</pre>
);
@@ -216,6 +216,44 @@ we can use 3 backticks ``` in new line and write snippet and close with 3 backti
</html>
```
### Code annotations
You can annotate code blocks with special comments to highlight, diff, focus, or word-highlight specific lines. The annotation comments are stripped from the rendered output (and from copy/paste).
#### Diff
Show added and removed lines with `// [!code ++]` and `// [!code --]`:
```ts
function greet(name: string) {
console.log('Hello') // [!code --]
console.log(`Hello, ${name}!`) // [!code ++]
console.log(`It's great to meet you.`) // [!code ++]
}
```
#### Focus
Dim everything except the focused lines with `// [!code focus]`. Hovering the code block reveals all lines:
```ts
function greet(name: string) {
const message = `hello, ${name}!`
console.log(message) // [!code focus]
}
```
#### Word highlight
Highlight a specific word or phrase with `// [!code word:term]`. For example, `// [!code word:name]` looks like this:
```ts
// [!code word:name]
function greet(name: string) {
console.log(`hello, ${name}!`)
}
```
### List types
#### Ordered list
+1
View File
@@ -1,4 +1,5 @@
@import "tailwindcss";
@import "./shiki-transformers.css";
/**
* @license
+72
View File
@@ -0,0 +1,72 @@
@layer base {
.astro-code code {
display: flex;
flex-direction: column;
}
.astro-code .line {
display: inline-flex;
position: relative;
line-height: 1.75;
}
.astro-code .line.diff,
.astro-code .line.focused {
width: calc(100% + var(--spacing) * 12);
margin-inline: calc(var(--spacing) * -6);
padding-inline: calc(var(--spacing) * 6);
}
/* Diff: added lines */
.astro-code .line.diff.add {
background-color: rgba(184, 187, 38, 0.12);
}
.astro-code .line.diff.add::before,
.astro-code .line.diff.remove::before {
position: absolute;
font-weight: bold;
left: 0;
top: 0;
bottom: 0;
width: calc(var(--spacing) * 6);
display: flex;
align-items: center;
justify-content: center;
}
.astro-code .line.diff.add::before {
content: "+";
color: rgba(184, 187, 31, 1);
}
/* Diff: removed lines */
.astro-code .line.diff.remove {
background-color: rgba(251, 73, 52, 0.12);
}
.astro-code .line.diff.remove::before {
content: "-";
color: rgba(251, 73, 52, 1);
}
/* Word highlight */
.astro-code .highlighted-word {
background-color: var(--color-soot);
border-bottom: 1px solid var(--color-manila-dark);
padding-inline: 0.2em;
}
:where(.dark, .dark *) .astro-code .highlighted-word {
background-color: var(--color-faded-black);
}
/* Focus: mute unfocused lines, reveal on hover */
.astro-code:has(.line.focused) .line:not(.focused) span {
opacity: 0.4;
transition: opacity 0.3s;
}
.astro-code:has(.line.focused):hover .line:not(.focused) span,
.astro-code:has(.line.focused):focus-within .line:not(.focused) span {
opacity: 1;
}
}
@@ -0,0 +1,12 @@
import {
transformerNotationDiff,
transformerNotationFocus,
transformerNotationWordHighlight,
} from '@shikijs/transformers';
import type { ShikiTransformer } from 'shiki';
export const shikiNotationTransformers: ShikiTransformer[] = [
transformerNotationDiff({ matchAlgorithm: 'v3' }),
transformerNotationFocus({ matchAlgorithm: 'v3' }),
transformerNotationWordHighlight({ matchAlgorithm: 'v3' }),
];