docs-site: implement tabs
This commit is contained in:
@@ -3,6 +3,9 @@
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<script>
|
||||
document.documentElement.classList.add("js");
|
||||
</script>
|
||||
%sveltekit.head%
|
||||
</head>
|
||||
<body data-sveltekit-preload-data="hover">
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
@import url("./shiki.css");
|
||||
@import url("./admonition.css");
|
||||
@import url("./tabs.css");
|
||||
|
||||
code {
|
||||
font-family:
|
||||
|
||||
50
pkgs/docs-site/src/lib/markdown/tabs.css
Normal file
50
pkgs/docs-site/src/lib/markdown/tabs.css
Normal file
@@ -0,0 +1,50 @@
|
||||
.md-tabs-bar {
|
||||
display: none;
|
||||
gap: 7px;
|
||||
align-items: flex-end;
|
||||
}
|
||||
.md-tabs-tab {
|
||||
padding: 8px 0;
|
||||
}
|
||||
.md-tabs-container {
|
||||
margin: 20px 0;
|
||||
}
|
||||
.js {
|
||||
.md-tabs-bar {
|
||||
display: flex;
|
||||
}
|
||||
.md-tabs-container {
|
||||
margin: 0;
|
||||
> .md-tabs-tab {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
.md-tabs {
|
||||
margin: 20px 0;
|
||||
}
|
||||
.md-tabs-tab {
|
||||
background: #d7dadf;
|
||||
padding: 8px 18px;
|
||||
border-top-left-radius: 8px;
|
||||
border-top-right-radius: 8px;
|
||||
cursor: pointer;
|
||||
&.is-active {
|
||||
background: #eff1f5;
|
||||
|
||||
.md-tabs.is-singleton & {
|
||||
padding: 8px 16px;
|
||||
border-top-left-radius: 5px;
|
||||
border-top-right-radius: 5px;
|
||||
flex: 1;
|
||||
border-bottom: 1px solid #d8dbe1;
|
||||
}
|
||||
}
|
||||
}
|
||||
.md-tabs-content {
|
||||
display: none;
|
||||
margin: 0 var(--pageMargin);
|
||||
&.is-active {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -17,6 +17,7 @@ import rehypeTocSlug from "./rehype-toc-slug";
|
||||
import transformerLineNumbers from "./shiki-transformer-line-numbers";
|
||||
import remarkParse from "./remark-parse";
|
||||
import remarkAdmonition from "./remark-admonition";
|
||||
import remarkTabs from "./remark-tabs";
|
||||
import rehypeWrapHeadings from "./rehype-wrap-headings";
|
||||
import remarkLinkMigration from "./link-migration";
|
||||
|
||||
@@ -44,6 +45,7 @@ export default function ({
|
||||
.use(remarkGfm)
|
||||
.use(remarkDirective)
|
||||
.use(remarkAdmonition)
|
||||
.use(remarkTabs)
|
||||
.use(remarkRehype)
|
||||
.use(rehypeTocSlug, {
|
||||
tocMaxDepth,
|
||||
|
||||
93
pkgs/docs-site/src/lib/markdown/vite/remark-tabs.ts
Normal file
93
pkgs/docs-site/src/lib/markdown/vite/remark-tabs.ts
Normal file
@@ -0,0 +1,93 @@
|
||||
import { visit } from "unist-util-visit";
|
||||
import type { Paragraph, Root, Text } from "mdast";
|
||||
|
||||
export default function remarkTabs() {
|
||||
return (tree: Root) => {
|
||||
visit(tree, (node) => {
|
||||
if (node.type != "containerDirective" || node.name != "tabs") {
|
||||
return;
|
||||
}
|
||||
|
||||
const data = (node.data ||= {});
|
||||
data.hName = "div";
|
||||
data.hProperties = {
|
||||
className: "md-tabs",
|
||||
};
|
||||
let tabIndex = 0;
|
||||
let tabTitles: string[] = [];
|
||||
for (const [i, child] of node.children.entries()) {
|
||||
if (child.type != "containerDirective" || child.name != "tab") {
|
||||
continue;
|
||||
}
|
||||
let tabTitle: string;
|
||||
if (child.children?.[0].data?.directiveLabel) {
|
||||
const p = child.children.shift() as Paragraph;
|
||||
tabTitle = (p.children[0] as Text).value;
|
||||
} else {
|
||||
tabTitle = "(empty)";
|
||||
}
|
||||
tabTitles.push(tabTitle);
|
||||
node.children[i] = {
|
||||
type: "containerDirective",
|
||||
name: "",
|
||||
data: {
|
||||
hName: "div",
|
||||
hProperties: {
|
||||
className: "md-tabs-container",
|
||||
},
|
||||
},
|
||||
children: [
|
||||
{
|
||||
type: "paragraph",
|
||||
data: {
|
||||
hName: "div",
|
||||
hProperties: {
|
||||
className: `md-tabs-tab ${tabIndex == 0 ? "is-active" : ""}`,
|
||||
},
|
||||
},
|
||||
children: [{ type: "text", value: tabTitle }],
|
||||
},
|
||||
{
|
||||
type: "containerDirective",
|
||||
name: "",
|
||||
data: {
|
||||
hName: "div",
|
||||
hProperties: {
|
||||
className: `md-tabs-content ${tabIndex == 0 ? "is-active" : ""}`,
|
||||
},
|
||||
},
|
||||
children: child.children,
|
||||
},
|
||||
],
|
||||
};
|
||||
tabIndex++;
|
||||
}
|
||||
if (tabTitles.length === 1) {
|
||||
data.hProperties.className += " is-singleton";
|
||||
}
|
||||
// Add tab bar for when js is enabled
|
||||
node.children = [
|
||||
{
|
||||
type: "paragraph",
|
||||
data: {
|
||||
hName: "div",
|
||||
hProperties: {
|
||||
className: "md-tabs-bar",
|
||||
},
|
||||
},
|
||||
children: tabTitles.map((tabTitle, tabIndex) => ({
|
||||
type: "text",
|
||||
data: {
|
||||
hName: "div",
|
||||
hProperties: {
|
||||
className: `md-tabs-tab ${tabIndex == 0 ? "is-active" : ""}`,
|
||||
},
|
||||
},
|
||||
value: tabTitle,
|
||||
})),
|
||||
},
|
||||
...node.children,
|
||||
];
|
||||
});
|
||||
};
|
||||
}
|
||||
@@ -111,7 +111,7 @@
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 0 var(--pagePadding);
|
||||
padding: 0 var(--pageMargin);
|
||||
color: var(--fgInvertedColor);
|
||||
background: var(--bgInvertedColor);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<script lang="ts">
|
||||
import "$lib/markdown/main.css";
|
||||
import { visit, type Heading as ArticleHeading } from "$lib/docs";
|
||||
import { onMount } from "svelte";
|
||||
const { data } = $props();
|
||||
|
||||
type Heading = ArticleHeading & {
|
||||
@@ -39,6 +40,36 @@
|
||||
}
|
||||
});
|
||||
|
||||
onMount(() => {
|
||||
const onClick = (ev: MouseEvent) => {
|
||||
const targetTabEl = (ev.target as HTMLElement).closest(".md-tabs-tab");
|
||||
if (!targetTabEl || targetTabEl.classList.contains(".is-active")) {
|
||||
return;
|
||||
}
|
||||
const tabsEl = targetTabEl.closest(".md-tabs")!;
|
||||
const tabEls = tabsEl.querySelectorAll(".md-tabs-tab")!;
|
||||
const tabIndex = Array.from(tabEls).indexOf(targetTabEl);
|
||||
if (tabIndex == -1) {
|
||||
return;
|
||||
}
|
||||
const tabContentEls = tabsEl.querySelectorAll(".md-tabs-content");
|
||||
const tabContentEl = tabContentEls[tabIndex];
|
||||
if (!tabContentEl) {
|
||||
return;
|
||||
}
|
||||
tabEls.forEach((tabEl) => tabEl.classList.remove("is-active"));
|
||||
targetTabEl.classList.add("is-active");
|
||||
tabContentEls.forEach((tabContentEl) =>
|
||||
tabContentEl.classList.remove("is-active"),
|
||||
);
|
||||
tabContentEl.classList.add("is-active");
|
||||
};
|
||||
document.addEventListener("click", onClick);
|
||||
return () => {
|
||||
document.removeEventListener("click", onClick);
|
||||
};
|
||||
});
|
||||
|
||||
function normalizeHeadings(headings: ArticleHeading[]): Heading[] {
|
||||
return headings.map((heading) => ({
|
||||
...heading,
|
||||
@@ -232,7 +263,7 @@
|
||||
|
||||
:global {
|
||||
& :is(h1, h2, h3, h4, h5, h6) {
|
||||
margin-left: calc(-1 * var(--pagePadding));
|
||||
margin-left: calc(-1 * var(--pageMargin));
|
||||
display: flex;
|
||||
align-items: center;
|
||||
&.is-scrolledPast {
|
||||
|
||||
@@ -10,7 +10,9 @@ See the complete [list](../guides/inventory/autoincludes.md) of auto-loaded file
|
||||
|
||||
## Create a machine
|
||||
|
||||
=== "clan.nix (declarative)"
|
||||
::::tabs
|
||||
|
||||
:::tab[clan.nix (declarative)]
|
||||
|
||||
```nix {3-4}
|
||||
{
|
||||
@@ -28,7 +30,9 @@ See the complete [list](../guides/inventory/autoincludes.md) of auto-loaded file
|
||||
}
|
||||
```
|
||||
|
||||
=== "CLI (imperative)"
|
||||
:::
|
||||
|
||||
:::tab[CLI (imperative)]
|
||||
|
||||
```sh
|
||||
clan machines create jon
|
||||
@@ -36,6 +40,23 @@ clan machines create jon
|
||||
|
||||
The imperative command might create a machine folder in `machines/jon`
|
||||
And might persist information in `inventory.json`
|
||||
:::
|
||||
::::
|
||||
|
||||
::::tabs
|
||||
|
||||
:::tab[file name test]
|
||||
|
||||
```nix
|
||||
{
|
||||
inventory.machines = {
|
||||
# Define a machine
|
||||
jon = { };
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
::::
|
||||
|
||||
### Configuring a machine
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
@import "@fontsource-variable/geist";
|
||||
|
||||
:root {
|
||||
--pagePadding: 15px;
|
||||
--pageMargin: 15px;
|
||||
--globalBarHeight: 60px;
|
||||
--fgColor: #000;
|
||||
--fgInvertedColor: #fff;
|
||||
|
||||
Reference in New Issue
Block a user