(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 />
</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 { Maybe } from 'purify-ts';
interface Props {
headings: Maybe<MarkdownHeading[]>;
headings: 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()
}
<h2 class="link-tree__heading">
<span class="link-tree__heading-text">Content</span>
</h2>
<nav id="table-of-contents" class="link-tree__nav">
<HeadingsList headings={Maybe.of(headings)} />
</nav>

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 { Maybe } from "purify-ts";
import PagesList from "./PagesList.astro";
import type { Maybe } from "purify-ts/Maybe";
import type { PagesProps } from "./PagesList.astro";
import { pathify } from "@utils/tree";
export interface PagesProps {
tree: PageTree;
slug: Maybe<string>;
prefix: Maybe<string>;
interface Props {
heading: string;
pages: Maybe<PagesProps>;
}
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)
}
const { heading, pages } = Astro.props;
---
{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()}
<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">
{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 Headings from "./Headings.astro";
import { pathify } from "@utils/tree";
import type { Maybe } from "purify-ts";
import { Maybe } from "purify-ts";
import type { MarkdownHeading } from "astro";
import type { PagesProps } from "./Pages.astro";
import type { PagesProps } from "./PagesList.astro";
interface Props {
@ -13,44 +12,60 @@ interface Props {
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 views = Maybe.catMaybes<Views>([
pages.map(pages => ({ kind: "pages", pages })),
headings.map(headings => ({ kind: "headings", headings })),
])
---
<section class="link-tree">
<!-- Nav mode switch -->
<input id="link-tree-mode" type="checkbox" hidden />
<label id="link-tree-switch" class="link-tree__switch"
for="link-tree-mode"
role="button"
tabindex="0"
title="Switch navigation mode">
<img class="link-tree__icon" src="/static/svg/change.svg" alt="Switch navigation mode" width="24" height="24"/>
</label>
{views.length > 1 && (
<input id="link-tree-mode" type="checkbox" hidden />
<label id="link-tree-switch" class="link-tree__switch"
for="link-tree-mode"
role="button"
tabindex="0"
title="Switch navigation mode">
<img class="link-tree__icon" src="/static/svg/change.svg" alt="Switch navigation mode" width="24" height="24"/>
</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">
{pages.map(pages => <Pages {...pages} />).extract()}
</nav>
</div>
<!-- If >0 views to show -->
{views.length > 0 && (
<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>
)}
<!-- 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>
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
tags: ["webdev"]
---
import Sidenote from '../../components/Sidenote.astro';
import Sidenote from '@components/Sidenote.astro';
## Writing CSS is hard

View file

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

View file

@ -1,5 +1,5 @@
---
layout: ../layouts/Article.astro
layout: ../layouts/Wiki.astro
title: "A little about me!"
date: 2021-09-10T19:34:01+02:00
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';
@ -12,6 +12,6 @@ const { entry } = Astro.props;
const { Content, headings } = await entry.render();
---
<Article frontmatter={entry.data} headings={headings}>
<Wiki frontmatter={entry.data} headings={headings}>
<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 {
overflow-x: auto;
> h1 {
font-size: 2.227em;
}
@ -38,6 +36,14 @@
}
}
> ul, ol {
padding-left: 1em;
ul, ol {
padding-left: 1em;
}
}
blockquote {
position: relative;
margin: 1em 2em;
@ -57,6 +63,7 @@
> table {
margin: 1em auto 1em auto;
border-collapse: collapse;
overflow-x: auto;
th, td {
padding: 0.2em 0.5em;
@ -101,6 +108,32 @@
.math-display {
margin-block: 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

View file

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