This page demonstrates every content shortcode that ships with Inkstone. Each section shows the source markdown and the rendered result. Use it as both a smoke test and a copy-paste reference.

For shortcodes that depend on external CDN libraries (mermaid, markmap, antv-g2, etc.), the loaders only inject when the page actually uses them — pages without the shortcode pay zero JS cost.


Callouts & Admonitions

callout — short colored note

Five severity levels with i18n-aware default titles.

{{< callout type="note" title="Heads up" >}}
This is a note callout. Use it for tangential context.
{{< /callout >}}

Heads up

This is a note callout. Use it for tangential context.
Tip callout (no explicit title — uses i18n default).

Backup first

Always run git stash before destructive operations.

admonition — foldable longer block

Same severities as callout but with optional fold/unfold and an icon.

{{< admonition type="tip" title="Pro tip" foldable=true >}}
Long-form callout content goes here. Useful when the
note itself contains multiple paragraphs or code blocks.
{{< /admonition >}}
Pro tip
Long-form callout content goes here. Useful when the note itself contains multiple paragraphs or code blocks. The foldable=true lets readers collapse it after reading.
Migration note
Inkstone 0.x → 1.x will be a breaking change for the design token API. Pin to ~0 until you’ve reviewed the migration guide.

Layout & Composition

flex + flex-item — flexbox layout helper

Wrap children in a flex container with control over direction, gap, and alignment.

{{< flex justify-content="space-between" column-gap="24px" >}}
  {{< flex-item >}}**Left** column content.{{< /flex-item >}}
  {{< flex-item >}}**Right** column content.{{< /flex-item >}}
{{< /flex >}}
**Left** column content. Useful for side-by-side comparisons or "before/after" prose.
**Right** column content. The wrapper accepts standard flex properties.

tab + tab-item — tabbed content

The tab-item shortcode uses the {{% %}} markdown form so fenced code blocks inside it render correctly. The label= attribute sets the tab header.

{{</* tab */>}}
  {{%/* tab-item label="Python" %}}
```python
print("hello")
```
  {{% /tab-item %}}
  {{% tab-item label="JavaScript" %}}
```javascript
console.log("hello");
```
  {{% /tab-item %}}
{{< /tab >}}
print("hello")
console.log("hello");

details — collapsible disclosure

{{< details summary="Click to expand" >}}
Hidden content goes here.
{{< /details >}}
Click to expand

Hidden content goes here. Use it for long appendices, derivations, or “if you really want to know” sidebars.


Code & Text

highlight — syntax-highlighted block with title

A wrapper around Chroma that adds an optional title bar.

{{< highlight lang="python" title="fibonacci.py" >}}
def fib(n):
    return n if n < 2 else fib(n-1) + fib(n-2)
{{< /highlight >}}
fibonacci.py
def fib(n):
    return n if n < 2 else fib(n-1) + fib(n-2)

include — inline another file (raw HTML)

{{< include "snippets/hello.html" >}}

Hello from snippets/hello.html!

This file is loaded inline by the include shortcode.

include-code — inline another file as a code block

{{< include-code file="snippets/hello.py" language="python" >}}
def hello(name: str = "world") -> str:
    """Greet someone. Inlined by the `include-code` shortcode."""
    return f"Hello, {name}!"


if __name__ == "__main__":
    print(hello("Inkstone"))

copy-to-clipboard — inline copy button

The text= parameter is the button label; the inner content is what gets copied to the clipboard.

Email: {{< copy-to-clipboard text="Copy" >}}user@example.com{{< /copy-to-clipboard >}}

Email: Copy

pseudocode — academic pseudocode rendering

Renders LaTeX-style algorithm pseudocode. Lazy-loads the renderer only on pages that use it.

{{< pseudocode >}}
\begin{algorithm}
\caption{Binary Search}
\begin{algorithmic}
\REQUIRE sorted array $A$, target $t$
\STATE $\ell \gets 0$, $r \gets |A| - 1$
\WHILE{$\ell \leq r$}
  \STATE $m \gets \lfloor (\ell + r) / 2 \rfloor$
  \IF{$A[m] = t$} \RETURN $m$ \ENDIF
  \IF{$A[m] < t$} \STATE $\ell \gets m + 1$
  \ELSE \STATE $r \gets m - 1$
  \ENDIF
\ENDWHILE
\RETURN $-1$
\end{algorithmic}
\end{algorithm}
{{< /pseudocode >}}
    
\begin{algorithm}
\caption{Binary Search}
\begin{algorithmic}
\REQUIRE sorted array $A$, target $t$
\STATE $\ell \gets 0$, $r \gets |A| - 1$
\WHILE{$\ell \leq r$}
  \STATE $m \gets \lfloor (\ell + r) / 2 \rfloor$
  \IF{$A[m] = t$} \RETURN $m$ \ENDIF
  \IF{$A[m] < t$} \STATE $\ell \gets m + 1$
  \ELSE \STATE $r \gets m - 1$
  \ENDIF
\ENDWHILE
\RETURN $-1$
\end{algorithmic}
\end{algorithm}

  
{{< button href="https://github.com/BerBai/inkstone" target="_blank" >}}View on GitHub{{< /button >}}
View on GitHub

pullquote — large emphasized quote

{{< pullquote author="Italo Calvino" >}}
A classic is a book that has never finished saying what it has to say.
{{< /pullquote >}}
A classic is a book that has never finished saying what it has to say. — Italo Calvino

rating — generic star rating

Display-only stars over a configurable max (default 5). Any input is rounded to the nearest 0.5 and clamped to [0, max]. The aria-label is i18n-driven and uses the rounded value so visual and screen-reader output stay in sync.

My take: {{< rating value="4.5" >}} (out of 5)

On a 10-point scale: {{< rating value="8" max="10" >}}

My take: (out of 5)

On a 10-point scale:


Media

figure — captioned image

{{< figure src="/img/figure-demo.svg" alt="Demo image" caption="A captioned figure with alt text." >}}
Demo image
A captioned figure with alt text.

image-compare — before/after slider

The shortcode takes image-before and image-after (note the prefix — required by the underlying viewer).

{{< image-compare image-before="/img/compare-before.svg" image-after="/img/compare-after.svg" >}}

Driven by a JSON data file. The fixture below lives at static/data/smoke/gallery.json (use an absolute path so the JS fetch resolves correctly from any page URL).

{{< gallery data="/data/smoke/gallery.json" >}}

video — self-hosted MP4/WebM

{{< video mp4="https://example.com/demo.mp4" controls=true >}}

Skipped here because exampleSite/ ships with no MP4 fixture. See the source code at layouts/shortcodes/video.html for the full parameter list.

youtube — YouTube embed

{{< youtube id="dQw4w9WgXcQ" >}}

bilibili — Bilibili embed

{{< bilibili bvid="BV1xx411c7mD" >}}

Live render skipped to avoid loading external iframes during the demo build. The shortcode accepts bvid (preferred) or aid.

song — NetEase Music single-track player

{{< song id="447925558" >}}

Live render skipped (CDN dependency). The shortcode accepts NetEase track IDs via id.

{{< swiper data="data/smoke/swiper.json" >}}

No fixture shipped in exampleSite/. See layouts/shortcodes/swiper.html for the schema.


Diagrams & Math

Mermaid diagrams (via fenced codeblock)

```mermaid
flowchart LR
  A[hugo build] --> B{has tag?}
  B -->|yes| C[use latest tag]
  B -->|no| D[use latest commit]
  C --> E[deploy preview]
  D --> E
```
  flowchart LR
  A[hugo build] --> B{has tag?}
  B -->|yes| C[use latest tag]
  B -->|no| D[use latest commit]
  C --> E[deploy preview]
  D --> E

Markmap mind maps (via fenced codeblock)

```markmap
# Inkstone
## Layouts
- baseof
- single
- list
## Shortcodes
- callout
- admonition
- gallery
```

antv-g2 — declarative chart

{{< antv-g2 script="data/charts/sample.js" caption="A sample chart" >}}

No script fixture shipped. The shortcode loads @antv/g2 from CDN and runs your chart spec from the given resource path. See static/data/smoke/ patterns to provide your own.

Math (MathJax v4)

Inline: $E = mc^2$.

Block:

$$ \frac{\partial}{\partial t} \rho + \nabla \cdot (\rho \mathbf{v}) = 0 $$

The MathJax CDN is only injected on pages that contain math delimiters — pages without math pay zero cost.


External & Embeds

iframe — embed external content with theme bridge

The theme passes a theme=light|dark query param to known hosts (codepen.io, codesandbox.io, stackblitz.com, replit.com), so embedded content matches the site’s current theme.

{{< iframe src="https://codepen.io/team/codepen/embed/PNaGbb" ratio=0.6 >}}

Live render skipped to keep this demo offline-friendly. The bridge whitelist lives at data/iframe_theme_hosts.toml.

douban-card — Douban book/movie card

{{< douban-card type="book" id="1084336" >}}

Requires Douban API access. The shortcode renders a card linking back to Douban.

wechat-qr — WeChat OA QR popover

{{< wechat-qr name="My OA" image="/img/wechat-qr.svg" >}}

Hover or focus this element to see a QR code popover: Demo OA


Summary

That’s the full shortcode catalog as of the current release. For production usage:

  • Always pass alt on figure, image-compare, and gallery for a11y
  • Don’t autoplay video unless you’re embedding a silent looping clip — Inkstone defaults autoplay=false
  • Lazy-loaded shortcodes (mermaid, markmap, antv-g2, mathjax, pseudocode, swiper, song) only fetch their CDN libs when the shortcode is actually present on the page

Issues or feature requests: github.com/BerBai/inkstone/issues .