Compare commits

...

3 Commits

Author SHA1 Message Date
eee2f60c61 feat: Implement sidebar for api docs 2024-08-26 11:05:21 -05:00
53d6ee686d feat: Improve sidebar on API docs 2024-08-26 09:36:52 -05:00
f1bc675869 feat: small ui improvements 2024-08-26 09:00:43 -05:00
12 changed files with 202 additions and 39 deletions

View File

@ -51,6 +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: #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);

View File

@ -1,5 +1,5 @@
.markdown h1 { .markdown > h1 {
font-size: 2.25rem; font-size: 2.25rem;
line-height: 2.5rem; line-height: 2.5rem;
margin-bottom: 1rem; margin-bottom: 1rem;
@ -8,9 +8,10 @@
opacity: 0.9; opacity: 0.9;
font-weight: 700; font-weight: 700;
color: var(--c-text-2); color: var(--c-text-2);
scroll-margin-top: 50px;
} }
.markdown h2 { .markdown > h2 {
/* use these tailwind classes: text-2xl mt-10 mb-4 font-display opacity-90 font-bold text-c-text-2 */ /* use these tailwind classes: text-2xl mt-10 mb-4 font-display opacity-90 font-bold text-c-text-2 */
font-size: 1.5rem; font-size: 1.5rem;
line-height: 2rem; line-height: 2rem;
@ -20,9 +21,10 @@
opacity: 0.9; opacity: 0.9;
font-weight: 600; font-weight: 600;
color: var(--c-text-2); color: var(--c-text-2);
scroll-margin-top: 5rem;
} }
.markdown h2::before { .markdown > h2::before {
content: "#"; content: "#";
display: block; display: block;
height: 0; height: 0;
@ -31,7 +33,12 @@
opacity: 0.2; opacity: 0.2;
} }
.markdown h3 { .markdown > h2:target::before {
color: var(--c-thp);
opacity: 1;
}
.markdown > h3 {
font-size: 1.35rem; font-size: 1.35rem;
line-height: 1.75rem; line-height: 1.75rem;
margin-bottom: 1rem; margin-bottom: 1rem;
@ -40,9 +47,10 @@
opacity: 0.9; opacity: 0.9;
font-weight: 400; font-weight: 400;
color: var(--c-text-2); color: var(--c-text-2);
scroll-margin-top: 5rem;
} }
.markdown h3::before { .markdown > h3::before {
content: "##"; content: "##";
display: block; display: block;
height: 0; height: 0;
@ -51,6 +59,11 @@
opacity: 0.2; opacity: 0.2;
} }
.markdown > h3:target::before {
color: var(--c-thp);
opacity: 1;
}
.markdown ul { .markdown ul {
list-style-type: disc; list-style-type: disc;
list-style-position: inside; list-style-position: inside;
@ -60,6 +73,10 @@
padding: 0.5rem 0; padding: 0.5rem 0;
} }
.markdown p > code {
border: solid 1px var(--c-border-1);
}
.markdown > pre { .markdown > pre {
margin: 0.5em 0; margin: 0.5em 0;
padding: 0.75em 0.75em; padding: 0.75em 0.75em;
@ -79,4 +96,10 @@
.two-column a { .two-column a {
color: #2563eb; color: #2563eb;
text-decoration: underline; text-decoration: underline;
display: inline-block;
} }
.two-column h3 {
margin: 0.75rem 0;
}

View 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>
))
}

View File

@ -25,6 +25,7 @@ function buildHierarchy(headings: any) {
parentHeadings.get(heading.depth - 1).subheadings.push(heading); parentHeadings.get(heading.depth - 1).subheadings.push(heading);
} }
}); });
return toc; return toc;
} }
--- ---

View File

@ -1,17 +1,22 @@
--- ---
// github.com/rezahedi/rezahedi.dev/blob/main/src/components/TOCHeading.astro // github.com/rezahedi/rezahedi.dev/blob/main/src/components/TOCHeading.astro
const { heading } = Astro.props; const { heading, parentMono } = Astro.props;
// If a heading starts with `API: `
// then its children should be rendered with a mono font
const isMono = heading.text.startsWith("API: ");
const monoClass = parentMono? " font-mono" : "";
--- ---
<li> <li>
<a class="inline-block py-1 hover:underline" href={"#" + heading.slug}> <a class={"inline-block py-1 hover:underline" + monoClass} href={"#" + heading.slug}>
{heading.text} {heading.text}
</a> </a>
{ {
heading.subheadings.length > 0 && ( heading.subheadings.length > 0 && (
<ul class="px-2"> <ul class="px-2">
{heading.subheadings.map((subheading: any) => ( {heading.subheadings.map((subheading: any) => (
<Astro.self heading={subheading} /> <Astro.self heading={subheading} parentMono={isMono} />
))} ))}
</ul> </ul>
) )

View File

@ -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>

View File

@ -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
View 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;
}
}
}

View File

@ -1,7 +1,7 @@
import { spawn } from "node:child_process"; import { spawn } from "node:child_process";
import { leftTrimDedent } from "../components/utils"; import { leftTrimDedent } from "../components/utils";
import { HighlightLevel } from "./types"; import { HighlightLevel } from "./types";
import type { LexError, SyntaxError, SemanticError, Token, TokenizeResult, TokenType } from "./types"; import type { LexError, SyntaxError, Token, TokenizeResult, TokenType } from "./types";
const error_classes = "underline underline-offset-4 decoration-wavy decoration-red-500"; const error_classes = "underline underline-offset-4 decoration-wavy decoration-red-500";

View File

@ -61,38 +61,40 @@ val my_animal = 'animal()
`} /> `} />
## Datatypes ## API: Datatypes
<TwoColumn> <TwoColumn>
[`Array[T]`](/api/std/Array/) ### [`Array[T]`](/api/std/Array/)
A uniform container of values or references. A uniform container of values or references.
[`String`](/api/std/String/) ### [`String`](/api/std/String/)
A series of extended ASCII characters (8 bits). A series of extended ASCII characters (8 bits).
[`Int`](/api/std/Int/) ### [`Int`](/api/std/Int/)
An integer number. An integer number.
[`Float`](/api/std/Float/) ### [`Float`](/api/std/Float/)
A [IEEE 754](https://en.wikipedia.org/wiki/IEEE_754) double precision floating point number. A [IEEE 754](https://en.wikipedia.org/wiki/IEEE_754) double precision floating point number.
[`Bool`](/api/std/Bool/) ### [`Bool`](/api/std/Bool/)
`true` or `false` `true` or `false`
</TwoColumn> </TwoColumn>
## Global functions ## API: Global functions
<TwoColumn> <TwoColumn>
[`print`](/api/std/print/)
### [`print`](/api/std/print/)
Prints text into stdout. Prints text into stdout.
</TwoColumn> </TwoColumn>

View File

@ -10,23 +10,30 @@ import Code from "../../../components/Code.astro"
```ebnf ```ebnf
Int = hexadecimal_number Int = hexadecimal_number
| octal_number
| binary_number
| decimal_number | decimal_number
hexadecimal_number = "0", ("x" | "X"), hexadecimal_digit+ hexadecimal_number = "0", ("x" | "X"), hexadecimal_digit+
decimal_number = decimal_digit+ decimal_number = decimal_digit+
octal_number = "0", ("o" | "O"), octal_digit+
binary_number = "0", "b", binary_digit +
``` ```
<Code thpcode={` <Code thpcode={`
12345 12345
01234 // This is a decimal number, not an octal number 01234 // This is a decimal number, not an octal number
0o755 // This is octal
0b0110
0xff25 0xff25
0XFfaA 0XFfaA
`} /> `} />
`TODO`: Implement octal `0o777` and binary `0b0110`.
`TODO`: Allow underscores `_` between any number: `1_000_000`. `TODO`: Allow underscores `_` between any number: `1_000_000`.
`TODO`: Make it an error to have a number start with a leading zero,
to eliminate confusion with proper octal and legacy PHP octal.
## Float ## Float

View File

@ -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)",