This commit is contained in:
parent
165aa5636f
commit
8312dc6d8a
12 changed files with 486 additions and 15 deletions
2
package-lock.json
generated
2
package-lock.json
generated
|
|
@ -38,12 +38,14 @@
|
|||
"embla-carousel-react": "^8.5.2",
|
||||
"katex": "^0.17.0",
|
||||
"lucide-react": "^0.479.0",
|
||||
"mdast-util-from-markdown": "^2.0.2",
|
||||
"react": "^19.0.0",
|
||||
"react-dom": "^19.0.0",
|
||||
"react-fast-marquee": "^1.6.5",
|
||||
"react-hook-form": "^7.54.2",
|
||||
"react-icons": "^5.4.0",
|
||||
"rehype-katex": "^7.0.1",
|
||||
"remark-gfm": "^4.0.1",
|
||||
"remark-math": "^6.0.0",
|
||||
"tailwind-merge": "^3.0.2",
|
||||
"tailwindcss": "^4.0.12",
|
||||
|
|
|
|||
|
|
@ -50,12 +50,14 @@
|
|||
"embla-carousel-react": "^8.5.2",
|
||||
"katex": "^0.17.0",
|
||||
"lucide-react": "^0.479.0",
|
||||
"mdast-util-from-markdown": "^2.0.2",
|
||||
"react": "^19.0.0",
|
||||
"react-dom": "^19.0.0",
|
||||
"react-fast-marquee": "^1.6.5",
|
||||
"react-hook-form": "^7.54.2",
|
||||
"react-icons": "^5.4.0",
|
||||
"rehype-katex": "^7.0.1",
|
||||
"remark-gfm": "^4.0.1",
|
||||
"remark-math": "^6.0.0",
|
||||
"tailwind-merge": "^3.0.2",
|
||||
"tailwindcss": "^4.0.12",
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
import { defineConfig } from "astro/config";
|
||||
import mdx from "@astrojs/mdx";
|
||||
import rehypeKatex from "rehype-katex";
|
||||
import remarkGfm from "remark-gfm";
|
||||
import remarkMath from "remark-math";
|
||||
import sitemap from "@astrojs/sitemap";
|
||||
|
||||
|
|
@ -9,9 +10,17 @@ import react from "@astrojs/react";
|
|||
// @ts-ignore - TailwindCSS v4 Vite plugin has type compatibility issues with Astro
|
||||
import tailwindcss from "@tailwindcss/vite";
|
||||
import remarkCallouts from "../../src/remark-callouts.mjs";
|
||||
import remarkCodeFenceLanguages from "../../src/remark-code-fence-languages.mjs";
|
||||
import remarkInlineFootnotes from "../../src/remark-inline-footnotes.mjs";
|
||||
import { ACTIVE_BLOG_SITE } from "./src/blog-sites.js";
|
||||
|
||||
const remarkPlugins = [remarkMath, remarkCallouts];
|
||||
const remarkPlugins = [
|
||||
remarkGfm,
|
||||
remarkInlineFootnotes,
|
||||
remarkCodeFenceLanguages,
|
||||
remarkMath,
|
||||
remarkCallouts,
|
||||
];
|
||||
const rehypePlugins = [rehypeKatex];
|
||||
|
||||
// https://astro.build/config
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
import { defineConfig } from "astro/config";
|
||||
import mdx from "@astrojs/mdx";
|
||||
import rehypeKatex from "rehype-katex";
|
||||
import remarkGfm from "remark-gfm";
|
||||
import remarkMath from "remark-math";
|
||||
import sitemap from "@astrojs/sitemap";
|
||||
|
||||
|
|
@ -9,9 +10,17 @@ import react from "@astrojs/react";
|
|||
// @ts-ignore - TailwindCSS v4 Vite plugin has type compatibility issues with Astro
|
||||
import tailwindcss from "@tailwindcss/vite";
|
||||
import remarkCallouts from "../../src/remark-callouts.mjs";
|
||||
import remarkCodeFenceLanguages from "../../src/remark-code-fence-languages.mjs";
|
||||
import remarkInlineFootnotes from "../../src/remark-inline-footnotes.mjs";
|
||||
import { ACTIVE_BLOG_SITE } from "./src/blog-sites.js";
|
||||
|
||||
const remarkPlugins = [remarkMath, remarkCallouts];
|
||||
const remarkPlugins = [
|
||||
remarkGfm,
|
||||
remarkInlineFootnotes,
|
||||
remarkCodeFenceLanguages,
|
||||
remarkMath,
|
||||
remarkCallouts,
|
||||
];
|
||||
const rehypePlugins = [rehypeKatex];
|
||||
|
||||
// https://astro.build/config
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
import { defineConfig } from "astro/config";
|
||||
import mdx from "@astrojs/mdx";
|
||||
import rehypeKatex from "rehype-katex";
|
||||
import remarkGfm from "remark-gfm";
|
||||
import remarkMath from "remark-math";
|
||||
import sitemap from "@astrojs/sitemap";
|
||||
|
||||
|
|
@ -9,9 +10,17 @@ import react from "@astrojs/react";
|
|||
// @ts-ignore - TailwindCSS v4 Vite plugin has type compatibility issues with Astro
|
||||
import tailwindcss from "@tailwindcss/vite";
|
||||
import remarkCallouts from "../../src/remark-callouts.mjs";
|
||||
import remarkCodeFenceLanguages from "../../src/remark-code-fence-languages.mjs";
|
||||
import remarkInlineFootnotes from "../../src/remark-inline-footnotes.mjs";
|
||||
import { ACTIVE_BLOG_SITE } from "./src/blog-sites.js";
|
||||
|
||||
const remarkPlugins = [remarkMath, remarkCallouts];
|
||||
const remarkPlugins = [
|
||||
remarkGfm,
|
||||
remarkInlineFootnotes,
|
||||
remarkCodeFenceLanguages,
|
||||
remarkMath,
|
||||
remarkCallouts,
|
||||
];
|
||||
const rehypePlugins = [rehypeKatex];
|
||||
|
||||
// https://astro.build/config
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
import { defineConfig } from "astro/config";
|
||||
import mdx from "@astrojs/mdx";
|
||||
import rehypeKatex from "rehype-katex";
|
||||
import remarkGfm from "remark-gfm";
|
||||
import remarkMath from "remark-math";
|
||||
import sitemap from "@astrojs/sitemap";
|
||||
|
||||
|
|
@ -9,9 +10,17 @@ import react from "@astrojs/react";
|
|||
// @ts-ignore - TailwindCSS v4 Vite plugin has type compatibility issues with Astro
|
||||
import tailwindcss from "@tailwindcss/vite";
|
||||
import remarkCallouts from "../../src/remark-callouts.mjs";
|
||||
import remarkCodeFenceLanguages from "../../src/remark-code-fence-languages.mjs";
|
||||
import remarkInlineFootnotes from "../../src/remark-inline-footnotes.mjs";
|
||||
import { ACTIVE_BLOG_SITE } from "./src/blog-sites.js";
|
||||
|
||||
const remarkPlugins = [remarkMath, remarkCallouts];
|
||||
const remarkPlugins = [
|
||||
remarkGfm,
|
||||
remarkInlineFootnotes,
|
||||
remarkCodeFenceLanguages,
|
||||
remarkMath,
|
||||
remarkCallouts,
|
||||
];
|
||||
const rehypePlugins = [rehypeKatex];
|
||||
|
||||
// https://astro.build/config
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
import { defineConfig } from "astro/config";
|
||||
import mdx from "@astrojs/mdx";
|
||||
import rehypeKatex from "rehype-katex";
|
||||
import remarkGfm from "remark-gfm";
|
||||
import remarkMath from "remark-math";
|
||||
import sitemap from "@astrojs/sitemap";
|
||||
|
||||
|
|
@ -9,9 +10,17 @@ import react from "@astrojs/react";
|
|||
// @ts-ignore - TailwindCSS v4 Vite plugin has type compatibility issues with Astro
|
||||
import tailwindcss from "@tailwindcss/vite";
|
||||
import remarkCallouts from "../../src/remark-callouts.mjs";
|
||||
import remarkCodeFenceLanguages from "../../src/remark-code-fence-languages.mjs";
|
||||
import remarkInlineFootnotes from "../../src/remark-inline-footnotes.mjs";
|
||||
import { ACTIVE_BLOG_SITE } from "./src/blog-sites.js";
|
||||
|
||||
const remarkPlugins = [remarkMath, remarkCallouts];
|
||||
const remarkPlugins = [
|
||||
remarkGfm,
|
||||
remarkInlineFootnotes,
|
||||
remarkCodeFenceLanguages,
|
||||
remarkMath,
|
||||
remarkCallouts,
|
||||
];
|
||||
const rehypePlugins = [rehypeKatex];
|
||||
|
||||
// https://astro.build/config
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
import { defineConfig } from "astro/config";
|
||||
import mdx from "@astrojs/mdx";
|
||||
import rehypeKatex from "rehype-katex";
|
||||
import remarkGfm from "remark-gfm";
|
||||
import remarkMath from "remark-math";
|
||||
import sitemap from "@astrojs/sitemap";
|
||||
|
||||
|
|
@ -9,9 +10,17 @@ import react from "@astrojs/react";
|
|||
// @ts-ignore - TailwindCSS v4 Vite plugin has type compatibility issues with Astro
|
||||
import tailwindcss from "@tailwindcss/vite";
|
||||
import remarkCallouts from "../../src/remark-callouts.mjs";
|
||||
import remarkCodeFenceLanguages from "../../src/remark-code-fence-languages.mjs";
|
||||
import remarkInlineFootnotes from "../../src/remark-inline-footnotes.mjs";
|
||||
import { ACTIVE_BLOG_SITE } from "./src/blog-sites.js";
|
||||
|
||||
const remarkPlugins = [remarkMath, remarkCallouts];
|
||||
const remarkPlugins = [
|
||||
remarkGfm,
|
||||
remarkInlineFootnotes,
|
||||
remarkCodeFenceLanguages,
|
||||
remarkMath,
|
||||
remarkCallouts,
|
||||
];
|
||||
const rehypePlugins = [rehypeKatex];
|
||||
|
||||
// https://astro.build/config
|
||||
|
|
|
|||
|
|
@ -25,6 +25,13 @@ function paragraphCalloutLabel(paragraph) {
|
|||
if (paragraph?.type !== "paragraph") return null;
|
||||
|
||||
const first = paragraph.children?.[0];
|
||||
if (first?.type === "text") {
|
||||
const match = first.value.match(/^\s*\[!(aside|caution|note|tip|warning)\]\s*/i);
|
||||
if (match) {
|
||||
return CALLOUT_LABELS.get(normalizeLabel(match[1]));
|
||||
}
|
||||
}
|
||||
|
||||
if (first?.type !== "strong") return null;
|
||||
|
||||
const label = CALLOUT_LABELS.get(normalizeLabel(textFromInline(first)));
|
||||
|
|
@ -37,6 +44,12 @@ function removeLeadingLabel(paragraph, label) {
|
|||
if (paragraph?.type !== "paragraph") return;
|
||||
|
||||
const first = paragraph.children?.[0];
|
||||
if (first?.type === "text") {
|
||||
first.value = first.value.replace(/^\s*\[!(aside|caution|note|tip|warning)\]\s*/i, "");
|
||||
if (!first.value) paragraph.children.shift();
|
||||
return;
|
||||
}
|
||||
|
||||
const firstText = normalizeLabel(textFromInline(first));
|
||||
if (!first || first.type !== "strong" || firstText !== label.toLowerCase()) {
|
||||
return;
|
||||
|
|
|
|||
29
src/remark-code-fence-languages.mjs
Normal file
29
src/remark-code-fence-languages.mjs
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
const LANGUAGE_ALIASES = new Map([["ojs", "js"]]);
|
||||
|
||||
const normalizeLanguage = (language) => {
|
||||
if (!language) return language;
|
||||
|
||||
const match = language.match(/^\{(.+)\}$/);
|
||||
if (!match) return language;
|
||||
|
||||
const normalized = match[1].trim().toLowerCase();
|
||||
return LANGUAGE_ALIASES.get(normalized) ?? normalized;
|
||||
};
|
||||
|
||||
const visit = (node) => {
|
||||
if (node.type === "code") {
|
||||
node.lang = normalizeLanguage(node.lang);
|
||||
}
|
||||
|
||||
if (!Array.isArray(node.children)) return;
|
||||
|
||||
for (const child of node.children) {
|
||||
visit(child);
|
||||
}
|
||||
};
|
||||
|
||||
const remarkCodeFenceLanguages = () => (tree) => {
|
||||
visit(tree);
|
||||
};
|
||||
|
||||
export default remarkCodeFenceLanguages;
|
||||
289
src/remark-inline-footnotes.mjs
Normal file
289
src/remark-inline-footnotes.mjs
Normal file
|
|
@ -0,0 +1,289 @@
|
|||
import { fromMarkdown } from "mdast-util-from-markdown";
|
||||
|
||||
const INLINE_FOOTNOTE_PREFIX = "inline-footnote";
|
||||
|
||||
const findInlineFootnote = (value, fromIndex = 0) => {
|
||||
const start = value.indexOf("^[", fromIndex);
|
||||
|
||||
if (start === -1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let depth = 1;
|
||||
|
||||
for (let index = start + 2; index < value.length; index += 1) {
|
||||
const character = value[index];
|
||||
|
||||
if (character === "\\" && index + 1 < value.length) {
|
||||
index += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (character === "[") {
|
||||
depth += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (character === "]") {
|
||||
depth -= 1;
|
||||
|
||||
if (depth === 0) {
|
||||
return {
|
||||
start,
|
||||
end: index + 1,
|
||||
value: value.slice(start + 2, index).trim(),
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
const createFootnoteChildren = (value) => {
|
||||
const tree = fromMarkdown(value);
|
||||
|
||||
if (tree.children.length > 0) {
|
||||
return tree.children;
|
||||
}
|
||||
|
||||
return [
|
||||
{
|
||||
type: "paragraph",
|
||||
children: [
|
||||
{
|
||||
type: "text",
|
||||
value,
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
};
|
||||
|
||||
const createFootnoteParagraph = (children) => ({
|
||||
type: "paragraph",
|
||||
children:
|
||||
children.length > 0
|
||||
? children
|
||||
: [
|
||||
{
|
||||
type: "text",
|
||||
value: "",
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const createFootnoteDefinition = (identifier, label, value) => ({
|
||||
type: "footnoteDefinition",
|
||||
identifier,
|
||||
label,
|
||||
children: createFootnoteChildren(value),
|
||||
});
|
||||
|
||||
const createFootnoteDefinitionFromChildren = (identifier, label, children) => ({
|
||||
type: "footnoteDefinition",
|
||||
identifier,
|
||||
label,
|
||||
children: [createFootnoteParagraph(children)],
|
||||
});
|
||||
|
||||
const createFootnoteReference = (context) => {
|
||||
context.count += 1;
|
||||
|
||||
const label = String(context.count);
|
||||
const identifier = `${INLINE_FOOTNOTE_PREFIX}-${label}`;
|
||||
|
||||
return {
|
||||
identifier,
|
||||
label,
|
||||
node: {
|
||||
type: "footnoteReference",
|
||||
identifier,
|
||||
label,
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
const findClosingBracket = (value) => {
|
||||
for (let index = 0; index < value.length; index += 1) {
|
||||
const character = value[index];
|
||||
|
||||
if (character === "\\" && index + 1 < value.length) {
|
||||
index += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (character === "]") {
|
||||
return index;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
};
|
||||
|
||||
const cloneNode = (node) => JSON.parse(JSON.stringify(node));
|
||||
|
||||
const splitTextNode = (node, context) => {
|
||||
const replacements = [];
|
||||
let cursor = 0;
|
||||
let match = findInlineFootnote(node.value, cursor);
|
||||
|
||||
while (match) {
|
||||
if (match.start > cursor) {
|
||||
replacements.push({
|
||||
type: "text",
|
||||
value: node.value.slice(cursor, match.start),
|
||||
});
|
||||
}
|
||||
|
||||
if (match.value) {
|
||||
const reference = createFootnoteReference(context);
|
||||
replacements.push(reference.node);
|
||||
|
||||
context.definitions.push(
|
||||
createFootnoteDefinition(reference.identifier, reference.label, match.value),
|
||||
);
|
||||
} else {
|
||||
replacements.push({
|
||||
type: "text",
|
||||
value: node.value.slice(match.start, match.end),
|
||||
});
|
||||
}
|
||||
|
||||
cursor = match.end;
|
||||
match = findInlineFootnote(node.value, cursor);
|
||||
}
|
||||
|
||||
if (cursor < node.value.length) {
|
||||
replacements.push({
|
||||
type: "text",
|
||||
value: node.value.slice(cursor),
|
||||
});
|
||||
}
|
||||
|
||||
return replacements;
|
||||
};
|
||||
|
||||
const splitAcrossInlineNodes = (children, startIndex, context) => {
|
||||
const startNode = children[startIndex];
|
||||
const start = startNode.value.indexOf("^[");
|
||||
|
||||
if (start === -1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (findInlineFootnote(startNode.value, start)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const footnoteChildren = [];
|
||||
const replacements = [];
|
||||
const before = startNode.value.slice(0, start);
|
||||
const initialText = startNode.value.slice(start + 2);
|
||||
|
||||
if (before) {
|
||||
replacements.push({
|
||||
type: "text",
|
||||
value: before,
|
||||
});
|
||||
}
|
||||
|
||||
if (initialText) {
|
||||
footnoteChildren.push({
|
||||
type: "text",
|
||||
value: initialText,
|
||||
});
|
||||
}
|
||||
|
||||
for (let index = startIndex + 1; index < children.length; index += 1) {
|
||||
const child = children[index];
|
||||
|
||||
if (child.type === "text") {
|
||||
const closingIndex = findClosingBracket(child.value);
|
||||
|
||||
if (closingIndex !== -1) {
|
||||
const footnoteText = child.value.slice(0, closingIndex);
|
||||
const after = child.value.slice(closingIndex + 1);
|
||||
|
||||
if (footnoteText) {
|
||||
footnoteChildren.push({
|
||||
type: "text",
|
||||
value: footnoteText,
|
||||
});
|
||||
}
|
||||
|
||||
const reference = createFootnoteReference(context);
|
||||
replacements.push(reference.node);
|
||||
|
||||
if (after) {
|
||||
replacements.push({
|
||||
type: "text",
|
||||
value: after,
|
||||
});
|
||||
}
|
||||
|
||||
context.definitions.push(
|
||||
createFootnoteDefinitionFromChildren(
|
||||
reference.identifier,
|
||||
reference.label,
|
||||
footnoteChildren,
|
||||
),
|
||||
);
|
||||
|
||||
return {
|
||||
consumed: index - startIndex + 1,
|
||||
replacements,
|
||||
};
|
||||
}
|
||||
|
||||
footnoteChildren.push(cloneNode(child));
|
||||
continue;
|
||||
}
|
||||
|
||||
footnoteChildren.push(cloneNode(child));
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
const visitChildren = (node, context) => {
|
||||
if (!Array.isArray(node.children)) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (let index = 0; index < node.children.length; index += 1) {
|
||||
const child = node.children[index];
|
||||
|
||||
if (child.type === "text" && child.value.includes("^[")) {
|
||||
const acrossNodes = splitAcrossInlineNodes(node.children, index, context);
|
||||
|
||||
if (acrossNodes) {
|
||||
node.children.splice(index, acrossNodes.consumed, ...acrossNodes.replacements);
|
||||
index += acrossNodes.replacements.length - 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
const replacements = splitTextNode(child, context);
|
||||
node.children.splice(index, 1, ...replacements);
|
||||
index += replacements.length - 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
visitChildren(child, context);
|
||||
}
|
||||
};
|
||||
|
||||
const remarkInlineFootnotes = () => (tree) => {
|
||||
const context = {
|
||||
count: 0,
|
||||
definitions: [],
|
||||
};
|
||||
|
||||
visitChildren(tree, context);
|
||||
|
||||
if (context.definitions.length > 0) {
|
||||
tree.children.push(...context.definitions);
|
||||
}
|
||||
};
|
||||
|
||||
export default remarkInlineFootnotes;
|
||||
|
|
@ -1,12 +1,13 @@
|
|||
.blog-post-shell {
|
||||
width: min(100% - 2rem, 94rem);
|
||||
margin-inline: auto;
|
||||
max-width: 78rem;
|
||||
padding: 3rem 1.75rem 4.5rem;
|
||||
}
|
||||
|
||||
.blog-article {
|
||||
width: 100%;
|
||||
margin-inline: auto;
|
||||
max-width: 68rem;
|
||||
max-width: 82rem;
|
||||
}
|
||||
|
||||
.blog-post-header {
|
||||
|
|
@ -96,6 +97,12 @@
|
|||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.article-content :where(hr) {
|
||||
margin-block: 2rem;
|
||||
border: 0;
|
||||
border-top: 1px solid hsl(var(--border));
|
||||
}
|
||||
|
||||
.article-content :where(ul, ol) {
|
||||
padding-left: 1.35rem;
|
||||
}
|
||||
|
|
@ -159,19 +166,29 @@
|
|||
}
|
||||
|
||||
.article-content :where(.callout) {
|
||||
margin-block: 1.5rem;
|
||||
margin-block: 1.6rem;
|
||||
border: 1px solid hsl(var(--border));
|
||||
border-left: 4px solid hsl(var(--primary));
|
||||
border-radius: 0.7rem;
|
||||
background: color-mix(in srgb, hsl(var(--accent)) 54%, transparent);
|
||||
padding: 1rem 1.15rem;
|
||||
border-left: 3px solid hsl(var(--primary));
|
||||
border-radius: 0.55rem;
|
||||
background: color-mix(in srgb, hsl(var(--accent)) 34%, transparent);
|
||||
padding: 1.05rem 1.25rem;
|
||||
color: hsl(var(--foreground));
|
||||
font-size: 0.98em;
|
||||
line-height: 1.68;
|
||||
}
|
||||
|
||||
.article-content :where(.callout > *:first-child) {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.article-content :where(.callout > *:last-child) {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.article-content :where(.callout > * + *) {
|
||||
margin-top: 0.8rem;
|
||||
}
|
||||
|
||||
.article-content :where(.callout h1) {
|
||||
font-size: 1.35rem;
|
||||
}
|
||||
|
|
@ -184,12 +201,28 @@
|
|||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
.article-content :where(.callout h1, .callout h2, .callout h3, .callout h4) {
|
||||
margin-bottom: 0.35rem;
|
||||
}
|
||||
|
||||
.article-content :where(.callout hr) {
|
||||
margin-block: 1rem;
|
||||
border-top-color: color-mix(in srgb, hsl(var(--border)) 70%, transparent);
|
||||
}
|
||||
|
||||
.article-content :where(.callout img) {
|
||||
max-width: min(100%, 34rem);
|
||||
}
|
||||
|
||||
.article-content :where(aside:not(.callout)) {
|
||||
margin-block: 1.5rem;
|
||||
border: 1px solid hsl(var(--border));
|
||||
border-radius: 0.7rem;
|
||||
background: hsl(var(--muted));
|
||||
border-left: 3px solid hsl(var(--primary));
|
||||
border-radius: 0.55rem;
|
||||
background: color-mix(in srgb, hsl(var(--accent)) 28%, transparent);
|
||||
padding: 1rem 1.15rem;
|
||||
font-size: 0.98em;
|
||||
line-height: 1.68;
|
||||
}
|
||||
|
||||
.article-content :where(img) {
|
||||
|
|
@ -247,6 +280,55 @@
|
|||
padding: 0.25rem 0;
|
||||
}
|
||||
|
||||
.article-content :where(sup) {
|
||||
line-height: 0;
|
||||
}
|
||||
|
||||
.article-content :where(a[data-footnote-ref]) {
|
||||
border-radius: 999px;
|
||||
padding-inline: 0.16rem;
|
||||
font-family: var(--font-mono);
|
||||
font-size: 0.72em;
|
||||
font-weight: 600;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.article-content :where([data-footnotes]) {
|
||||
margin-top: 3rem;
|
||||
border-top: 1px solid hsl(var(--border));
|
||||
padding-top: 1.15rem;
|
||||
color: hsl(var(--muted-foreground));
|
||||
font-size: 0.92rem;
|
||||
line-height: 1.62;
|
||||
}
|
||||
|
||||
.article-content :where([data-footnotes] h2) {
|
||||
margin: 0 0 0.8rem;
|
||||
color: hsl(var(--muted-foreground));
|
||||
font-family: var(--font-mono);
|
||||
font-size: 0.72rem;
|
||||
font-weight: 600;
|
||||
letter-spacing: 0.08em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.article-content :where([data-footnotes] ol) {
|
||||
padding-left: 1.25rem;
|
||||
}
|
||||
|
||||
.article-content :where([data-footnotes] li + li) {
|
||||
margin-top: 0.55rem;
|
||||
}
|
||||
|
||||
.article-content :where([data-footnotes] p) {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.article-content :where(a[data-footnote-backref]) {
|
||||
margin-left: 0.25rem;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.blog-post-shell {
|
||||
padding-top: 4rem;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue