site: admonitions custom title with icons
This commit is contained in:
@@ -105,7 +105,7 @@ def render_option(
|
||||
read_only = option.get("readOnly")
|
||||
|
||||
res = f"""
|
||||
{"#" * level} {sanitize(name) if short_head is None else sanitize(short_head)} {"{: #" + sanitize_anchor(name) + "}" if level > 1 else ""}
|
||||
{"#" * level} {sanitize(name) if short_head is None else sanitize(short_head)}
|
||||
|
||||
"""
|
||||
|
||||
|
||||
5
site/.gitignore
vendored
5
site/.gitignore
vendored
@@ -21,4 +21,7 @@ vite.config.ts.timestamp-*
|
||||
|
||||
# Generated docs
|
||||
src/routes/docs/reference/options
|
||||
src/routes/docs/reference/clan.core
|
||||
src/routes/docs/reference/clan.core
|
||||
|
||||
# Icons and other assets
|
||||
static/icons
|
||||
@@ -21,5 +21,9 @@ buildNpmPackage {
|
||||
cp -r ${module-docs}/reference/* src/routes/docs/reference
|
||||
|
||||
chmod +w -R src/routes/docs/reference
|
||||
|
||||
mkdir -p static/icons
|
||||
cp -af ${../pkgs/clan-app/ui/icons}/* ./static/icons
|
||||
chmod +w -R static/icons
|
||||
'';
|
||||
}
|
||||
|
||||
883
site/package-lock.json
generated
883
site/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -20,6 +20,7 @@
|
||||
"@sveltejs/adapter-static": "^3.0.10",
|
||||
"@sveltejs/kit": "^2.43.2",
|
||||
"@sveltejs/vite-plugin-svelte": "^6.2.0",
|
||||
"hastscript": "^9.0.1",
|
||||
"mdast": "^2.3.2",
|
||||
"mdast-util-toc": "^7.1.0",
|
||||
"mdsvex": "^0.12.6",
|
||||
@@ -29,7 +30,9 @@
|
||||
"rehype-slug": "^6.0.0",
|
||||
"rehype-stringify": "^10.0.1",
|
||||
"remark": "^15.0.1",
|
||||
"remark-directive": "^4.0.0",
|
||||
"remark-frontmatter": "^5.0.0",
|
||||
"remark-gfm": "^4.0.1",
|
||||
"remark-parse": "^11.0.0",
|
||||
"remark-rehype": "^11.1.2",
|
||||
"remark-stringify": "^11.0.0",
|
||||
@@ -39,6 +42,7 @@
|
||||
"to-vfile": "^8.0.0",
|
||||
"typescript": "^5.9.2",
|
||||
"unified": "^11.0.5",
|
||||
"unist-util-visit": "^5.0.0",
|
||||
"vfile": "^6.0.3",
|
||||
"vfile-matter": "^5.0.1",
|
||||
"vite": "^7.1.7"
|
||||
|
||||
@@ -46,4 +46,90 @@ inventory.instances = {
|
||||
|
||||
## Step Foo
|
||||
|
||||
Miscellaneous Symbols
|
||||
☀ ☁ ☂ ☃ ☄ ★ ☆ ☇ ☈ ☉ ☊ ☋ ☌ ☍ ☎ ☏ ☐ ☑ ☒ ☓ ☚ ☛ ☜ ☝ ☞ ☟ ☠ ☡ ☢ ☣ ☤ ☥ ☦ ☧ ☨ ☩ ☪ ☫ ☬ ☭ ☮ ☯ ☰ ☱ ☲ ☳ ☴ ☵ ☶ ☷ ☸ ☹ ☺ ☻ ☼ ☽ ☾ ☿ ♀ ♁ ♂ ♃ ♄ ♅ ♆ ♇ ♈ ♉ ♊ ♋ ♌ ♍ ♎ ♏ ♐ ♑ ♒ ♓ ♔ ♕ ♖ ♗ ♘ ♙ ♚ ♛ ♜ ♝ ♞ ♟ ♠ ♡ ♢ ♣ ♤ ♥ ♦ ♧ ♨ ♩ ♪ ♫ ♬ ♭ ♮ ♯
|
||||
|
||||
## Step Bar
|
||||
|
||||
↑
|
||||
Duplicate heading, should still be linked
|
||||
|
||||
This is a divider
|
||||
|
||||
---
|
||||
|
||||
---
|
||||
|
||||
:::note[Note about nature]
|
||||
|
||||
Respect the nature of things
|
||||
|
||||
:::
|
||||
|
||||
::::important[Its important]
|
||||
|
||||
Follow this and your life will be happy
|
||||
|
||||
:::note
|
||||
nested note probably a bad idea
|
||||
|
||||
but technically valid
|
||||
:::
|
||||
|
||||
::::
|
||||
|
||||
:::danger[Attention Footgun]
|
||||
|
||||
Please don't erase your disk
|
||||
|
||||
```nix
|
||||
erase = false;
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
:::tip[Outsmart]
|
||||
|
||||
Lets be really clever
|
||||
|
||||
- List
|
||||
- Inside
|
||||
|
||||
:::
|
||||
|
||||
This is a table
|
||||
|
||||
| A/B | A | ¬A |
|
||||
| - | - | - |
|
||||
| B | AB | B |
|
||||
| ¬B | A | 0 |
|
||||
|
||||
## GFM
|
||||
|
||||
### Autolink literals
|
||||
|
||||
www.example.com, https://example.com, and contact@example.com.
|
||||
|
||||
### Footnote
|
||||
|
||||
A note[^1]
|
||||
|
||||
[^1]: Big note.
|
||||
|
||||
### Strikethrough
|
||||
|
||||
~one~ or ~~two~~ tildes.
|
||||
|
||||
### Table
|
||||
|
||||
| a | b | c | d |
|
||||
| - | :- | -: | :-: |
|
||||
| 1 | 2 | 3 | 4 |
|
||||
|
||||
### Tasklist
|
||||
|
||||
* [ ] to do
|
||||
* [x] done
|
||||
|
||||
- item
|
||||
- normal
|
||||
@@ -3,3 +3,105 @@
|
||||
body {
|
||||
font-family: "Geist Variable";
|
||||
}
|
||||
|
||||
|
||||
.admonition {
|
||||
border-left: 4px solid;
|
||||
padding: 1rem;
|
||||
margin: 1rem 0;
|
||||
.admonition-title {
|
||||
text-transform: capitalize;
|
||||
font-weight: 600;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: start;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
.admonition-icon {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 1.25rem;
|
||||
height: 1.25rem;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.admonition-icon::before {
|
||||
content: "";
|
||||
display: block;
|
||||
width: 1rem;
|
||||
height: 1rem;
|
||||
background-color: currentColor;
|
||||
}
|
||||
}
|
||||
|
||||
/* TODO: Adjust styling */
|
||||
.admonition.note {
|
||||
border-left-color:#3b82f6;
|
||||
background-color: #eff6ff;
|
||||
.admonition-title {
|
||||
color: #1e40af;
|
||||
}
|
||||
.admonition-icon::before {
|
||||
mask: url("/icons/info.svg") no-repeat center;
|
||||
mask-size: contain;
|
||||
}
|
||||
}
|
||||
|
||||
.admonition.important {
|
||||
border-left-color: #facc15;
|
||||
background-color: #fffbeb;
|
||||
.admonition-title {
|
||||
color: #b45309;
|
||||
}
|
||||
.admonition-icon::before {
|
||||
mask: url("/icons/attention.svg") no-repeat center;
|
||||
mask-size: contain;
|
||||
}
|
||||
}
|
||||
|
||||
.admonition.danger {
|
||||
border-left-color: #ef4444;
|
||||
background-color: #fef2f2;
|
||||
|
||||
.admonition-title {
|
||||
color: #b91c1c;
|
||||
}
|
||||
.admonition-icon::before {
|
||||
mask: url("/icons/warning-filled.svg") no-repeat center;
|
||||
mask-size: contain;
|
||||
}
|
||||
}
|
||||
|
||||
.admonition.tip {
|
||||
border-left-color: #10b981;
|
||||
background-color: #ecfdf5;
|
||||
|
||||
.admonition-title {
|
||||
color: #065f46;
|
||||
}
|
||||
.admonition-icon::before {
|
||||
mask: url("/icons/heart.svg") no-repeat center;
|
||||
mask-size: contain;
|
||||
}
|
||||
}
|
||||
|
||||
ul {
|
||||
list-style: none;
|
||||
padding-left: 1rem;
|
||||
}
|
||||
|
||||
ul li {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
margin-top: 0.35em;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
/* TODO: Checklist */
|
||||
ul li::before {
|
||||
content: "-";
|
||||
display: block;
|
||||
width: 1rem;
|
||||
height: 1rem;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
@@ -12,6 +12,10 @@ const config = {
|
||||
// If your environment is not supported, or you settled on a specific environment, switch out the adapter.
|
||||
// See https://svelte.dev/docs/kit/adapters for more information about adapters.
|
||||
adapter: adapter(),
|
||||
prerender: {
|
||||
handleHttpError: "warn",
|
||||
handleMissingId: "warn",
|
||||
},
|
||||
},
|
||||
extensions: [".svelte"],
|
||||
};
|
||||
|
||||
@@ -8,6 +8,8 @@ import remarkRehype from "remark-rehype";
|
||||
import rehypeStringify from "rehype-stringify";
|
||||
import rehypeShiki from "@shikijs/rehype";
|
||||
import rehypeSlug from "rehype-slug";
|
||||
import remarkGfm from "remark-gfm";
|
||||
import remarkDirective from "remark-directive";
|
||||
import rehypeAutolinkHeadings from "rehype-autolink-headings";
|
||||
import { toc } from "mdast-util-toc";
|
||||
import type { Nodes } from "mdast";
|
||||
@@ -17,6 +19,90 @@ import {
|
||||
transformerRenderIndentGuides,
|
||||
transformerMetaHighlight,
|
||||
} from "@shikijs/transformers";
|
||||
import { visit } from "unist-util-visit";
|
||||
import { h } from "hastscript";
|
||||
|
||||
// Needed according to:
|
||||
// https://github.com/remarkjs/remark-directive
|
||||
export function styleDirectives() {
|
||||
/**
|
||||
* @param {Root} tree
|
||||
* Tree.
|
||||
* @returns {undefined}
|
||||
* Nothing.
|
||||
*/
|
||||
return (tree: Nodes) => {
|
||||
visit(tree, (node) => {
|
||||
if (
|
||||
node.type === "textDirective" ||
|
||||
node.type === "leafDirective" ||
|
||||
node.type === "containerDirective"
|
||||
) {
|
||||
const data = (node.data ||= {});
|
||||
const hast = h(node.name, node.attributes);
|
||||
|
||||
// Detect whether first child is a label paragraph
|
||||
const hasCustomTitle =
|
||||
node.children?.[0]?.data?.directiveLabel === true;
|
||||
|
||||
// For custom title: use the existing paragraph node (will be converted to HAST)
|
||||
// For fallback: create a new paragraph with text
|
||||
const titleNode = hasCustomTitle
|
||||
? node.children[0]
|
||||
: {
|
||||
type: "paragraph" as const,
|
||||
children: [
|
||||
{
|
||||
type: "text" as const,
|
||||
value: node.name,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
// Remove label paragraph from children if it exists
|
||||
const contentChildren = hasCustomTitle
|
||||
? node.children.slice(1)
|
||||
: node.children;
|
||||
|
||||
data.hName = "div";
|
||||
data.hProperties = {
|
||||
className: `admonition ${hast.tagName}`,
|
||||
};
|
||||
|
||||
// Synthetic icon node
|
||||
const iconNode = {
|
||||
type: "text" as const,
|
||||
value: "",
|
||||
data: {
|
||||
hName: "span",
|
||||
hProperties: {
|
||||
className: ["admonition-icon"],
|
||||
"data-icon": hast.tagName,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
// Create new children array with title wrapped in div
|
||||
// The remark-rehype plugin will convert these MDAST nodes to HAST
|
||||
node.children = [
|
||||
// Title node
|
||||
{
|
||||
type: "paragraph" as const,
|
||||
data: {
|
||||
hName: "div",
|
||||
hProperties: { className: ["admonition-title"] },
|
||||
},
|
||||
children:
|
||||
titleNode.type === "paragraph"
|
||||
? [iconNode, ...titleNode.children]
|
||||
: [iconNode, titleNode],
|
||||
},
|
||||
...contentChildren,
|
||||
];
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [
|
||||
@@ -31,6 +117,9 @@ export default defineConfig({
|
||||
matter(file, { strip: true });
|
||||
const html = await unified()
|
||||
.use(remarkParse)
|
||||
.use(remarkGfm)
|
||||
.use(remarkDirective)
|
||||
.use(styleDirectives)
|
||||
.use(remarkRehype)
|
||||
.use(rehypeShiki, {
|
||||
themes: {
|
||||
|
||||
Reference in New Issue
Block a user