diff --git a/src/components/ApiLayout/Sidebar.astro b/src/components/ApiLayout/Sidebar.astro deleted file mode 100644 index 5610822..0000000 --- a/src/components/ApiLayout/Sidebar.astro +++ /dev/null @@ -1,58 +0,0 @@ ---- -import type { Hierarchy, Post } from "../../layouts/ApiLayout.astro"; -import { splitAndLast } from "../utils"; - -const hierarchy: Hierarchy = Astro.props.hierarchy; - -function postComparison(a: Post, b: Post): number { - const s1 = splitAndLast(a.url); - const s2 = splitAndLast(b.url); - - return s1 > s2 ? 0 : 1; -} - -function appendSlash(s: string): string { - if (s.endsWith("/")) { - return s; - } else { - return s + "/"; - } -} ---- - -{ - Object.entries(hierarchy.children).map( - ([folderName, [folderPost, children]]) => ( - <> - {folderPost !== null ? ( - - {splitAndLast(folderPost.url)} - - ) : ( -
- {folderName} -
- )} - -
- -
- - ), - ) -} -{ - hierarchy.posts.sort(postComparison).map((p) => ( - - {splitAndLast(p.url)} - - )) -} diff --git a/src/components/Navbar.astro b/src/components/Navbar.astro index f999689..27ae018 100644 --- a/src/components/Navbar.astro +++ b/src/components/Navbar.astro @@ -1,6 +1,4 @@ --- -import { Sun, Moon, Laptop } from "lucide-astro"; - const { showSidebarButton = true, version = "latest" } = Astro.props; --- diff --git a/src/components/Sidebar.astro b/src/components/Sidebar.astro index 2dac5c8..bb5afdf 100644 --- a/src/components/Sidebar.astro +++ b/src/components/Sidebar.astro @@ -1,20 +1,63 @@ --- -import type { PageEntry } from "../layouts/PagesLayout.astro"; +import type { AstroFileHierarchy } from "@/layouts/NewDocsLayout.astro"; -const entry: PageEntry = Astro.props.entry; +const entry: AstroFileHierarchy = Astro.props.entry; const post_url = entry.url + (entry.url.endsWith("/") ? "" : "/"); // this may deal with folders. // if so, it will turn any `-` into whitespace, // and remove any leading number const entry_title = entry.title.replaceAll("-", " ").replaceAll(/\d+_/g, ""); +const mono_class = entry.frontmatter.mono === true ? "font-mono " : ""; --- { - !entry.children && ( + entry.children.length > 0 ? ( + entry.has_index === true ? ( + <> +
  • + + {entry_title} + +
  • + + + + ) : ( + <> +
    + {entry_title} +
    + + + + ) + ) : (
  • {entry.title} @@ -22,7 +65,9 @@ const entry_title = entry.title.replaceAll("-", " ").replaceAll(/\d+_/g, "");
  • ) } + { + /* entry.children && ( <>
    @@ -36,4 +81,5 @@ const entry_title = entry.title.replaceAll("-", " ").replaceAll(/\d+_/g, ""); ) +*/ } diff --git a/src/layouts/ApiLayout.astro b/src/layouts/ApiLayout.astro deleted file mode 100644 index 7fff50a..0000000 --- a/src/layouts/ApiLayout.astro +++ /dev/null @@ -1,150 +0,0 @@ ---- -import Navbar from "../components/Navbar.astro"; -import BaseLayout from "./BaseLayout.astro"; -import TOC from "../components/TOC.astro"; -import Sidebar from "../components/ApiLayout/Sidebar.astro"; -import { splitAndLast } from "../components/utils"; - -const { headings } = Astro.props; - -export type Post = { - frontmatter: any; - getHeadings: any; - url: string; - file: any; - Content: any; - default: any; -}; -type Posts = Array>; - -const basePath = "/api/std"; -const posts: Posts = await Astro.glob( - "../pages/en/latest/api/std/**/*.{md,mdx}", -); - -export type Hierarchy = { - posts: Array; - children: Record; -}; - -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] = [ - null, - { - posts: [], - children: {}, - }, - ]; - } - - const [_, childrenHierarchy] = hierarchy.children[folderName]!; - currentHierarchy = childrenHierarchy; - } - - // add the page - currentHierarchy.posts.push(post); - } - - return hierarchy; -} - -function normalizeHierarchy(h: Hierarchy): Hierarchy { - let posts = h.posts; - for (const folderName in h.children) { - // search if there is a post with the same name - // as the folder - const postIdx = h.posts.findIndex( - (post) => splitAndLast(post.url) === folderName, - ); - - if (postIdx !== -1) { - const post = h.posts[postIdx]!; - h.children[folderName]![0] = post; - posts.splice(postIdx, 1); - } - } - - // do the same to all children - // TODO - - return { - children: h.children, - posts, - }; -} - -const hierarchy = normalizeHierarchy(createHierarchy(posts)); ---- - - - - -
    - - -
    - -
    -
    - - -
    - - -
    diff --git a/src/layouts/NewDocsLayout.astro b/src/layouts/NewDocsLayout.astro index 7966fc9..5e32bef 100644 --- a/src/layouts/NewDocsLayout.astro +++ b/src/layouts/NewDocsLayout.astro @@ -15,13 +15,46 @@ export interface AstroFile { __usesAstroImage: boolean; url: string; file: string; - relative_file: string; } +export interface AstroFileP { + frontmatter: Frontmatter; + __usesAstroImage: boolean; + /** + * Full URL in the filesystem's `pages` folder. + * E.g.: `/en/latest/api/std/Array` + */ + url: string; + /** + * Full URL in the filesystem + * E.g.: `/home/user/project/src/pages/en/latest/api/std/Array` + */ + file: string; + /** + * Title of the page, as found in the frontmatter + * E.g.: `Array` + */ + title: string; + /** + * URL of the file, relative to a `base_url`. + * E.g.: if base_url=`/en/latest/api`, then path=`/std/Array/index.mdx` + */ + path: string; + /** + * Whether or not this file has a children whose name is index.mdx + */ + has_index: boolean; +} + +export type AstroFileHierarchy = AstroFileP & { + children: Array; +}; + export interface Frontmatter { layout: string; title: string; order: number; + mono?: boolean; } type Props = { @@ -41,77 +74,108 @@ const { version = "latest", }: Props = Astro.props; -const base_len = base_url.length; - -const posts_2 = posts +const posts_2: Array = posts .map((post) => ({ ...post, title: post.frontmatter.title, - // this should be a path relative to the base url. - // e.g if base_url is `/spec`, then this instead of - // being `/spec/ast/tokens` would be `/ast/tokens` - path: post.url.substring(base_len), + path: post.file.split(base_url)[1]!, + has_index: false, })) .sort((p1, p2) => p1.frontmatter.order > p2.frontmatter.order ? 1 : -1, ); -// build a hierarchy of the files -const second_level: Record> = { - _: [], -}; -for (const post of posts_2) { - const fragments = post.path.split("/"); - if (fragments.length === 3) { - const folder_name = fragments[1]!; +function buildFileTree( + flatPosts: Array, +): Array { + // @ts-ignore + const root: AstroFileHierarchy = { path: "", children: [] }; - // create if not exists - if (second_level[folder_name] === undefined) { - second_level[folder_name] = []; - } - second_level[folder_name].push(post); - } else { - // add to root folder - second_level["_"]!.push(post); - } + flatPosts.forEach((post) => { + // Remove leading/trailing slashes and split path + const parts = post.path.replace(/^\/|\/$/g, "").split("/"); + let current = root; + + // Build path segments + parts.forEach((part, index) => { + const path = "/" + parts.slice(0, index + 1).join("/"); + let node = current.children?.find( + (child) => child.path === path, + ); + + if (!node) { + node = { + ...post, + path, + title: + index === parts.length - 1 + ? post.title + : part, + children: [], + }; + current.children?.push(node); + } + current = node; + }); + }); + + return root.children || []; } -// build a folder hierarchy (only 2 levels) - -const entries: Array = []; -const levels_keys = Object.keys(second_level).toSorted(); - -// The key `_` contains the top level links. Always insert those -const top_level_posts = second_level["_"]!; -// sort -const sorted_posts = top_level_posts.toSorted(sort_posts); -entries.push(...sorted_posts); - -for (const levels_key of levels_keys) { - if (levels_key === "_") { - // top level, already inserted - continue; - } else { - const posts = second_level[levels_key]!; - const sorted_posts = posts.toSorted(sort_posts); - const parentEntry = { - path: "", - title: levels_key, - children: sorted_posts, - url: "", - }; - entries.push(parentEntry); - } +function sortFileTree(tree: AstroFileHierarchy[]): AstroFileHierarchy[] { + return tree + .map((node) => ({ + ...node, + children: node.children + ? sortFileTree(node.children) + : [], + })) + .sort(sort_posts); } -function sort_posts(p1, p2) { - if (!!p1.frontmatter.order && !!p2.frontmatter.order) { +function sort_posts(p1: AstroFileP, p2: AstroFileP) { + if (p1.frontmatter.order !== p2.frontmatter.order) { return p1.frontmatter.order > p2.frontmatter.order ? 1 : -1; } else { return p1.title > p2.title ? 1 : -1; } } +function markIndexPages(tree: AstroFileHierarchy[]): AstroFileHierarchy[] { + return tree.map((node) => { + const indexChild = node.children?.find((child) => + child.path.endsWith("index.mdx"), + ); + + if (indexChild && node.children) { + // Keep children (except index) and has_index, replace everything else + const { children, ...indexProps } = indexChild; + return { + ...indexProps, + children: markIndexPages( + node.children.filter( + (child) => + !child.path.endsWith( + "index.mdx", + ), + ), + ), + has_index: true, + }; + } + + return { + ...node, + children: node.children + ? markIndexPages(node.children) + : [], + }; + }); +} + +const posts_hierarchy = sortFileTree(markIndexPages(buildFileTree(posts_2))); + +// FIXME: centralize somewhere else const versions = ["latest", "v0.0.1"].filter((x) => x !== version); const url_components = base_url.split(version); const lc = url_components[0] ?? ""; @@ -186,7 +250,7 @@ const rc = url_components[1] ?? "";
    { - entries.map((entry) => ( + posts_hierarchy.map((entry) => ( )) } diff --git a/src/pages/en/latest/api/std/Array/concat.mdx b/src/pages/en/latest/api/std/Array/concat.mdx index 882c944..91fba63 100644 --- a/src/pages/en/latest/api/std/Array/concat.mdx +++ b/src/pages/en/latest/api/std/Array/concat.mdx @@ -1,5 +1,8 @@ --- -layout: "@/layouts/ApiLayout.astro" +layout: "../_wrapper.astro" +title: concat +order: 1 +mono: true --- import Code from "@/components/Code.astro"; diff --git a/src/pages/en/latest/api/std/Array/fold.mdx b/src/pages/en/latest/api/std/Array/fold.mdx index 5f6b461..731a400 100644 --- a/src/pages/en/latest/api/std/Array/fold.mdx +++ b/src/pages/en/latest/api/std/Array/fold.mdx @@ -1,5 +1,8 @@ --- -layout: "@/layouts/ApiLayout.astro" +layout: "../_wrapper.astro" +title: fold +order: 1 +mono: true --- import Code from "@/components/Code.astro"; diff --git a/src/pages/en/latest/api/std/Array.mdx b/src/pages/en/latest/api/std/Array/index.mdx similarity index 99% rename from src/pages/en/latest/api/std/Array.mdx rename to src/pages/en/latest/api/std/Array/index.mdx index e73bf8b..bc96a7b 100644 --- a/src/pages/en/latest/api/std/Array.mdx +++ b/src/pages/en/latest/api/std/Array/index.mdx @@ -1,5 +1,8 @@ --- -layout: "@/layouts/ApiLayout.astro" +layout: "../_wrapper.astro" +title: Array +order: 2 +mono: true --- import TwoColumn from "@/components/TwoColumn.astro"; diff --git a/src/pages/en/latest/api/std/Array/map.mdx b/src/pages/en/latest/api/std/Array/map.mdx index 21c5608..ac57352 100644 --- a/src/pages/en/latest/api/std/Array/map.mdx +++ b/src/pages/en/latest/api/std/Array/map.mdx @@ -1,5 +1,8 @@ --- -layout: "@/layouts/ApiLayout.astro" +layout: "../_wrapper.astro" +title: map +order: 1 +mono: true --- import Code from "@/components/Code.astro"; diff --git a/src/pages/en/latest/api/std/_wrapper.astro b/src/pages/en/latest/api/std/_wrapper.astro new file mode 100644 index 0000000..ca4e695 --- /dev/null +++ b/src/pages/en/latest/api/std/_wrapper.astro @@ -0,0 +1,24 @@ +--- +import NewDocsLayout, { type AstroFile } from "@/layouts/NewDocsLayout.astro"; + +const { frontmatter, headings } = Astro.props; +// Get all the posts from this dir + +const posts = (await Astro.glob( + "./**/*.{md,mdx}", +)) as unknown as Array; + +// The base of every URL under this glob +const base_url = "/en/latest/api/std"; +const version = "latest"; +--- + + + + diff --git a/src/pages/en/latest/api/std/index.mdx b/src/pages/en/latest/api/std/index.mdx index cfbedff..54c88de 100644 --- a/src/pages/en/latest/api/std/index.mdx +++ b/src/pages/en/latest/api/std/index.mdx @@ -1,5 +1,7 @@ --- -layout: "@/layouts/ApiLayout.astro" +layout: "./_wrapper.astro" +title: The THP stdlib +order: 1 --- import TwoColumn from "@/components/TwoColumn.astro"; diff --git a/src/pages/en/latest/api/std/print.mdx b/src/pages/en/latest/api/std/print.mdx index 6830fbb..156bee7 100644 --- a/src/pages/en/latest/api/std/print.mdx +++ b/src/pages/en/latest/api/std/print.mdx @@ -1,5 +1,8 @@ --- -layout: "@/layouts/ApiLayout.astro" +layout: "./_wrapper.astro" +title: print +order: 2 +mono: true --- import TwoColumn from "@/components/TwoColumn.astro";