Test impl of tree component

This commit is contained in:
Maciej Jur 2023-06-06 10:24:08 +02:00
parent f61508d4a8
commit 1b5b644356
8 changed files with 185 additions and 0 deletions

View file

@ -17,6 +17,7 @@
"dayjs": "^1.11.7",
"leaflet": "^1.9.4",
"leaflet.markercluster": "^1.5.3",
"purify-ts": "^2.0.1",
"rehype-katex": "^6.0.3",
"rehype-raw": "^6.1.1",
"rehype-stringify": "^9.0.3",

View file

@ -26,6 +26,9 @@ dependencies:
leaflet.markercluster:
specifier: ^1.5.3
version: 1.5.3(leaflet@1.9.4)
purify-ts:
specifier: ^2.0.1
version: 2.0.1
rehype-katex:
specifier: ^6.0.3
version: 6.0.3
@ -828,6 +831,10 @@ packages:
'@types/unist': 2.0.6
dev: false
/@types/json-schema@7.0.12:
resolution: {integrity: sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA==}
dev: false
/@types/json5@0.0.30:
resolution: {integrity: sha512-sqm9g7mHlPY/43fcSNrCYfOeX9zkTTK+euO5E6+CVijSMm5tTjkVdwdqRkY3ljjIAf8679vps5jKUoJBCLsMDA==}
dev: false
@ -3069,6 +3076,12 @@ packages:
/proxy-from-env@1.1.0:
resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==}
/purify-ts@2.0.1:
resolution: {integrity: sha512-g17AdcyNtXyUuLgMfQN8bS2xPiTrxxkebe5Ssy234NX8ZpE2Nbk6bIXO5MNapFVb77jcv7a4Xt9NfPtuCLGiBQ==}
dependencies:
'@types/json-schema': 7.0.12
dev: false
/queue-microtask@1.2.3:
resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
dev: false

View file

@ -0,0 +1,34 @@
---
import { Tree, pathify } from "@utils/tree";
import { Maybe } from "purify-ts";
interface Props {
tree: Tree;
prefix: Maybe<string>;
}
const { tree, prefix } = Astro.props;
---
{tree.children
.map(m => Object.values(m))
.filter(xs => xs.length > 0)
.map(pages =>
<ul>
{pages.map(page =>
<li>
{Maybe.of(Maybe.catMaybes([prefix, page.slug]))
.filter(xs => xs.length > 0)
.map(xs => pathify(...xs))
.mapOrDefault(href =>
<a href={href}>{page.title}</a>,
<span>{page.title}</span>
)}
<Astro.self tree={page} prefix={prefix} />
</li>
)}
</ul>
).extract()}

View file

@ -0,0 +1,26 @@
---
import List from "./List.astro";
import { Tree, pathify } from "@utils/tree";
import type { Maybe } from "purify-ts";
interface Props {
tree: Tree;
prefix: Maybe<string>;
}
const { tree, prefix } = Astro.props;
---
<aside class="link-tree">
<h2 class="link-tree__heading">
{prefix.map(pathify).mapOrDefault(href =>
<a href={href}>Personal wiki</a>,
<span>Personal Wiki</span>
)}
</h2>
<section>
<List tree={tree} prefix={prefix} />
</section>
</aside>

View file

@ -0,0 +1,5 @@
---
title: "Hello"
slug: "typescript"
---
Hello

View file

@ -0,0 +1,35 @@
---
title: "Hello"
---
## 4・Pick
> Implement the built-in `Pick<T, K>` generic without using it. Constructs a type by picking the set of properties `K` from `T`.
```ts
type MyPick<T, K extends keyof T> = {
[key in K]: k extends keyof T ? T[key] : never;
}
```
## 7・Readonly
> Implement the built-in `Readonly<T>` generic without using it. Constructs a type with all properties of T set to readonly, meaning the properties of the constructed type cannot be reassigned.
```ts
type MyReadonly<T> = {
readonly [key in keyof T]: T[key];
}
```
## 11・Tuple to Object
> Given an array, transform it into an object type and the key/value must be in the provided array.
```ts
type TupleToObject<T extends readonly (string | number)[]> = {
[val in T[number]]: val;
}
```

View file

@ -0,0 +1,27 @@
---
import Tree from '@components/tree/Tree.astro';
import Base from '@layouts/Base.astro';
import type { InferGetStaticPropsType } from 'astro';
import { getCollection } from 'astro:content';
import { Maybe } from 'purify-ts';
import { collapse } from '@utils/tree';
type Props = InferGetStaticPropsType<typeof getStaticPaths>;
export async function getStaticPaths() {
const pages = await getCollection('wiki');
const tree = collapse(pages);
return pages.map(entry => ({params: {slug: entry.slug}, props: {tree, entry}}));
}
const { tree, entry } = Astro.props;
const { Content } = await entry.render();
---
<Base>
<Tree tree={tree} prefix={Maybe.of("/wiki/")}/>
<main>
<Content />
</main>
</Base>

44
src/utils/tree.ts Normal file
View file

@ -0,0 +1,44 @@
import { Maybe } from "purify-ts";
interface Page {
slug: string;
data: { title: string };
}
export interface Tree {
title: string;
slug: Maybe<string>;
children: Maybe<{ [key: string]: Tree }>;
}
export function collapse(pages: Page[]): Tree {
const root: Tree = { title: '', slug: Maybe.empty(), children: Maybe.empty() };
for (const page of pages) {
const ptr = page.slug.split('/')
.reduce((ptr, slug) => {
// acquire pointer on next node in tree
const next = ptr.children
.chainNullable(trie => trie[slug])
.orDefaultLazy(() => ({ title: slug, slug: Maybe.empty(), children: Maybe.empty() }));
// update tree refs
ptr.children = ptr.children
.ifJust(trie => trie[slug] = next)
.altLazy(() => Maybe.of({[slug]: next}));
return next;
}, root);
ptr.slug = Maybe.of(`/${page.slug}/`);
ptr.title = page.data.title;
}
return root;
}
export function pathify(...slugs: string[]): string {
const path = slugs.map(part => part.trim().replace(/(^[\/]*|[\/]*$)/g, '')).join('/');
return `/${path}/`;
}