Change the way admonitions work
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
This commit is contained in:
parent
bbfe4f67ca
commit
06d483b3dd
14 changed files with 94 additions and 83 deletions
|
@ -5,7 +5,7 @@ import { rehypeAccessibleEmojis } from "rehype-accessible-emojis";
|
|||
import remarkReadingTime from "./plugin/remark-reading-time";
|
||||
import remarkEmoji from "remark-emoji";
|
||||
import remarkDescription from "astro-remark-description";
|
||||
import remarkAdmonitions from "./plugin/remark-admonitions";
|
||||
import remarkAdmonitions, { mkdocsConfig } from "./plugin/remark-admonitions";
|
||||
import remarkMath from "remark-math";
|
||||
import rehypeKatex from "rehype-katex";
|
||||
import remarkTypst from "./plugin/remark-typst";
|
||||
|
@ -35,7 +35,7 @@ export default defineConfig({
|
|||
remarkPlugins: [
|
||||
() => remarkAgda({ outDir, base, publicDir }),
|
||||
remarkMath,
|
||||
remarkAdmonitions,
|
||||
[remarkAdmonitions, mkdocsConfig],
|
||||
remarkReadingTime,
|
||||
remarkTypst,
|
||||
remarkEmoji,
|
||||
|
|
|
@ -6,6 +6,7 @@ import type { Data } from "unist";
|
|||
import type { BuildVisitor } from "unist-util-visit";
|
||||
import type { Blockquote, Paragraph, Text } from "mdast";
|
||||
import type { RemarkPlugin } from "@astrojs/markdown-remark";
|
||||
import classNames from "classnames";
|
||||
|
||||
const remarkAdmonitions: RemarkPlugin =
|
||||
(providedConfig?: Partial<Config>) => (tree) => {
|
||||
|
@ -14,59 +15,64 @@ const remarkAdmonitions: RemarkPlugin =
|
|||
|
||||
export default remarkAdmonitions;
|
||||
|
||||
const handleNode = (config: Config): BuildVisitor => (node) => {
|
||||
// Filter required elems
|
||||
if (node.type !== "blockquote") return;
|
||||
const blockquote = node as Blockquote;
|
||||
const handleNode =
|
||||
(config: Config): BuildVisitor =>
|
||||
(node) => {
|
||||
// Filter required elems
|
||||
if (node.type !== "blockquote") return;
|
||||
const blockquote = node as Blockquote;
|
||||
|
||||
if (blockquote.children[0]?.type !== "paragraph") return;
|
||||
if (blockquote.children[0]?.type !== "paragraph") return;
|
||||
|
||||
const paragraph = blockquote.children[0];
|
||||
if (paragraph.children[0]?.type !== "text") return;
|
||||
const paragraph = blockquote.children[0];
|
||||
if (paragraph.children[0]?.type !== "text") return;
|
||||
|
||||
const text = paragraph.children[0];
|
||||
const text = paragraph.children[0];
|
||||
|
||||
// A link break after the title is explicitly required by GitHub
|
||||
const titleEnd = text.value.indexOf("\n");
|
||||
if (titleEnd < 0) return;
|
||||
// A link break after the title is explicitly required by GitHub
|
||||
const titleEnd = text.value.indexOf("\n");
|
||||
if (titleEnd < 0) return;
|
||||
|
||||
const textBody = text.value.substring(titleEnd + 1);
|
||||
let title = text.value.substring(0, titleEnd);
|
||||
// Handle whitespaces after the title.
|
||||
// Whitespace characters are defined by GFM
|
||||
const m = /[ \t\v\f\r]+$/.exec(title);
|
||||
if (m && !config.titleKeepTrailingWhitespaces) {
|
||||
title = title.substring(0, title.length - m[0].length);
|
||||
}
|
||||
if (!nameFilter(config.titleFilter)(title)) return;
|
||||
const { displayTitle, checkedTitle } = config.titleTextMap(title);
|
||||
const textBody = text.value.substring(titleEnd + 1);
|
||||
let title = text.value.substring(0, titleEnd);
|
||||
// Handle whitespaces after the title.
|
||||
// Whitespace characters are defined by GFM
|
||||
const m = /[ \t\v\f\r]+$/.exec(title);
|
||||
if (m && !config.titleKeepTrailingWhitespaces) {
|
||||
title = title.substring(0, title.length - m[0].length);
|
||||
}
|
||||
if (!nameFilter(config.titleFilter)(title)) return;
|
||||
const { displayTitle, checkedTitle } = config.titleTextMap(title);
|
||||
|
||||
// Update the text body
|
||||
text.value = textBody;
|
||||
// Update the text body
|
||||
text.value = textBody;
|
||||
|
||||
// Insert the title element and add classes for the title
|
||||
const paragraphTitleText: Text = { type: "text", value: displayTitle };
|
||||
const paragraphTitle: Paragraph = {
|
||||
type: "paragraph",
|
||||
children: [paragraphTitleText],
|
||||
data: config.dataMaps.title({
|
||||
// Insert the title element and add classes for the title
|
||||
const paragraphTitleText: Text = { type: "text", value: displayTitle };
|
||||
const paragraphTitle: Paragraph = {
|
||||
type: "paragraph",
|
||||
children: [paragraphTitleText],
|
||||
data: config.dataMaps.title({
|
||||
hProperties: {
|
||||
className: classNameMap(config.classNameMaps.title)(checkedTitle),
|
||||
},
|
||||
}),
|
||||
};
|
||||
blockquote.children.unshift(paragraphTitle);
|
||||
|
||||
// Add classes for the block
|
||||
blockquote.data = config.dataMaps.block({
|
||||
...blockquote.data,
|
||||
hProperties: {
|
||||
className: classNameMap(config.classNameMaps.title)(checkedTitle),
|
||||
className: classNameMap(config.classNameMaps.block)(checkedTitle),
|
||||
},
|
||||
}),
|
||||
// The blockquote should be rendered as a div, which is explicitly required by GitHub
|
||||
hName: "div",
|
||||
});
|
||||
};
|
||||
blockquote.children.unshift(paragraphTitle);
|
||||
|
||||
// Add classes for the block
|
||||
blockquote.data = config.dataMaps.block({
|
||||
...blockquote.data,
|
||||
hProperties: {
|
||||
className: classNameMap(config.classNameMaps.block)(checkedTitle),
|
||||
},
|
||||
// The blockquote should be rendered as a div, which is explicitly required by GitHub
|
||||
hName: "div",
|
||||
});
|
||||
};
|
||||
const TITLE_PATTERN =
|
||||
/\[\!admonition: (attention|caution|danger|error|hint|important|note|tip|warning)\]/i;
|
||||
|
||||
export const mkdocsConfig: Partial<Config> = {
|
||||
classNameMaps: {
|
||||
|
@ -74,40 +80,34 @@ export const mkdocsConfig: Partial<Config> = {
|
|||
"admonition",
|
||||
...(title.startsWith("admonition: ")
|
||||
? title.substring("admonition: ".length)
|
||||
: title).split(
|
||||
" ",
|
||||
),
|
||||
: title
|
||||
).split(" "),
|
||||
],
|
||||
title: "admonition-title",
|
||||
title: classNames("admonition-title"),
|
||||
},
|
||||
titleFilter: (title) =>
|
||||
(title.startsWith("[!admonition: ") && title.endsWith("]")) ||
|
||||
(Boolean(
|
||||
title.match(
|
||||
/^\[!(attention|caution|danger|error|hint|important|note|tip|warning)/,
|
||||
),
|
||||
) &&
|
||||
title.endsWith("]")),
|
||||
titleTextMap: (title) => {
|
||||
title = title.substring(2, title.length - 1);
|
||||
// ' "' will not occur in classes
|
||||
const i = title.indexOf(' "');
|
||||
const displayTitle = i >= 0
|
||||
? title.substring(i + 2, title.length - 1) // Display title is wrapped with ""
|
||||
: "";
|
||||
const checkedTitle = title.substring(0, i);
|
||||
|
||||
titleFilter: (title) => Boolean(title.match(TITLE_PATTERN)),
|
||||
|
||||
titleTextMap: (title: string) => {
|
||||
console.log("title", title);
|
||||
const match = title.match(TITLE_PATTERN);
|
||||
console.log("matches", match);
|
||||
const displayTitle = match?.[1] ?? "";
|
||||
const checkedTitle = displayTitle;
|
||||
return { displayTitle, checkedTitle };
|
||||
},
|
||||
};
|
||||
|
||||
export interface Config {
|
||||
classNameMaps: {
|
||||
block: ClassNameMap;
|
||||
title: ClassNameMap;
|
||||
};
|
||||
titleFilter: NameFilter;
|
||||
titleTextMap: (
|
||||
title: string,
|
||||
) => { displayTitle: string; checkedTitle: string };
|
||||
titleTextMap: (title: string) => {
|
||||
displayTitle: string;
|
||||
checkedTitle: string;
|
||||
};
|
||||
dataMaps: {
|
||||
block: (data: Data) => Data;
|
||||
title: (data: Data) => Data;
|
||||
|
@ -121,7 +121,9 @@ export const defaultConfig: Config = {
|
|||
block: "admonition",
|
||||
title: "admonition-title",
|
||||
},
|
||||
|
||||
titleFilter: ["[!NOTE]", "[!IMPORTANT]", "[!WARNING]"],
|
||||
|
||||
titleTextMap: (title) => ({
|
||||
displayTitle: title.substring(2, title.length - 1),
|
||||
checkedTitle: title.substring(2, title.length - 1),
|
||||
|
|
|
@ -12,7 +12,7 @@ container without exiting it. Some Docker containers are incredibly stripped
|
|||
down to optimize away bloat (which is good!) but this may make debugging them
|
||||
relatively annoying.
|
||||
|
||||
> [!NOTE]
|
||||
> [!admonition: NOTE]
|
||||
> These are my specific steps for running it, please replace the paths and
|
||||
> container names with the ones relevant to your specific use-case.
|
||||
|
||||
|
|
|
@ -61,7 +61,7 @@ I shove new config files in their root directory.
|
|||
flake.nix ✗
|
||||
```
|
||||
|
||||
> [!NOTE]
|
||||
> [!admonition: NOTE]
|
||||
> The `✗` indicates that I added the file to the project, and it hasn't been
|
||||
> committed to the repo yet.
|
||||
|
||||
|
@ -131,7 +131,7 @@ project structure should look a bit more like this:
|
|||
flake.nix
|
||||
```
|
||||
|
||||
> [!NOTE]
|
||||
> [!admonition: NOTE]
|
||||
> Remember, since you moved the `.envrc` file, you will need to run `direnv allow`
|
||||
> again. Depending on how you moved it, you might also need to change the path you
|
||||
> wrote in the `use flake` command.
|
||||
|
|
|
@ -108,7 +108,7 @@ true≢false2 p = transport bool-map2 p refl
|
|||
|
||||
## Note on proving divergence on equivalent values
|
||||
|
||||
> [!NOTE]
|
||||
> [!admonition: NOTE]
|
||||
> Update: some of these have been commented out since regular Agda doesn't support higher inductive types
|
||||
|
||||
Let's make sure this isn't broken by trying to apply this to something that's
|
||||
|
|
|
@ -29,7 +29,7 @@ my personal schedule, yet they only see a small slice of your life. The only
|
|||
things calendars can see automatically with no intervention on my part are
|
||||
emails that are sent from airlines.
|
||||
|
||||
> [!NOTE]
|
||||
> [!admonition: NOTE]
|
||||
> I'm sure Google or Apple could probably ritz up their services to scan text
|
||||
> and guess events to put on your calendar, but that's missing the point. The vast
|
||||
> majority of people I associate with rarely coordinate events over email in the
|
||||
|
@ -118,7 +118,7 @@ data using various visualizations for this purpose.
|
|||
|
||||
[2]: https://git.mzhang.io/michael/logseq-calendar
|
||||
|
||||
> [!NOTE]
|
||||
> [!admonition: NOTE]
|
||||
> As an aside, this isn't sponsored in any way. While this post makes me sound
|
||||
> like just a Logseq shill, it's actually quite the opposite: they're an
|
||||
> open-source project solely funded by donations. I've been donating to them
|
||||
|
|
|
@ -142,7 +142,7 @@ That's quite a mouthful. If you tried calling $Y$ on some term, you will find
|
|||
that evaluation will quickly expand infinitely. That makes sense given its
|
||||
purpose: to find a _fixed point_ of whatever function you pass in.
|
||||
|
||||
> [!NOTE]
|
||||
> [!admonition: NOTE]
|
||||
> As an example, the fixed-point of the function $f(x) = \sqrt{x}$ is $1$.
|
||||
> That's because $f(1) = 1$, and applying $f$ to any other number sort of
|
||||
> converges in on this value. If you took any number and applied $f$ infinitely
|
||||
|
@ -221,7 +221,7 @@ much. But as a result of this tiny change, _every_ term now has a type:
|
|||
- $λ(x:\mathbb{N}).2x :: \mathbb{N} \rightarrow \mathbb{N}$
|
||||
- $isEven(3) :: (\mathbb{N} \rightarrow \mathrm{Bool}) · \mathbb{N} = \mathrm{Bool}$
|
||||
|
||||
> [!NOTE]
|
||||
> [!admonition: NOTE]
|
||||
> Some notation:
|
||||
>
|
||||
> - $x :: T$ means $x$ has type $T$, and
|
||||
|
|
|
@ -16,7 +16,7 @@ to, since they're very different concepts.
|
|||
to be the same, so anytime you see $x$, you can replace it with $y$ and vice
|
||||
versa."
|
||||
|
||||
> [!NOTE]
|
||||
> [!admonition: NOTE]
|
||||
> Technically speaking, definitional and judgmental are two separate concepts
|
||||
> but coincide in many type theories. You could think of multiple levels of
|
||||
> equalities like this:
|
||||
|
|
|
@ -70,7 +70,7 @@ data Type where
|
|||
|
||||
Monotypes (usually denoted $\tau$) are types that aren't universally quantified.
|
||||
|
||||
> [!NOTE]
|
||||
> [!admonition: NOTE]
|
||||
> In the declarative version of this algorithm, monotypes don't have existential quantifiers either,
|
||||
> but the algorithmic type system includes it.
|
||||
> TODO: Explain why
|
||||
|
|
|
@ -22,7 +22,7 @@ data _≡_ {l} {A : Set l} : (a b : A) → Set l where
|
|||
|
||||
</details>
|
||||
|
||||
> [!NOTE]
|
||||
> [!admonition: NOTE]
|
||||
> This content is a writeup from a weekend discussion session for the fall 2023 special-topics course CSCI 8980 at the University of Minnesota taught by [Favonia], who provided the examples.
|
||||
> This post is primarily a summary of the concepts discussed.
|
||||
|
||||
|
|
|
@ -130,7 +130,7 @@ With this knowledge, when you see a 200 BPM song, you can divide $300 / 200 = 1.
|
|||
|
||||
Some tools like [3icecream] have a BPM calculator for charts if you enter in your reading speed, but often using your phone's calculator or just memorizing some common benchmark BPMs will do just fine.
|
||||
|
||||
> [!NOTE]
|
||||
> [!admonition: NOTE]
|
||||
> Since every song you play might be a different BPM, always check to make sure the scroll speed is what you want!
|
||||
|
||||
If a song's BPM is variable, it will show a range instead.
|
||||
|
@ -312,4 +312,4 @@ There's an incredible wealth of information across the internet about this game,
|
|||
While I'm certainly not even close to the end of my journey with DDR, I hope that you got to learn something from my experience.
|
||||
|
||||
If there's something I got wrong, or some resources or information you want me to add, please let me know in the comments.
|
||||
**See you next time on the dance floor!**
|
||||
**See you next time on the dance floor!**
|
||||
|
|
|
@ -55,7 +55,7 @@ boat load of files to hide your potential complexity into, consider whether the
|
|||
cost of adding that abstraction is worth the pain it will take to change it
|
||||
later.
|
||||
|
||||
> [!NOTE]
|
||||
> [!admonition: NOTE]
|
||||
> As a bonus, if your language has a good enough type system, you probably don't
|
||||
> need the strategy pattern at all. Just create a function signature and pass
|
||||
functions as values!
|
||||
|
|
|
@ -22,6 +22,8 @@
|
|||
// Admonition
|
||||
--note-color: #{$linkColor};
|
||||
--note-background-color: var(--link-hover-color);
|
||||
--warning-color: rgb(208, 126, 25);
|
||||
--warning-bg-color: rgb(255, 250, 202);
|
||||
|
||||
// Syntax Highlighting
|
||||
--astro-code-color-text: #24292e;
|
||||
|
@ -62,6 +64,8 @@
|
|||
// Admonition
|
||||
--note-color: #{$linkColor};
|
||||
--note-background-color: var(--link-hover-color);
|
||||
--warning-color: rgb(211, 185, 107);
|
||||
--warning-bg-color: rgb(121, 81, 21);
|
||||
|
||||
// Syntax Highlighting
|
||||
--astro-code-color-text: #e1e4e8;
|
||||
|
|
|
@ -245,10 +245,10 @@ hr.endline {
|
|||
}
|
||||
|
||||
.admonition {
|
||||
// TODO: Figure out how to distinguish admonitions
|
||||
--admonition-color: var(--note-color);
|
||||
--admonition-bg-color: var(--note-background-color);
|
||||
|
||||
background-color: var(--note-background-color);
|
||||
background-color: var(--admonition-bg-color);
|
||||
border-left: 4px solid var(--admonition-color);
|
||||
padding: 8px;
|
||||
font-size: 0.9rem;
|
||||
|
@ -269,4 +269,9 @@ hr.endline {
|
|||
:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
&.WARNING {
|
||||
--admonition-color: var(--warning-color);
|
||||
--admonition-bg-color: var(--warning-bg-color);
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue