(styles,wiki) use new layout for regular posts
This commit is contained in:
parent
179d5788ec
commit
6862bdebeb
|
@ -1,3 +1,3 @@
|
|||
<aside class="sc-sidenote">
|
||||
<small class="marginnote">
|
||||
<slot />
|
||||
</aside>
|
||||
</small>
|
||||
|
|
|
@ -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>
|
||||
|
|
49
src/components/tree/HeadingsList.astro
Normal file
49
src/components/tree/HeadingsList.astro
Normal 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()
|
||||
}
|
|
@ -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>
|
||||
|
|
51
src/components/tree/PagesList.astro
Normal file
51
src/components/tree/PagesList.astro
Normal 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()}
|
|
@ -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");
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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"]
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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} />
|
|
@ -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} />
|
|
@ -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>()
|
||||
);
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue