r4ai / remark-callout

A remark plugin to add obsidian style callouts to markdown
https://r4ai.github.io/remark-callout/
MIT License
4 stars 1 forks source link
callout caution markdown remark remark-plugin

remark-callout

npm version test coverage CI Release CodeQL

NPM

[!important] Website: https://r4ai.github.io/remark-callout

A remark plugin to add obsidian style callouts to markdown.

> [!note] title here
> body here

Installation

# npm
npm install @r4ai/remark-callout

# pnpm
pnpm install @r4ai/remark-callout

# bun
bun add @r4ai/remark-callout

Usage

See Usage.

Quick Start

Vanilla JS

import remarkParse from "remark-parse";
import { unified } from "unified";
import remarkCallout from "@r4ai/remark-callout";
import remarkRehype from "remark-rehype";
import rehypeRaw from "rehype-raw";
import rehypeStringify from "rehype-stringify";

const md = `
  > [!note] title here
  > body here
`;

const html = unified()
  .use(remarkParse)
  .use(remarkCallout)
  .use(remarkRehype, { allowDangerousHtml: true })
  .use(rehypeRaw)
  .use(rehypeStringify)
  .processSync(md)
  .toString();

console.log(html);

yields:

<div data-callout data-callout-type="note">
  <div data-callout-title>title here</div>
  <div data-callout-body>
    <p>body here</p>
  </div>
</div>

[!WARNING] To display the callout icon as HTML using options.icon or options.foldIcon, you need to set the allowDangerousHtml option to true in remark-rehype and add rehype-raw as a plugin.

Astro

  1. Install the plugin:

    npm install @r4ai/remark-callout
  2. Add @r4ai/remark-callout to remark plugins in your astro config file (e.g. astro.config.ts):

    // astro.config.ts
    import remarkCallout from "@r4ai/remark-callout";
    
    export default defineConfig({
     // ...
     markdown: {
       // ...
       remarkPlugins: [
         // ...
         remarkCallout,
       ],
     },
    });

    Note: This plugin works fine in MDX files as well. For instructions on how to use MDX with Astro, see @astrojs/mdx.

  3. Start using callouts in your markdown or mdx files:

    > [!note] title here
    > body here

    yields:

    <div data-callout data-callout-type="note">
     <div data-callout-title>title here</div>
     <div data-callout-body>
       <p>body here</p>
     </div>
    </div>

    Now you can style the callouts using CSS. Following is an example of how you can style the callouts using Tailwind CSS:

    https://github.com/r4ai/remark-callout/blob/40d857e9885d335ca0c688d6eb2755e54dd2567b/packages/website/src/pages/playground/_callout.css#L1-L384

    Or if you are using MDX, you can use custom components to style the callouts:

    // astro.config.ts
    import { remarkCallout } from "@r4ai/remark-callout";
    
    export default defineConfig({
     // ...
     markdown: {
       // ...
       remarkPlugins: [
         // ...
         [
           remarkCallout,
           {
             root: (callout) => ({
               tagName: "callout",
               properties: {
                 calloutType: callout.type,
                 isFoldable: String(callout.isFoldable),
               },
             }),
             title: (callout) => ({
               tagName: "callout-title",
               properties: {
                 calloutType: callout.type,
                 isFoldable: String(callout.isFoldable),
               },
             }),
           },
         ],
       ],
     },
    });
    ---
    // src/components/Callout.astro
    
    type Props = {
     calloutType: string
     isFoldable: boolean
    }
    const { calloutType, isFoldable } = Astro.props
    ---
    
    <div
     class={/* Your TailwindCSS style here */}
    >
     <slot />
    </div>
    ---
    // src/components/CalloutTitle.astro
    
    type Props = {
     callouType: string
     isFoldable: boolean
    }
    const { calloutType, isFoldable } = Astro.props
    ---
    
    <div
     class={/* Your TailwindCSS style here */}
    >
     <SomeIconComponent />
     <slot />
    </div>
    ---
    // src/pages/callout-example.astro
    
    import { Content, components } from "../content.mdx";
    import Callout from "../components/Callout.astro";
    import CalloutTitle from "../components/CalloutTitle.astro";
    ---
    
    <Content components={{ ...components, callout: Callout, "callout-title": CalloutTitle }} />

Options

See r4ai.github.io/remark-callout/docs/en/api-reference/type-aliases/options

Development

Commands

Command Description
bun install Install dependencies
bun run build Build the packages
bun run test Run tests
bun run test:coverage Run tests with coverage
bun run check Check the code
bun run check:write Check and fix the code
bun run changeset Create a changeset

Directory Structure

Directory Description
examples/nextjs Example Next.js project
packages/remark-callout The remark-callout package
packages/website The documentation website for remark-callout

Getting Started

  1. Install dependencies:

    bun install
  2. Build the packages:

    bun run build
  3. Check and fix the code:

    bun run check:write
  4. Run tests with coverage:

    bun run test:coverage
  5. Launch the documentation website:

    bun run --cwd packages/website dev