diff --git a/astro.config.ts b/astro.config.ts index 2ab9624..e8d131d 100644 --- a/astro.config.ts +++ b/astro.config.ts @@ -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, diff --git a/plugin/remark-admonitions.ts b/plugin/remark-admonitions.ts index 1391833..87ee409 100644 --- a/plugin/remark-admonitions.ts +++ b/plugin/remark-admonitions.ts @@ -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) => (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 = { classNameMaps: { @@ -74,40 +80,34 @@ export const mkdocsConfig: Partial = { "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), diff --git a/src/content/posts/2023-03-29-shell-in-docker-compose-container-without-shell.md b/src/content/posts/2023-03-29-shell-in-docker-compose-container-without-shell.md index 7876718..63e504c 100644 --- a/src/content/posts/2023-03-29-shell-in-docker-compose-container-without-shell.md +++ b/src/content/posts/2023-03-29-shell-in-docker-compose-container-without-shell.md @@ -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. diff --git a/src/content/posts/2023-04-20-developing-without-flake.md b/src/content/posts/2023-04-20-developing-without-flake.md index c88cf7d..41be908 100644 --- a/src/content/posts/2023-04-20-developing-without-flake.md +++ b/src/content/posts/2023-04-20-developing-without-flake.md @@ -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. diff --git a/src/content/posts/2023-04-21-proving-true-from-false.lagda.md b/src/content/posts/2023-04-21-proving-true-from-false.lagda.md index 920d783..5c191f7 100644 --- a/src/content/posts/2023-04-21-proving-true-from-false.lagda.md +++ b/src/content/posts/2023-04-21-proving-true-from-false.lagda.md @@ -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 diff --git a/src/content/posts/2023-08-31-thoughts-on-organization/index.md b/src/content/posts/2023-08-31-thoughts-on-organization/index.md index 4baa175..e1e5738 100644 --- a/src/content/posts/2023-08-31-thoughts-on-organization/index.md +++ b/src/content/posts/2023-08-31-thoughts-on-organization/index.md @@ -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 diff --git a/src/content/posts/2023-09-01-formal-cek-machine-in-agda/index.md b/src/content/posts/2023-09-01-formal-cek-machine-in-agda/index.md index e33076d..9759216 100644 --- a/src/content/posts/2023-09-01-formal-cek-machine-in-agda/index.md +++ b/src/content/posts/2023-09-01-formal-cek-machine-in-agda/index.md @@ -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 diff --git a/src/content/posts/2023-09-15-equality.md b/src/content/posts/2023-09-15-equality.md index 0cbabb2..25b847e 100644 --- a/src/content/posts/2023-09-15-equality.md +++ b/src/content/posts/2023-09-15-equality.md @@ -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: diff --git a/src/content/posts/2023-10-10-dtt-project.md b/src/content/posts/2023-10-10-dtt-project.md index 028bfba..d7a6894 100644 --- a/src/content/posts/2023-10-10-dtt-project.md +++ b/src/content/posts/2023-10-10-dtt-project.md @@ -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 diff --git a/src/content/posts/2023-10-23-path-induction-gadt-perspective.lagda.md b/src/content/posts/2023-10-23-path-induction-gadt-perspective.lagda.md index 4147fce..c879d1c 100644 --- a/src/content/posts/2023-10-23-path-induction-gadt-perspective.lagda.md +++ b/src/content/posts/2023-10-23-path-induction-gadt-perspective.lagda.md @@ -22,7 +22,7 @@ data _≡_ {l} {A : Set l} : (a b : A) → Set l where -> [!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. diff --git a/src/content/posts/2024-05-02-ddr/index.mdx b/src/content/posts/2024-05-02-ddr/index.mdx index d716ce2..d3376f9 100644 --- a/src/content/posts/2024-05-02-ddr/index.mdx +++ b/src/content/posts/2024-05-02-ddr/index.mdx @@ -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!** \ No newline at end of file +**See you next time on the dance floor!** diff --git a/src/content/posts/2024-06-21-coping-with-refactoring/index.md b/src/content/posts/2024-06-21-coping-with-refactoring/index.md index 1a5d486..07cfc41 100644 --- a/src/content/posts/2024-06-21-coping-with-refactoring/index.md +++ b/src/content/posts/2024-06-21-coping-with-refactoring/index.md @@ -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! diff --git a/src/styles/_colors.scss b/src/styles/_colors.scss index 1def76b..eb932b8 100644 --- a/src/styles/_colors.scss +++ b/src/styles/_colors.scss @@ -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; diff --git a/src/styles/post.scss b/src/styles/post.scss index 7f75feb..bc35718 100644 --- a/src/styles/post.scss +++ b/src/styles/post.scss @@ -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); + } } \ No newline at end of file