(styles,wiki) use new layout for regular posts

This commit is contained in:
Maciej Jur 2023-06-10 21:34:22 +02:00
parent 179d5788ec
commit 6862bdebeb
15 changed files with 245 additions and 197 deletions

View file

@ -1,3 +1,3 @@
<aside class="sc-sidenote"> <small class="marginnote">
<slot /> <slot />
</aside> </small>

View file

@ -1,49 +1,20 @@
--- ---
import { Maybe } from 'purify-ts/Maybe';
import HeadingsList from './HeadingsList.astro';
import type { MarkdownHeading } from 'astro'; import type { MarkdownHeading } from 'astro';
import { Maybe } from 'purify-ts';
interface Props { interface Props {
headings: Maybe<MarkdownHeading[]>; headings: MarkdownHeading[];
} }
type Nested = MarkdownHeading & { children?: MarkdownHeading[] };
const { headings } = Astro.props; const { headings } = Astro.props;
function fold(headings: MarkdownHeading[]) {
const toc = [] as Nested[];
const map = new Map<number, Nested>();
for (const h of headings) {
const heading = { ...h };
map.set(heading.depth, heading);
if (heading.depth === 2)
toc.push(heading)
else {
const backref = map.get(heading.depth - 1)!;
backref.children
? backref.children.push(heading)
: backref.children = [heading];
}
}
return toc;
}
--- ---
{headings <h2 class="link-tree__heading">
.map(fold) <span class="link-tree__heading-text">Content</span>
.map(headings => </h2>
<ul class="link-tree__nav-list"> <nav id="table-of-contents" class="link-tree__nav">
{headings.map(heading => <HeadingsList headings={Maybe.of(headings)} />
<li class="link-tree__nav-list-item"> </nav>
<a class="link-tree__nav-list-text link" href={`#${heading.slug}`}>
{heading.text}
</a>
<Astro.self headings={Maybe.fromNullable(heading.children)}/>
</li>
)}
</ul>
)
.extract()
}

View file

@ -0,0 +1,49 @@
---
import type { MarkdownHeading } from 'astro';
import { Maybe } from 'purify-ts';
interface Props {
headings: Maybe<MarkdownHeading[]>;
}
type Nested = MarkdownHeading & { children?: MarkdownHeading[] };
const { headings } = Astro.props;
function fold(headings: MarkdownHeading[]) {
const toc = [] as Nested[];
const map = new Map<number, Nested>();
for (const h of headings) {
const heading = { ...h };
map.set(heading.depth, heading);
if (heading.depth === 2)
toc.push(heading)
else {
const backref = map.get(heading.depth - 1)!;
backref.children
? backref.children.push(heading)
: backref.children = [heading];
}
}
return toc;
}
---
{headings
.map(fold)
.map(headings =>
<ul class="link-tree__nav-list">
{headings.map(heading =>
<li class="link-tree__nav-list-item">
<a class="link-tree__nav-list-text link" href={`#${heading.slug}`}>
{heading.text}
</a>
<Astro.self headings={Maybe.fromNullable(heading.children)}/>
</li>
)}
</ul>
)
.extract()
}

View file

@ -1,51 +1,26 @@
--- ---
import { PageTree, pathify } from "@utils/tree"; import PagesList from "./PagesList.astro";
import { Maybe } from "purify-ts"; import type { Maybe } from "purify-ts/Maybe";
import type { PagesProps } from "./PagesList.astro";
import { pathify } from "@utils/tree";
export interface PagesProps { interface Props {
tree: PageTree; heading: string;
slug: Maybe<string>; pages: Maybe<PagesProps>;
prefix: Maybe<string>;
} }
const { heading, pages } = Astro.props;
type Props = PagesProps;
const { tree, slug, prefix } = Astro.props;
function compare(a: {title: string}, b: {title: string}) {
return a.title.localeCompare(b.title, "en", {
numeric: true,
sensitivity: "base",
});
}
function checkCurrent(checked: Maybe<string>) {
return Maybe
.sequence([checked, slug])
.mapOrDefault(([a, b]) => a == pathify(b), false)
}
--- ---
{tree.children <h2 class="link-tree__heading">
.map(m => Object.values(m)) {pages.chain(x => x.prefix)
.filter(xs => xs.length > 0) .map(pathify)
.map(pages => .mapOrDefault(href =>
<ul class="link-tree__nav-list"> <a class="link-tree__heading-text" href={href}>{heading}</a>,
{pages <span class="link-tree__heading-text">{heading}</span>
.sort(compare)
.map(page => ({...page, current: checkCurrent(page.slug) }))
.map(page =>
<li class="link-tree__nav-list-item">
{page.slug
.chain(slug => prefix.map(prefix => pathify(prefix, slug)))
.map(href => (page.current)
? <button id="current-page-button" class="link-tree__nav-list-text current">{page.title}</button>
: <a class="link-tree__nav-list-text link" href={href}>{page.title}</a>
)
.orDefault(<span class="link-tree__nav-list-text">{page.title}</span>)}
<Astro.self tree={page} slug={slug} prefix={prefix} />
</li>
)} )}
</ul> </h2>
).extract()} <nav class="link-tree__nav">
{pages.map(pages => <PagesList {...pages} />).extract()}
</nav>

View file

@ -0,0 +1,51 @@
---
import { PageTree, pathify } from "@utils/tree";
import { Maybe } from "purify-ts";
export interface PagesProps {
tree: PageTree;
slug: Maybe<string>;
prefix: Maybe<string>;
}
type Props = PagesProps;
const { tree, slug, prefix } = Astro.props;
function compare(a: {title: string}, b: {title: string}) {
return a.title.localeCompare(b.title, "en", {
numeric: true,
sensitivity: "base",
});
}
function checkCurrent(checked: Maybe<string>) {
return Maybe
.sequence([checked, slug])
.mapOrDefault(([a, b]) => a == pathify(b), false)
}
---
{tree.children
.map(m => Object.values(m))
.filter(xs => xs.length > 0)
.map(pages =>
<ul class="link-tree__nav-list">
{pages
.sort(compare)
.map(page => ({...page, current: checkCurrent(page.slug) }))
.map(page =>
<li class="link-tree__nav-list-item">
{page.slug
.chain(slug => prefix.map(prefix => pathify(prefix, slug)))
.map(href => (page.current)
? <button id="current-page-button" class="link-tree__nav-list-text current">{page.title}</button>
: <a class="link-tree__nav-list-text link" href={href}>{page.title}</a>
)
.orDefault(<span class="link-tree__nav-list-text">{page.title}</span>)}
<Astro.self tree={page} slug={slug} prefix={prefix} />
</li>
)}
</ul>
).extract()}

View file

@ -1,10 +1,9 @@
--- ---
import Pages from "./Pages.astro"; import Pages from "./Pages.astro";
import Headings from "./Headings.astro"; import Headings from "./Headings.astro";
import { pathify } from "@utils/tree"; import { Maybe } from "purify-ts";
import type { Maybe } from "purify-ts";
import type { MarkdownHeading } from "astro"; import type { MarkdownHeading } from "astro";
import type { PagesProps } from "./Pages.astro"; import type { PagesProps } from "./PagesList.astro";
interface Props { interface Props {
@ -13,11 +12,31 @@ interface Props {
headings: Maybe<MarkdownHeading[]>; headings: Maybe<MarkdownHeading[]>;
} }
interface PagesView {
kind: "pages";
pages: PagesProps;
}
interface HeadingsView {
kind: "headings";
headings: MarkdownHeading[];
}
type Views =
| PagesView
| HeadingsView;
const { heading, pages, headings } = Astro.props; const { heading, pages, headings } = Astro.props;
const views = Maybe.catMaybes<Views>([
pages.map(pages => ({ kind: "pages", pages })),
headings.map(headings => ({ kind: "headings", headings })),
])
--- ---
<section class="link-tree"> <section class="link-tree">
<!-- Nav mode switch --> <!-- Nav mode switch -->
{views.length > 1 && (
<input id="link-tree-mode" type="checkbox" hidden /> <input id="link-tree-mode" type="checkbox" hidden />
<label id="link-tree-switch" class="link-tree__switch" <label id="link-tree-switch" class="link-tree__switch"
for="link-tree-mode" for="link-tree-mode"
@ -26,31 +45,27 @@ const { heading, pages, headings } = Astro.props;
title="Switch navigation mode"> title="Switch navigation mode">
<img class="link-tree__icon" src="/static/svg/change.svg" alt="Switch navigation mode" width="24" height="24"/> <img class="link-tree__icon" src="/static/svg/change.svg" alt="Switch navigation mode" width="24" height="24"/>
</label> </label>
<!-- Primary view displaying current headings -->
<div class="v-alt">
<h2 class="link-tree__heading">
<span class="link-tree__heading-text">Content</span>
</h2>
<nav class="link-tree__nav">
<Headings headings={headings} />
</nav>
</div>
<!-- Optional view displaying page tree -->
<div class="v-prime">
<h2 class="link-tree__heading">
{pages.chain(x => x.prefix)
.map(pathify)
.mapOrDefault(href =>
<a class="link-tree__heading-text" href={href}>{heading}</a>,
<span class="link-tree__heading-text">{heading}</span>
)} )}
</h2>
<nav class="link-tree__nav"> <!-- If >0 views to show -->
{pages.map(pages => <Pages {...pages} />).extract()} {views.length > 0 && (
</nav> <div class="v-prime">
{views[0].kind === 'pages'
&& <Pages heading={heading} pages={Maybe.of(views[0].pages)} />}
{views[0].kind === 'headings'
&& <Headings headings={views[0].headings}/>}
</div> </div>
)}
<!-- If >1 views to show -->
{views.length > 1 && (
<div class="v-alt">
{views[1].kind === 'pages'
&& <Pages heading={heading} pages={Maybe.of(views[1].pages)} />}
{views[1].kind === 'headings'
&& <Headings headings={views[1].headings}/>}
</div>
)}
<script> <script>
const button = document.getElementById("link-tree-switch"); const button = document.getElementById("link-tree-switch");

View file

@ -3,7 +3,7 @@ title: "CSS - How do you even write that?"
date: 2022-10-01T21:06:44+02:00 date: 2022-10-01T21:06:44+02:00
tags: ["webdev"] tags: ["webdev"]
--- ---
import Sidenote from '../../components/Sidenote.astro'; import Sidenote from '@components/Sidenote.astro';
## Writing CSS is hard ## Writing CSS is hard

View file

@ -19,22 +19,23 @@ interface Props {
const { frontmatter, slug } = Astro.props; const { frontmatter, slug } = Astro.props;
function constructTree(tree?: PageTree) { function constructWikiTree(tree?: PageTree) {
return MaybeAsync return MaybeAsync
.liftMaybe(Maybe.fromNullable(tree)) .liftMaybe(Maybe.fromNullable(tree))
.alt( .alt(
MaybeAsync(async () => await getCollection('wiki')) MaybeAsync(async () => await getCollection('wiki'))
.map(collapse)); .map(collapse))
}
const headings = Maybe.fromNullable(Astro.props.headings);
const pages = (await constructTree(Astro.props.tree))
.map(tree => ({ .map(tree => ({
tree, tree,
slug: Maybe.fromNullable(slug), slug: Maybe.fromNullable(slug),
prefix: Maybe.of("/wiki/") prefix: Maybe.of("/wiki/")
})); }));
}
const headings = Maybe.fromNullable(Astro.props.headings);
const pages = Astro.url.pathname.startsWith("/wiki/")
? await constructWikiTree(Astro.props.tree)
: Maybe.empty();
--- ---
<Base> <Base>
@ -51,9 +52,13 @@ const pages = (await constructTree(Astro.props.tree))
<Tree heading="Personal Wiki" pages={pages} headings={headings} /> <Tree heading="Personal Wiki" pages={pages} headings={headings} />
</aside> </aside>
<article class="wiki-article markdown"> <article class="wiki-article">
<heading class="markdown">
<h1>{frontmatter?.title}</h1> <h1>{frontmatter?.title}</h1>
</heading>
<section class="wiki-article__markdown markdown">
<slot /> <slot />
</section>
</article> </article>
</main> </main>
</Base> </Base>

View file

@ -1,5 +1,5 @@
--- ---
layout: ../layouts/Article.astro layout: ../layouts/Wiki.astro
title: "A little about me!" title: "A little about me!"
date: 2021-09-10T19:34:01+02:00 date: 2021-09-10T19:34:01+02:00
tags: ["meta"] tags: ["meta"]

View file

@ -1,5 +1,5 @@
--- ---
import Article from '../../layouts/Article.astro'; import Wiki from '@layouts/Wiki.astro';
import { getCollection } from 'astro:content'; import { getCollection } from 'astro:content';
@ -12,6 +12,6 @@ const { entry } = Astro.props;
const { Content, headings } = await entry.render(); const { Content, headings } = await entry.render();
--- ---
<Article frontmatter={entry.data} headings={headings}> <Wiki frontmatter={entry.data} headings={headings}>
<Content /> <Content />
</Article> </Wiki>

View file

@ -1,28 +0,0 @@
---
import dayjs from "dayjs";
import List from "../../layouts/List.astro";
import { getCollection } from 'astro:content';
import { getAllTags } from "./utils";
export async function getStaticPaths() {
return [...await getAllTags()].map(tag => ({params: {tag}}));
}
const tag = Astro.params.tag!;
const predicate = (entry: any) => entry.data.tags?.includes(tag);
const posts = (await Promise.all([
getCollection('posts', predicate),
getCollection('slides', predicate),
]))
.flat()
.sort((a, b) => a.data.date < b.data.date ? 1 : -1)
.map(entry => ({
title: entry.data.title,
slug: `/${entry.collection}/${entry.slug}/`,
date: dayjs(entry.data.date),
}))
---
<List title={tag} pages={posts} />

View file

@ -1,13 +0,0 @@
---
import List from "../../layouts/List.astro";
import { getAllTags } from "./utils";
const pages = [...await getAllTags()]
.map(tag => ({
title: tag,
slug: `/tags/${tag}/`
}));
---
<List title="Tags" pages={pages} />

View file

@ -1,14 +0,0 @@
import { getCollection } from "astro:content";
export async function getAllTags() {
return (await Promise.all([
getCollection('posts'),
getCollection('slides'),
]))
.flat()
.reduce(
(acc, next) => (next.data.tags?.forEach(tag => acc.add(tag)), acc),
new Set<string>()
);
}

View file

@ -1,6 +1,4 @@
.markdown { .markdown {
overflow-x: auto;
> h1 { > h1 {
font-size: 2.227em; font-size: 2.227em;
} }
@ -38,6 +36,14 @@
} }
} }
> ul, ol {
padding-left: 1em;
ul, ol {
padding-left: 1em;
}
}
blockquote { blockquote {
position: relative; position: relative;
margin: 1em 2em; margin: 1em 2em;
@ -57,6 +63,7 @@
> table { > table {
margin: 1em auto 1em auto; margin: 1em auto 1em auto;
border-collapse: collapse; border-collapse: collapse;
overflow-x: auto;
th, td { th, td {
padding: 0.2em 0.5em; padding: 0.2em 0.5em;
@ -101,6 +108,32 @@
.math-display { .math-display {
margin-block: 1em; margin-block: 1em;
font-size: 1.1em; font-size: 1.1em;
overflow-x: auto;
}
.marginnote {
display: block;
margin: 1em 1.5em;
padding-block: 0.5em;
border-block: 1px dashed gray;
color: gray;
@media (min-width: 38em) {
float: right;
clear: right;
max-width: 14rem;
margin-right: 0;
text-align: justify;
hyphens: auto;
}
@media (min-width: 80em) {
margin: 2em -17rem;
}
a {
color: var(--c-primary);
}
} }
// TODO: clean this // TODO: clean this

View file

@ -5,14 +5,14 @@ $bp-l: 80rem;
.wiki-main { .wiki-main {
position: relative; position: relative;
display: grid; display: grid;
grid-template-columns: auto 1fr; grid-template-columns: auto minmax(0, 1fr);
@media (min-width: $bp-m) { @media (min-width: $bp-m) {
grid-template-columns: 16rem 1fr; grid-template-columns: 16rem minmax(0, 1fr);
} }
@media (min-width: $bp-l) { @media (min-width: $bp-l) {
grid-template-columns: 16rem 1fr 16rem; grid-template-columns: 16rem minmax(0, 1fr) 16rem;
} }
} }
@ -74,7 +74,7 @@ $bp-l: 80rem;
} }
.wiki-article { .wiki-article {
max-width: 100%; min-width: 0;
margin-inline: auto; margin-inline: auto;
padding: 1em; padding: 1em;
padding-top: 2em; padding-top: 2em;
@ -94,4 +94,8 @@ $bp-l: 80rem;
margin-block: 2em; margin-block: 2em;
padding: 2em; padding: 2em;
} }
&__markdown {
max-width: calc(100vw - 2em);
}
} }