Skip to content

Commit e0506cb

Browse files
authored
feat: add callout support (#655)
* feat: toggle .dark class on theme change * feat: add callouts with rehype-callouts plugin * docs: update blog posts with callouts
1 parent 98f15ee commit e0506cb

10 files changed

Lines changed: 106 additions & 25 deletions

File tree

astro.config.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import sitemap from "@astrojs/sitemap";
1010
import { unified } from "@astrojs/markdown-remark";
1111
import remarkToc from "remark-toc";
1212
import remarkCollapse from "remark-collapse";
13+
import rehypeCallouts from "rehype-callouts";
1314
import {
1415
transformerNotationDiff,
1516
transformerNotationHighlight,
@@ -40,6 +41,7 @@ export default defineConfig({
4041
remarkToc,
4142
[remarkCollapse, { test: "Table of contents" }],
4243
],
44+
rehypePlugins: [rehypeCallouts],
4345
}),
4446
shikiConfig: {
4547
themes: { light: "min-light", dark: "night-owl" },

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
"astro": "^6.4.2",
2424
"dayjs": "^1.11.21",
2525
"lodash.kebabcase": "^4.1.1",
26+
"rehype-callouts": "^2.1.2",
2627
"remark-collapse": "^0.1.2",
2728
"remark-toc": "^9.0.0",
2829
"satori": "^0.26.0",

pnpm-lock.yaml

Lines changed: 15 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/content/posts/adding-new-post.mdx

Lines changed: 69 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
---
22
author: Sat Naing
33
pubDatetime: 2022-09-23T15:22:00Z
4-
modDatetime: 2026-05-17T04:47:08.212Z
4+
modDatetime: 2026-06-03T00:00:00.000Z
55
title: Adding new posts in AstroPaper theme
66
slug: adding-new-posts-in-astropaper-theme
77
featured: true
@@ -44,6 +44,7 @@ src/content/posts/docs/_legacy/how-to.md -> mysite.com/posts/docs/how-to
4444
src/content/posts/Example Dir/Dummy Post.md -> mysite.com/posts/example-dir/dummy-post
4545
```
4646

47+
> [!TIP]
4748
> Files and directories prefixed with `_` are excluded from routing. Use them for drafts, shared assets, or internal-only content.
4849
4950
## Frontmatter
@@ -71,7 +72,8 @@ Here is the list of frontmatter properties for each post:
7172

7273
</ResponsiveTable>
7374

74-
> Tip! You can get an ISO 8601 datetime by running `new Date().toISOString()` in the console.
75+
> [!TIP]
76+
> You can get an ISO 8601 datetime by running `new Date().toISOString()` in the console.
7577
7678
Only `title`, `description`, and `pubDatetime` fields in frontmatter must be specified.
7779

@@ -116,6 +118,65 @@ AstroPaper includes workspace snippets to speed up creating new posts:
116118

117119
These snippets live in `.vscode/astro-paper.code-snippets`. If you use VS Code (or Cursor), they should be available automatically when you open the workspace.
118120

121+
## Callouts
122+
123+
AstroPaper started supporting callouts in AstroPaper v6.1. They use a simple blockquote syntax powered by `rehype-callouts` (Obsidian theme).
124+
125+
Here are the most commonly used types:
126+
127+
> [!NOTE]
128+
> Supplementary information the reader should be aware of.
129+
130+
> [!TIP]
131+
> Helpful advice, shortcuts, or best practices.
132+
133+
> [!WARNING]
134+
> Something that could go wrong or have unintended consequences.
135+
136+
> [!DANGER]
137+
> Serious risk of failure, data loss, or incorrect behavior.
138+
139+
> [!INFO]
140+
> Neutral informational context — less urgent than a note.
141+
142+
> [!SUCCESS]
143+
> Confirmation that something worked or is correct.
144+
145+
The full list of supported types includes: `NOTE`, `ABSTRACT`, `INFO`, `TODO`, `TIP`, `SUCCESS`, `QUESTION`, `WARNING`, `FAILURE`, `DANGER`, `BUG`, `EXAMPLE`, `QUOTE` — each with its own icon and color. Many types also accept aliases (e.g. `HINT` and `IMPORTANT` for `TIP`, `CAUTION` for `WARNING`). See the [rehype-callouts docs](https://github.com/lin-stephanie/rehype-callouts) for the complete reference.
146+
147+
### Collapsible callouts
148+
149+
Add `-` after the type to make the callout collapsed by default, or `+` to make it expanded but collapsible:
150+
151+
> [!WARNING]- Read before proceeding
152+
> This content is hidden until the reader expands it. Useful for long caveats that would otherwise interrupt the flow.
153+
154+
> [!TIP]+ Pro tip (expanded by default)
155+
> This starts open but can be collapsed. Great for optional detail you still want visible on first load.
156+
157+
### Custom titles
158+
159+
Replace the default type label with any title you like by adding text after the type:
160+
161+
> [!NOTE] Did you know?
162+
> The text after the type becomes the callout's heading. Leave it out and the type name is used automatically.
163+
164+
### Syntax summary
165+
166+
```md
167+
> [!NOTE]
168+
> Supplementary information.
169+
170+
> [!WARNING]- Collapsed by default
171+
> Hidden until expanded.
172+
173+
> [!TIP]+ Expanded, but collapsible
174+
> Starts open.
175+
176+
> [!DANGER] Custom title
177+
> Replaces the default heading.
178+
```
179+
119180
## Adding table of contents
120181

121182
By default, a post does not include any table of contents (TOC). To include one, write `Table of contents` as an h2 heading (`##` in Markdown) and place it where you want it to appear:
@@ -181,7 +242,8 @@ export default defineConfig({
181242

182243
Here are two methods for storing images and using them inside a markdown file.
183244

184-
> Note: If you need to style optimized images in markdown, you should [use MDX](https://docs.astro.build/en/guides/images/#images-in-mdx-files).
245+
> [!IMPORTANT]
246+
> If you need to style optimized images in markdown, you should [use MDX](https://docs.astro.build/en/guides/images/#images-in-mdx-files).
185247
186248
### Inside `src/assets/` directory (recommended)
187249

@@ -203,6 +265,7 @@ Example: suppose you want to display `example.jpg` whose path is `src/assets/ima
203265
<!-- ^^ This is wrong -->
204266
```
205267

268+
> [!TIP]
206269
> Technically, you can store images inside any directory under `src`. `src/assets` is just a recommendation.
207270
208271
### Inside `public/` directory
@@ -225,7 +288,8 @@ Example: assume `example.jpg` is located at `public/assets/images/example.jpg`.
225288

226289
### Image compression
227290

228-
When putting images in a blog post (especially those in the `public/` directory), it is recommended to compress them. This will affect the overall performance of the website.
291+
> [!WARNING]
292+
> When putting images in a blog post (especially those in the `public/` directory), compress them first. Unoptimized images significantly hurt page performance.
229293
230294
Recommended image compression sites:
231295

@@ -236,4 +300,5 @@ Recommended image compression sites:
236300

237301
The default OG image will be used if a post does not specify one. Though not required, an OG image relevant to the post should be specified in the frontmatter. The recommended size for OG images is **_1200 X 640_** px.
238302

303+
> [!TIP]
239304
> Since AstroPaper v1.4.0, OG images are generated automatically if not specified. Check out [the announcement](https://astro-paper.pages.dev/posts/dynamic-og-image-generation-in-astropaper-blog-posts/).

src/content/posts/dynamic-og-images.md

Lines changed: 8 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
---
22
author: Sat Naing
33
pubDatetime: 2022-12-28T04:59:04.866Z
4-
modDatetime: 2026-05-04T00:00:00Z
4+
modDatetime: 2026-06-03T00:00:00.000Z
55
title: Dynamic OG image generation in AstroPaper blog posts
66
slug: dynamic-og-image-generation-in-astropaper-blog-posts
77
featured: false
@@ -49,9 +49,8 @@ Dynamic OG images include _the blog post title_, _author name_, and _site title_
4949

5050
### Issue with Non-Latin Characters
5151

52-
Titles with non-latin characters won't display properly out of the box. In AstroPaper v6, dynamic OG images load font files from Astro's **Fonts** configuration (`astro.config.ts`) and register them with Satori.
53-
54-
To fix missing glyphs, switch the Google font family to one that covers your writing system, and make sure you include **both** `400` and `700` weights (Satori uses separate buffers for regular + bold).
52+
> [!CAUTION]
53+
> Titles with non-latin characters won't display properly out of the box. Switch the Google font family to one that covers your writing system, and include **both** `400` and `700` weights — Satori uses separate buffers for regular and bold, so missing either causes mismatched rendering.
5554
5655
```ts file="astro.config.ts"
5756
import { defineConfig, fontProviders } from "astro/config";
@@ -79,15 +78,8 @@ If you change `cssVariable`, also update the matching key in:
7978

8079
> Check out [this PR](https://github.com/satnaing/astro-paper/pull/318) for more info.
8180
82-
## Trade-off
83-
84-
While this is a nice feature to have, there's still a trade-off: AstroPaper generates one PNG per eligible post at build time (when og image is not specified in the frontmatter), so total build time grows with content volume.
85-
86-
In AstroPaper v6, OG image generation is significantly faster (PR [#632](https://github.com/satnaing/astro-paper/pull/632)) than earlier implementations, so the per-image overhead is much lower in practice. If you still want to minimize build time on very large sites, you can disable it by setting `features.dynamicOgImage: false` in `astro-paper.config.ts` (and provide per-post `ogImage` files instead).
87-
88-
## Limitations
89-
90-
At the time of writing this, [Satori](https://github.com/vercel/satori) is fairly new and has not reached major release yet. So, there are still some limitations to this dynamic OG image feature.
91-
92-
- RTL languages are not supported yet.
93-
- [Using emoji](https://github.com/vercel/satori#emojis) in the title might be a little bit tricky.
81+
> [!WARNING] Caveats
82+
>
83+
> - **Build time** grows with content volume — one PNG per eligible post is generated at build time. Generation is faster in v6 (PR [#632](https://github.com/satnaing/astro-paper/pull/632)), but on very large sites you can disable it with `features.dynamicOgImage: false` in `astro-paper.config.ts`.
84+
> - **RTL languages** are not supported yet.
85+
> - **Emoji** in titles can be tricky — some may not render correctly.

src/content/posts/how-to-configure-astropaper-theme.mdx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
---
22
author: Sat Naing
33
pubDatetime: 2022-09-23T04:58:53Z
4-
modDatetime: 2026-05-17T05:50:08.212Z
4+
modDatetime: 2026-06-03T00:00:00.000Z
55
title: How to configure AstroPaper theme
66
slug: how-to-configure-astropaper-theme
77
featured: true
@@ -296,7 +296,8 @@ import { Font } from "astro:assets";
296296

297297
The `--font-app` variable is used throughout the theme via the `font-app` Tailwind utility class, so updating this single variable applies your custom font everywhere.
298298

299-
> **Note**: Make sure the font name matches exactly as it appears on [Google Fonts](https://fonts.google.com). For other font providers or local fonts, refer to the [Astro Fonts documentation](https://docs.astro.build/en/guides/fonts/).
299+
> [!WARNING]
300+
> Make sure the font name matches exactly as it appears on [Google Fonts](https://fonts.google.com). For other font providers or local fonts, refer to the [Astro Fonts documentation](https://docs.astro.build/en/guides/fonts/).
300301
301302
## See also
302303

src/layouts/Layout.astro

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,9 @@ const rssHref = getRelativeLocaleUrl(
106106
"(prefers-color-scheme: dark)"
107107
).matches;
108108
const theme = stored ?? (prefersDark ? "dark" : "light");
109-
document.firstElementChild?.setAttribute("data-theme", theme);
109+
const root = document.firstElementChild;
110+
root?.setAttribute("data-theme", theme);
111+
root?.classList.toggle("dark", theme === "dark");
110112
// Expose value so theme.ts can skip re-detection.
111113
window.__theme = { value: theme };
112114
})();

src/scripts/theme.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,9 @@ function persist(): void {
2121
}
2222

2323
function reflect(): void {
24-
document.firstElementChild?.setAttribute("data-theme", themeValue);
24+
const root = document.firstElementChild;
25+
root?.setAttribute("data-theme", themeValue);
26+
root?.classList.toggle("dark", themeValue === DARK);
2527
document.querySelector("#theme-btn")?.setAttribute("aria-label", themeValue);
2628

2729
// Fill <meta name="theme-color"> with the computed background colour so

src/styles/global.css

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
@import "tailwindcss";
22
@import "./theme.css";
33
@import "./typography.css";
4+
@import "rehype-callouts/theme/obsidian";
45

56
@custom-variant dark (&:where([data-theme=dark], [data-theme=dark] *));
67

src/styles/typography.css

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@
8282
@apply border-s-accent/80 wrap-break-word opacity-80;
8383
}
8484

85-
details {
85+
details:not(.callout) {
8686
@apply text-foreground inline-block cursor-pointer select-none [&_p]:hidden [&_ul]:my-0!;
8787
}
8888

0 commit comments

Comments
 (0)