feat: Implement sidebar for api docs
This commit is contained in:
parent
53d6ee686d
commit
eee2f60c61
@ -51,7 +51,7 @@
|
|||||||
--c-primary: rgb(255, 180, 180);
|
--c-primary: rgb(255, 180, 180);
|
||||||
--c-pink: #374259;
|
--c-pink: #374259;
|
||||||
--c-link: #0284c7;
|
--c-link: #0284c7;
|
||||||
--c-border-1: #9090r0;
|
--c-border-1: #909090;
|
||||||
|
|
||||||
--c-nav-bg: rgb(255, 247, 255, 0.5);
|
--c-nav-bg: rgb(255, 247, 255, 0.5);
|
||||||
--c-secondary: rgba(255, 255, 240, 0.5);
|
--c-secondary: rgba(255, 255, 240, 0.5);
|
||||||
|
43
src/components/ApiLayout/Sidebar.astro
Normal file
43
src/components/ApiLayout/Sidebar.astro
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
---
|
||||||
|
import type { Hierarchy, Post } from "../../layouts/ApiLayout.astro";
|
||||||
|
|
||||||
|
const hierarchy: Hierarchy = Astro.props.hierarchy;
|
||||||
|
|
||||||
|
function splitAndLast(s: string): string {
|
||||||
|
const segments = s.split("/");
|
||||||
|
return segments[segments.length - 1]!;
|
||||||
|
}
|
||||||
|
|
||||||
|
function postComparison(a: Post, b: Post): number {
|
||||||
|
const s1 = splitAndLast(a.url);
|
||||||
|
const s2 = splitAndLast(b.url);
|
||||||
|
|
||||||
|
return s1 > s2 ? 0 : 1;
|
||||||
|
}
|
||||||
|
---
|
||||||
|
|
||||||
|
{
|
||||||
|
Object.entries(hierarchy.children).map(([folderName, children]) => (
|
||||||
|
<>
|
||||||
|
<div class="mt-6 px-2 py-1 uppercase font-display text-c-text-2 font-medium">
|
||||||
|
{folderName}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="pl-2 my-1">
|
||||||
|
<ul class="border-l border-c-border-1">
|
||||||
|
<Astro.self hierarchy={children} />
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
))
|
||||||
|
}
|
||||||
|
{
|
||||||
|
hierarchy.posts.sort(postComparison).map((p) => (
|
||||||
|
<a
|
||||||
|
class="inline-block rounded-2xl w-full hover:bg-neutral-200 dark:hover:bg-neutral-800 transition-colors px-3 py-2"
|
||||||
|
href={p.url}
|
||||||
|
>
|
||||||
|
{splitAndLast(p.url)}
|
||||||
|
</a>
|
||||||
|
))
|
||||||
|
}
|
@ -2,8 +2,78 @@
|
|||||||
import Navbar from "../components/Navbar.astro";
|
import Navbar from "../components/Navbar.astro";
|
||||||
import BaseLayout from "./BaseLayout.astro";
|
import BaseLayout from "./BaseLayout.astro";
|
||||||
import TOC from "../components/TOC.astro";
|
import TOC from "../components/TOC.astro";
|
||||||
|
import Sidebar from "../components/ApiLayout/Sidebar.astro";
|
||||||
|
|
||||||
const { headings } = Astro.props;
|
const { headings } = Astro.props;
|
||||||
|
|
||||||
|
export type Post = {
|
||||||
|
frontmatter: any;
|
||||||
|
getHeadings: any;
|
||||||
|
url: string;
|
||||||
|
file: any;
|
||||||
|
Content: any;
|
||||||
|
default: any;
|
||||||
|
};
|
||||||
|
type Posts = Array<Readonly<Post>>;
|
||||||
|
|
||||||
|
const basePath = "/api/std";
|
||||||
|
const posts: Posts = await Astro.glob("../pages/api/std/**/*.{md,mdx}");
|
||||||
|
|
||||||
|
export type Hierarchy = {
|
||||||
|
posts: Array<Post>;
|
||||||
|
children: Record<string, Hierarchy>;
|
||||||
|
};
|
||||||
|
|
||||||
|
function createHierarchy(posts: Posts): Hierarchy {
|
||||||
|
const hierarchy: Hierarchy = {
|
||||||
|
posts: [],
|
||||||
|
children: {},
|
||||||
|
};
|
||||||
|
|
||||||
|
for (const post of posts) {
|
||||||
|
const postUrl: string = post.url;
|
||||||
|
const urlAfterBase = postUrl.split(basePath)[1] ?? "";
|
||||||
|
|
||||||
|
// handle / (index)
|
||||||
|
if (urlAfterBase === "") {
|
||||||
|
hierarchy.posts.push(post);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const urlSegments = urlAfterBase.split("/").slice(1);
|
||||||
|
|
||||||
|
// top level urls
|
||||||
|
if (urlSegments.length === 1) {
|
||||||
|
hierarchy.posts.push(post);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// folders
|
||||||
|
const folders = urlSegments.slice(0, -1);
|
||||||
|
|
||||||
|
// traverse the hierarchy until the neccesary hierarchy is found
|
||||||
|
let currentHierarchy = hierarchy;
|
||||||
|
for (const folderName of folders) {
|
||||||
|
// check if folder exists, create otherwise
|
||||||
|
if (!hierarchy.children[folderName]) {
|
||||||
|
// create if doesnt exist
|
||||||
|
hierarchy.children[folderName] = {
|
||||||
|
posts: [],
|
||||||
|
children: {},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
currentHierarchy = hierarchy.children[folderName];
|
||||||
|
}
|
||||||
|
|
||||||
|
// add the page
|
||||||
|
currentHierarchy.posts.push(post);
|
||||||
|
}
|
||||||
|
|
||||||
|
return hierarchy;
|
||||||
|
}
|
||||||
|
|
||||||
|
const hierarchy = createHierarchy(posts);
|
||||||
---
|
---
|
||||||
|
|
||||||
<BaseLayout>
|
<BaseLayout>
|
||||||
@ -16,7 +86,7 @@ const { headings } = Astro.props;
|
|||||||
border-c-border-1 -translate-x-64 lg:translate-x-0 transition-transform"
|
border-c-border-1 -translate-x-64 lg:translate-x-0 transition-transform"
|
||||||
>
|
>
|
||||||
<nav class="py-4 pr-2 overflow-x-scroll h-[calc(100vh-3rem)]">
|
<nav class="py-4 pr-2 overflow-x-scroll h-[calc(100vh-3rem)]">
|
||||||
<a href="/">Home page</a>
|
<Sidebar hierarchy={hierarchy} />
|
||||||
</nav>
|
</nav>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -39,4 +109,10 @@ const { headings } = Astro.props;
|
|||||||
</nav>
|
</nav>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { sidebarHighlight } from "./utils";
|
||||||
|
// Highlight the current url of the sidebar
|
||||||
|
document.addEventListener("DOMContentLoaded", sidebarHighlight);
|
||||||
|
</script>
|
||||||
</BaseLayout>
|
</BaseLayout>
|
||||||
|
@ -77,7 +77,9 @@ for (const entry of pagesIndex) {
|
|||||||
<BaseLayout title={frontmatter.title}>
|
<BaseLayout title={frontmatter.title}>
|
||||||
<Navbar />
|
<Navbar />
|
||||||
|
|
||||||
<div class="lg:grid lg:grid-cols-[14rem_auto_12rem] lg:container mx-auto font-display">
|
<div
|
||||||
|
class="lg:grid lg:grid-cols-[14rem_auto_12rem] lg:container mx-auto font-display"
|
||||||
|
>
|
||||||
<div
|
<div
|
||||||
id="sidebar"
|
id="sidebar"
|
||||||
class="pt-12 h-screen lg:sticky top-0 fixed z-10 bg-c-bg w-60 lg:w-auto border-r-2 lg:border-0
|
class="pt-12 h-screen lg:sticky top-0 fixed z-10 bg-c-bg w-60 lg:w-auto border-r-2 lg:border-0
|
||||||
@ -112,26 +114,12 @@ for (const entry of pagesIndex) {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import {highlightOnDom} from "./thpHighlighter";
|
import { highlightOnDom } from "./thpHighlighter";
|
||||||
document.addEventListener("DOMContentLoaded", highlightOnDom);
|
document.addEventListener("DOMContentLoaded", highlightOnDom);
|
||||||
</script>
|
</script>
|
||||||
<script>
|
<script>
|
||||||
|
import { sidebarHighlight } from "./utils";
|
||||||
// Highlight the current url of the sidebar
|
// Highlight the current url of the sidebar
|
||||||
document.addEventListener("DOMContentLoaded", () => {
|
document.addEventListener("DOMContentLoaded", sidebarHighlight);
|
||||||
let current_uri = window.location.pathname;
|
|
||||||
|
|
||||||
const sidebar = document.getElementById("sidebar")!
|
|
||||||
.children[0]! as HTMLElement;
|
|
||||||
const links = sidebar.querySelectorAll("a");
|
|
||||||
for (const link of [...links]) {
|
|
||||||
if (link.getAttribute("href") === current_uri) {
|
|
||||||
sidebar.scrollTop =
|
|
||||||
link.offsetTop - sidebar.offsetTop - 250;
|
|
||||||
|
|
||||||
link.classList.add("bg-pink-200", "dark:bg-pink-950");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
</script>
|
</script>
|
||||||
</BaseLayout>
|
</BaseLayout>
|
||||||
|
17
src/layouts/utils.ts
Normal file
17
src/layouts/utils.ts
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
|
||||||
|
export function sidebarHighlight() {
|
||||||
|
let current_uri = window.location.pathname;
|
||||||
|
|
||||||
|
const sidebar = document.getElementById("sidebar")!
|
||||||
|
.children[0]! as HTMLElement;
|
||||||
|
const links = sidebar.querySelectorAll("a");
|
||||||
|
for (const link of [...links]) {
|
||||||
|
if (link.getAttribute("href") === current_uri) {
|
||||||
|
sidebar.scrollTop =
|
||||||
|
link.offsetTop - sidebar.offsetTop - 250;
|
||||||
|
|
||||||
|
link.classList.add("bg-pink-200", "dark:bg-pink-950");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -9,7 +9,7 @@ export default {
|
|||||||
"c-text": "var(--c-text)",
|
"c-text": "var(--c-text)",
|
||||||
"c-text-2": "var(--c-text-2)",
|
"c-text-2": "var(--c-text-2)",
|
||||||
"c-purple": "var(--c-purple)",
|
"c-purple": "var(--c-purple)",
|
||||||
"c-border-1": "rgba(150,150,150,0.25)",
|
"c-border-1": "var(--c-border-1)",
|
||||||
"c-purple-light": "var(--c-purple-light)",
|
"c-purple-light": "var(--c-purple-light)",
|
||||||
"c-box-shadow": "var(--c-box-shadow)",
|
"c-box-shadow": "var(--c-box-shadow)",
|
||||||
"c-ping": "var(--c-pink)",
|
"c-ping": "var(--c-pink)",
|
||||||
|
Loading…
Reference in New Issue
Block a user