This commit is contained in:
parent
e94fee5345
commit
3bf0200e7e
7 changed files with 138 additions and 39 deletions
41
src/components/TocWrapper.astro
Normal file
41
src/components/TocWrapper.astro
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
---
|
||||||
|
import type { MarkdownHeading } from "astro";
|
||||||
|
import "../styles/toc.scss";
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
toc: boolean;
|
||||||
|
headings: MarkdownHeading[];
|
||||||
|
}
|
||||||
|
|
||||||
|
const { toc, headings } = Astro.props;
|
||||||
|
---
|
||||||
|
|
||||||
|
{
|
||||||
|
toc ? (
|
||||||
|
<>
|
||||||
|
<div class="toc-wrapper">
|
||||||
|
<slot />
|
||||||
|
<div class="toc">
|
||||||
|
Table of contents
|
||||||
|
<ul>
|
||||||
|
{headings.map((heading) => {
|
||||||
|
return (
|
||||||
|
<li>
|
||||||
|
<a href={`#${heading.slug}`}>{heading.text}</a>
|
||||||
|
</li>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<slot />
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
document.addEventListener("scroll", (doc, evt) => {
|
||||||
|
console.log("SHIET");
|
||||||
|
});
|
||||||
|
</script>
|
|
@ -27,6 +27,7 @@ const posts = defineCollection({
|
||||||
tags: z.array(z.string()),
|
tags: z.array(z.string()),
|
||||||
draft: z.boolean().default(false),
|
draft: z.boolean().default(false),
|
||||||
math: z.boolean().default(false),
|
math: z.boolean().default(false),
|
||||||
|
toc: z.boolean().default(false),
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@ tags:
|
||||||
heroImage: ./header.jpg
|
heroImage: ./header.jpg
|
||||||
heroAlt: gears spinning wallpaper
|
heroAlt: gears spinning wallpaper
|
||||||
math: true
|
math: true
|
||||||
|
toc: true
|
||||||
---
|
---
|
||||||
|
|
||||||
Back in 2022, I took a special topics course, CSCI 8980, on [reasoning about
|
Back in 2022, I took a special topics course, CSCI 8980, on [reasoning about
|
||||||
|
|
|
@ -4,6 +4,7 @@ import BaseLayout from "../../layouts/BaseLayout.astro";
|
||||||
import { type CollectionEntry, getCollection } from "astro:content";
|
import { type CollectionEntry, getCollection } from "astro:content";
|
||||||
import Timestamp from "../../components/Timestamp.astro";
|
import Timestamp from "../../components/Timestamp.astro";
|
||||||
import { getImage } from "astro:assets";
|
import { getImage } from "astro:assets";
|
||||||
|
import TocWrapper from "../../components/TocWrapper.astro";
|
||||||
|
|
||||||
export async function getStaticPaths() {
|
export async function getStaticPaths() {
|
||||||
const posts = await getCollection("posts");
|
const posts = await getCollection("posts");
|
||||||
|
@ -16,8 +17,8 @@ export async function getStaticPaths() {
|
||||||
type Props = CollectionEntry<"posts">;
|
type Props = CollectionEntry<"posts">;
|
||||||
|
|
||||||
const post = Astro.props;
|
const post = Astro.props;
|
||||||
const { Content, remarkPluginFrontmatter } = await post.render();
|
const { Content, remarkPluginFrontmatter, headings } = await post.render();
|
||||||
const { heroImage: heroImagePath, heroAlt } = post.data;
|
const { toc, heroImage: heroImagePath, heroAlt } = post.data;
|
||||||
|
|
||||||
let heroImage;
|
let heroImage;
|
||||||
if (heroImagePath) {
|
if (heroImagePath) {
|
||||||
|
@ -44,44 +45,44 @@ const datestamp = post.data.date.toLocaleDateString(undefined, {
|
||||||
<meta slot="head" property="article:published_time" content={datestamp} />
|
<meta slot="head" property="article:published_time" content={datestamp} />
|
||||||
<meta slot="head" property="article:author" content="Michael Zhang" />
|
<meta slot="head" property="article:author" content="Michael Zhang" />
|
||||||
|
|
||||||
<div class="post-container">
|
<TocWrapper toc={toc} headings={headings}>
|
||||||
<h1 class="post-title">{post.data.title}</h1>
|
<div class="post-container">
|
||||||
|
<h1 class="post-title">{post.data.title}</h1>
|
||||||
|
|
||||||
|
<span class="tags">
|
||||||
|
{
|
||||||
|
post.data.draft && (
|
||||||
|
<a href="/drafts" class="tag draft">
|
||||||
|
<i class="fa fa-warning" aria-hidden="true" />
|
||||||
|
<span class="text">draft</span>
|
||||||
|
</a>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
post.data.tags.map((tag) => (
|
||||||
|
<a href={`/tags/${tag}`} class="tag">
|
||||||
|
<i class="fa fa-tag" aria-hidden="true" />
|
||||||
|
<span class="text">{tag}</span>
|
||||||
|
</a>
|
||||||
|
))
|
||||||
|
}
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<small class="post-meta">
|
||||||
|
Posted on <Timestamp timestamp={post.data.date} />
|
||||||
|
- {remarkPluginFrontmatter.minutesRead}
|
||||||
|
</small>
|
||||||
|
|
||||||
<span class="tags">
|
|
||||||
{
|
{
|
||||||
post.data.draft && (
|
heroImage && heroAlt && (
|
||||||
<a href="/drafts" class="tag draft">
|
<div style={`background-image: url(${heroImage.src});`} title={heroAlt} class="hero" />
|
||||||
<i class="fa fa-warning" aria-hidden="true" />
|
|
||||||
<span class="text">draft</span>
|
|
||||||
</a>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
<div class="post-content">
|
||||||
post.data.tags.map((tag) => (
|
<Content />
|
||||||
<a href={`/tags/${tag}`} class="tag">
|
</div>
|
||||||
<i class="fa fa-tag" aria-hidden="true" />
|
|
||||||
<span class="text">{tag}</span>
|
|
||||||
</a>
|
|
||||||
))
|
|
||||||
}
|
|
||||||
</span>
|
|
||||||
|
|
||||||
<small class="post-meta">
|
|
||||||
Posted on <Timestamp timestamp={post.data.date} />
|
|
||||||
- {remarkPluginFrontmatter.minutesRead}
|
|
||||||
</small>
|
|
||||||
|
|
||||||
{
|
|
||||||
heroImage && heroAlt && (
|
|
||||||
<div style={`background-image: url(${heroImage.src});`} title={heroAlt} class="hero" />
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
<!-- <BlogPost {...post.data}> -->
|
|
||||||
<div class="post-content">
|
|
||||||
<Content />
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</TocWrapper>
|
||||||
<!-- </BlogPost> -->
|
|
||||||
</BaseLayout>
|
</BaseLayout>
|
||||||
|
|
|
@ -12,7 +12,6 @@ body {
|
||||||
background-color: var(--background-color);
|
background-color: var(--background-color);
|
||||||
color: var(--text-color);
|
color: var(--text-color);
|
||||||
|
|
||||||
max-width: 1024px;
|
|
||||||
margin: auto;
|
margin: auto;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 1px;
|
height: 1px;
|
||||||
|
@ -94,12 +93,13 @@ pre > code {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
align-items: stretch;
|
align-items: stretch;
|
||||||
|
justify-content: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.flex-wrapper > main {
|
.flex-wrapper > main {
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
padding: 20px;
|
// padding: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media screen and (max-width: variables.$breakpoint) {
|
@media screen and (max-width: variables.$breakpoint) {
|
||||||
|
@ -120,6 +120,6 @@ pre > code {
|
||||||
}
|
}
|
||||||
|
|
||||||
.flex-wrapper > main {
|
.flex-wrapper > main {
|
||||||
padding-left: 30px;
|
// padding-left: 30px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
@use "variables";
|
||||||
|
|
||||||
.post-title {
|
.post-title {
|
||||||
font-size: 2rem;
|
font-size: 2rem;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
|
@ -20,7 +22,9 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.post-container {
|
.post-container {
|
||||||
|
max-width: 720px;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
padding: 20px;
|
||||||
|
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
.toc-drawer {
|
.toc-drawer {
|
||||||
|
@ -175,6 +179,12 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media screen and (min-width: variables.$breakpoint) {
|
||||||
|
.post-container {
|
||||||
|
padding-left: 30px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.division .post-content,
|
.division .post-content,
|
||||||
.post-content {
|
.post-content {
|
||||||
.heading {
|
.heading {
|
||||||
|
@ -210,6 +220,7 @@ hr.endline {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 6px;
|
gap: 6px;
|
||||||
margin-bottom: 6px;
|
margin-bottom: 6px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
|
||||||
.tag {
|
.tag {
|
||||||
font-size: 0.75rem;
|
font-size: 0.75rem;
|
||||||
|
|
44
src/styles/toc.scss
Normal file
44
src/styles/toc.scss
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
@use "variables";
|
||||||
|
$tocWidth: 180px;
|
||||||
|
$tocBreakpoint: variables.$breakpoint + $tocWidth;
|
||||||
|
|
||||||
|
.toc-wrapper {
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toc {
|
||||||
|
height: 100vh;
|
||||||
|
|
||||||
|
ul {
|
||||||
|
list-style-type: none;
|
||||||
|
padding-inline-start: 0;
|
||||||
|
|
||||||
|
li {
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (max-width: $tocBreakpoint) {
|
||||||
|
.toc {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (min-width: $tocBreakpoint) {
|
||||||
|
.article {
|
||||||
|
flex-grow: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toc {
|
||||||
|
flex: 0 0 $tocWidth;
|
||||||
|
max-width: $tocWidth;
|
||||||
|
|
||||||
|
position: sticky;
|
||||||
|
top: 0;
|
||||||
|
padding: 20px;
|
||||||
|
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue