Merge branch 'toc-new'

# Conflicts:
#	astro.config.mjs
#	pnpm-lock.yaml
#	src/components/GlobalStyles.astro
This commit is contained in:
saicaca
2024-10-26 16:02:43 +08:00
9 changed files with 243 additions and 274 deletions

View File

@@ -120,6 +120,10 @@ color_set({
--admonitions-color-important: oklch(0.7 0.14 310) oklch(0.75 0.14 310)
--admonitions-color-warning: oklch(0.7 0.14 60) oklch(0.75 0.14 60)
--admonitions-color-caution: oklch(0.6 0.2 25) oklch(0.65 0.2 25)
--toc-badge-bg: oklch(0.9 0.045 var(--hue)) var(--btn-regular-bg)
--toc-btn-hover: oklch(0.92 0.015 var(--hue)) oklch(0.22 0.02 var(--hue))
--toc-btn-active: oklch(0.90 0.015 var(--hue)) oklch(0.25 0.02 var(--hue))
})

View File

@@ -25,7 +25,7 @@ import { Icon } from 'astro-icon/components'
font-weight: bold
border: none
position: fixed
bottom: 15rem
bottom: 10rem
opacity: 1
cursor: pointer
transform: translateX(5rem)

View File

@@ -2,8 +2,17 @@
import Profile from './Profile.astro'
import Tag from './Tags.astro'
import Categories from './Categories.astro'
import type { MarkdownHeading } from 'astro'
import TOC from './TOC.astro'
interface Props {
class? : string
headings? : MarkdownHeading[]
}
const className = Astro.props.class
const headings = Astro.props.headings
---
<div id="sidebar" class:list={[className, "w-full"]}>
<div class="flex flex-col w-full gap-4 mb-4">

View File

@@ -0,0 +1,60 @@
---
import type { MarkdownHeading } from 'astro';
interface Props {
class?: string
headings: MarkdownHeading[]
}
const { headings = [] } = Astro.props;
// generate random headings, for testing
/*
for (let i = 0; i < 50; i++) {
headings.push({
text: `Heading ${i + 1}`,
depth: Math.floor(Math.random() * 3) + 1,
slug: `heading-${i + 1}`
})
}
*/
let minDepth = 10;
for (const heading of headings) {
minDepth = Math.min(minDepth, heading.depth);
}
const className = Astro.props.class
const removeTailingHash = (text: string) => {
let lastIndexOfHash = text.lastIndexOf('#');
if (lastIndexOfHash != text.length - 1) {
return text;
}
return text.substring(0, lastIndexOfHash);
}
let heading1Count = 1;
---
<div class:list={[className]}>
{headings.filter((heading) => heading.depth <= minDepth + 1).map((heading) =>
<a href={`#${heading.slug}`} class="px-2 transition flex w-full gap-2 h-9 rounded-xl items-center
hover:bg-[var(--toc-btn-hover)] active:bg-[var(--toc-btn-active)]
">
<div class:list={["w-5 h-5 rounded-lg text-xs flex items-center justify-center font-bold",
{
"bg-[var(--toc-badge-bg)] text-[var(--btn-content)]": heading.depth == minDepth,
}
]}
>
{heading.depth == minDepth && heading1Count++}
{heading.depth == minDepth + 1 && <div class="w-1.5 h-1.5 rounded-sm bg-black/5 dark:bg-white/5"></div>}
</div>
<div class:list={["text-sm", {
"text-50": heading.depth == minDepth,
"text-30": heading.depth == minDepth + 1,
}]}>{removeTailingHash(heading.text)}</div>
</a>
)}
</div>

View File

@@ -343,8 +343,8 @@ const setup = () => {
}
})
*/
// Remove the delay for the first time page load
window.swup.hooks.on('link:click', () => {
// Remove the delay for the first time page load
document.documentElement.style.setProperty('--content-delay', '0ms')
// prevent elements from overlapping the navbar
@@ -375,6 +375,12 @@ const setup = () => {
if (heightExtend) {
heightExtend.classList.remove('hidden')
}
// Hide the TOC while scrolling back to top
let toc = document.getElementById('toc-wrapper');
if (toc) {
toc.classList.add('toc-not-ready')
}
});
window.swup.hooks.on('page:view', () => {
// hide the temp high element when the transition is done
@@ -385,9 +391,16 @@ const setup = () => {
});
window.swup.hooks.on('visit:end', (visit: {to: {url: string}}) => {
// execute 1s later
const heightExtend = document.getElementById('page-height-extend')
if (heightExtend) {
heightExtend.classList.add('hidden')
setTimeout(() => {
const heightExtend = document.getElementById('page-height-extend')
if (heightExtend) {
heightExtend.classList.add('hidden')
}
}, 200)
const toc = document.getElementById('toc-wrapper');
if (toc) {
toc.classList.remove('toc-not-ready')
}
});
}
@@ -398,6 +411,7 @@ if (window?.swup?.hooks) {
}
let backToTopBtn = document.getElementById('back-to-top-btn');
let toc = document.getElementById('toc-wrapper');
let navbar = document.getElementById('navbar-wrapper')
function scrollFunction() {
if (backToTopBtn) {
@@ -408,6 +422,14 @@ function scrollFunction() {
}
}
if (toc) {
if (document.body.scrollTop > 600 || document.documentElement.scrollTop > 600) {
toc.classList.remove('toc-hide')
} else {
toc.classList.add('toc-hide')
}
}
if (!bannerEnabled) return
if (navbar) {
let threshold = window.innerHeight * 0.30 - 72 - 16

View File

@@ -6,6 +6,8 @@ import SideBar from '@components/widget/SideBar.astro'
import Layout from './Layout.astro'
import { Icon } from 'astro-icon/components'
import { siteConfig } from '../config'
import type { MarkdownHeading } from 'astro'
import TOC from "../components/widget/TOC.astro";
interface Props {
title?: string
@@ -13,9 +15,10 @@ interface Props {
description?: string
lang?: string
setOGTypeArticle?: boolean;
headings? : MarkdownHeading[]
}
const { title, banner, description, lang, setOGTypeArticle } = Astro.props
const { title, banner, description, lang, setOGTypeArticle, headings = [] } = Astro.props
const hasBannerCredit =
siteConfig.banner.enable && siteConfig.banner.credit.enable
const hasBannerLink = !!siteConfig.banner.credit.url
@@ -48,7 +51,7 @@ const hasBannerLink = !!siteConfig.banner.credit.url
</a>}
<SideBar class="mb-4 row-start-2 row-end-3 col-span-2 lg:row-start-1 lg:row-end-2 lg:col-span-1 lg:max-w-[17.5rem] onload-animation"></SideBar>
<SideBar class="mb-4 row-start-2 row-end-3 col-span-2 lg:row-start-1 lg:row-end-2 lg:col-span-1 lg:max-w-[17.5rem] onload-animation" headings={headings}></SideBar>
<main id="swup-container" class="transition-swup-fade col-span-2 lg:col-span-1 overflow-hidden">
<div id="content-wrapper" class="onload-animation">
@@ -65,6 +68,17 @@ const hasBannerLink = !!siteConfig.banner.credit.url
<Footer></Footer>
</div>
</div>
<!-- TOC component -->
<div id="toc-wrapper" class="transition absolute top-0 -right-[30rem] w-[30rem] flex items-center toc-hide">
<div id="toc-inner-wrapper" class="fixed top-14 w-96 h-[calc(100vh_-_20rem)] overflow-y-scroll overflow-x-hidden hide-scrollbar">
<div id="toc" class="w-full h-full transition-swup-fade">
<div class="h-8 w-full"></div>
<TOC headings={headings}></TOC>
<div class="h-8 w-full"></div>
</div>
</div>
</div>
<BackToTop></BackToTop>
</div>
</div>

View File

@@ -25,7 +25,7 @@ export async function getStaticPaths() {
}
const { entry } = Astro.props
const { Content } = await entry.render()
const { Content, headings } = await entry.render()
const { remarkPluginFrontmatter } = await entry.render()
@@ -45,7 +45,7 @@ const jsonLd = {
// TODO include cover image here
}
---
<MainGridLayout banner={entry.data.image} title={entry.data.title} description={entry.data.description} lang={entry.data.lang} setOGTypeArticle={true}>
<MainGridLayout banner={entry.data.image} title={entry.data.title} description={entry.data.description} lang={entry.data.lang} setOGTypeArticle={true} headings={headings}>
<script is:inline slot="head" type="application/ld+json" set:html={JSON.stringify(jsonLd)}></script>
<div class="flex w-full rounded-[var(--radius-large)] overflow-hidden relative mb-4">
<div id="post-container" class:list={["card-base z-10 px-6 md:px-9 pt-6 pb-4 relative w-full ",