diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 11e01cb..d9c75cf 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -91,7 +91,7 @@ importers: specifier: ^2.13.0 version: 2.13.0 sharp: - specifier: ^0.33.5 + specifier: ^0.33.0 version: 0.33.5 svelte: specifier: ^4.2.19 @@ -889,28 +889,24 @@ packages: engines: {node: '>=14.21.3'} cpu: [arm64] os: [linux] - libc: [musl] '@biomejs/cli-linux-arm64@1.8.3': resolution: {integrity: sha512-fed2ji8s+I/m8upWpTJGanqiJ0rnlHOK3DdxsyVLZQ8ClY6qLuPc9uehCREBifRJLl/iJyQpHIRufLDeotsPtw==} engines: {node: '>=14.21.3'} cpu: [arm64] os: [linux] - libc: [glibc] '@biomejs/cli-linux-x64-musl@1.8.3': resolution: {integrity: sha512-UHrGJX7PrKMKzPGoEsooKC9jXJMa28TUSMjcIlbDnIO4EAavCoVmNQaIuUSH0Ls2mpGMwUIf+aZJv657zfWWjA==} engines: {node: '>=14.21.3'} cpu: [x64] os: [linux] - libc: [musl] '@biomejs/cli-linux-x64@1.8.3': resolution: {integrity: sha512-I8G2QmuE1teISyT8ie1HXsjFRz9L1m5n83U1O6m30Kw+kPMPSKjag6QGUn+sXT8V+XWIZxFFBoTDEDZW2KPDDw==} engines: {node: '>=14.21.3'} cpu: [x64] os: [linux] - libc: [glibc] '@biomejs/cli-win32-arm64@1.8.3': resolution: {integrity: sha512-J+Hu9WvrBevfy06eU1Na0lpc7uR9tibm9maHynLIoAjLZpQU3IW+OKHUtyL8p6/3pT2Ju5t5emReeIS2SAxhkQ==} @@ -1144,79 +1140,67 @@ packages: resolution: {integrity: sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA==} cpu: [arm64] os: [linux] - libc: [glibc] '@img/sharp-libvips-linux-arm@1.0.5': resolution: {integrity: sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g==} cpu: [arm] os: [linux] - libc: [glibc] '@img/sharp-libvips-linux-s390x@1.0.4': resolution: {integrity: sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA==} cpu: [s390x] os: [linux] - libc: [glibc] '@img/sharp-libvips-linux-x64@1.0.4': resolution: {integrity: sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw==} cpu: [x64] os: [linux] - libc: [glibc] '@img/sharp-libvips-linuxmusl-arm64@1.0.4': resolution: {integrity: sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA==} cpu: [arm64] os: [linux] - libc: [musl] '@img/sharp-libvips-linuxmusl-x64@1.0.4': resolution: {integrity: sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw==} cpu: [x64] os: [linux] - libc: [musl] '@img/sharp-linux-arm64@0.33.5': resolution: {integrity: sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [linux] - libc: [glibc] '@img/sharp-linux-arm@0.33.5': resolution: {integrity: sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm] os: [linux] - libc: [glibc] '@img/sharp-linux-s390x@0.33.5': resolution: {integrity: sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [s390x] os: [linux] - libc: [glibc] '@img/sharp-linux-x64@0.33.5': resolution: {integrity: sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [linux] - libc: [glibc] '@img/sharp-linuxmusl-arm64@0.33.5': resolution: {integrity: sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [linux] - libc: [musl] '@img/sharp-linuxmusl-x64@0.33.5': resolution: {integrity: sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [linux] - libc: [musl] '@img/sharp-wasm32@0.33.5': resolution: {integrity: sha512-ykUW4LVGaMcU9lu9thv85CbRMAwfeadCJHRsg2GmeRa/cJxsVY9Rbd57JcMxBkKHag5U/x7TSBpScF4U8ElVzg==} @@ -1393,55 +1377,46 @@ packages: resolution: {integrity: sha512-sWWgdQ1fq+XKrlda8PsMCfut8caFwZBmhYeoehJ05FdI0YZXk6ZyUjWLrIgbR/VgiGycrFKMMgp7eJ69HOF2pQ==} cpu: [arm] os: [linux] - libc: [glibc] '@rollup/rollup-linux-arm-musleabihf@4.21.1': resolution: {integrity: sha512-9OIiSuj5EsYQlmwhmFRA0LRO0dRRjdCVZA3hnmZe1rEwRk11Jy3ECGGq3a7RrVEZ0/pCsYWx8jG3IvcrJ6RCew==} cpu: [arm] os: [linux] - libc: [musl] '@rollup/rollup-linux-arm64-gnu@4.21.1': resolution: {integrity: sha512-0kuAkRK4MeIUbzQYu63NrJmfoUVicajoRAL1bpwdYIYRcs57iyIV9NLcuyDyDXE2GiZCL4uhKSYAnyWpjZkWow==} cpu: [arm64] os: [linux] - libc: [glibc] '@rollup/rollup-linux-arm64-musl@4.21.1': resolution: {integrity: sha512-/6dYC9fZtfEY0vozpc5bx1RP4VrtEOhNQGb0HwvYNwXD1BBbwQ5cKIbUVVU7G2d5WRE90NfB922elN8ASXAJEA==} cpu: [arm64] os: [linux] - libc: [musl] '@rollup/rollup-linux-powerpc64le-gnu@4.21.1': resolution: {integrity: sha512-ltUWy+sHeAh3YZ91NUsV4Xg3uBXAlscQe8ZOXRCVAKLsivGuJsrkawYPUEyCV3DYa9urgJugMLn8Z3Z/6CeyRQ==} cpu: [ppc64] os: [linux] - libc: [glibc] '@rollup/rollup-linux-riscv64-gnu@4.21.1': resolution: {integrity: sha512-BggMndzI7Tlv4/abrgLwa/dxNEMn2gC61DCLrTzw8LkpSKel4o+O+gtjbnkevZ18SKkeN3ihRGPuBxjaetWzWg==} cpu: [riscv64] os: [linux] - libc: [glibc] '@rollup/rollup-linux-s390x-gnu@4.21.1': resolution: {integrity: sha512-z/9rtlGd/OMv+gb1mNSjElasMf9yXusAxnRDrBaYB+eS1shFm6/4/xDH1SAISO5729fFKUkJ88TkGPRUh8WSAA==} cpu: [s390x] os: [linux] - libc: [glibc] '@rollup/rollup-linux-x64-gnu@4.21.1': resolution: {integrity: sha512-kXQVcWqDcDKw0S2E0TmhlTLlUgAmMVqPrJZR+KpH/1ZaZhLSl23GZpQVmawBQGVhyP5WXIsIQ/zqbDBBYmxm5w==} cpu: [x64] os: [linux] - libc: [glibc] '@rollup/rollup-linux-x64-musl@4.21.1': resolution: {integrity: sha512-CbFv/WMQsSdl+bpX6rVbzR4kAjSSBuDgCqb1l4J68UYsQNalz5wOqLGYj4ZI0thGpyX5kc+LLZ9CL+kpqDovZA==} cpu: [x64] os: [linux] - libc: [musl] '@rollup/rollup-win32-arm64-msvc@4.21.1': resolution: {integrity: sha512-3Q3brDgA86gHXWHklrwdREKIrIbxC0ZgU8lwpj0eEKGBQH+31uPqr0P2v11pn0tSIxHvcdOWxa4j+YvLNx1i6g==} @@ -3008,56 +2983,48 @@ packages: engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] - libc: [glibc] lightningcss-linux-arm64-gnu@1.26.0: resolution: {integrity: sha512-iJmZM7fUyVjH+POtdiCtExG+67TtPUTer7K/5A8DIfmPfrmeGvzfRyBltGhQz13Wi15K1lf2cPYoRaRh6vcwNA==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] - libc: [glibc] lightningcss-linux-arm64-musl@1.25.1: resolution: {integrity: sha512-IhxVFJoTW8wq6yLvxdPvyHv4NjzcpN1B7gjxrY3uaykQNXPHNIpChLB52+wfH+yS58zm1PL4LemUp8u9Cfp6Bw==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] - libc: [musl] lightningcss-linux-arm64-musl@1.26.0: resolution: {integrity: sha512-XxoEL++tTkyuvu+wq/QS8bwyTXZv2y5XYCMcWL45b8XwkiS8eEEEej9BkMGSRwxa5J4K+LDeIhLrS23CpQyfig==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] - libc: [musl] lightningcss-linux-x64-gnu@1.25.1: resolution: {integrity: sha512-RXIaru79KrREPEd6WLXfKfIp4QzoppZvD3x7vuTKkDA64PwTzKJ2jaC43RZHRt8BmyIkRRlmywNhTRMbmkPYpA==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] - libc: [glibc] lightningcss-linux-x64-gnu@1.26.0: resolution: {integrity: sha512-1dkTfZQAYLj8MUSkd6L/+TWTG8V6Kfrzfa0T1fSlXCXQHrt1HC1/UepXHtKHDt/9yFwyoeayivxXAsApVxn6zA==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] - libc: [glibc] lightningcss-linux-x64-musl@1.25.1: resolution: {integrity: sha512-TdcNqFsAENEEFr8fJWg0Y4fZ/nwuqTRsIr7W7t2wmDUlA8eSXVepeeONYcb+gtTj1RaXn/WgNLB45SFkz+XBZA==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] - libc: [musl] lightningcss-linux-x64-musl@1.26.0: resolution: {integrity: sha512-yX3Rk9m00JGCUzuUhFEojY+jf/6zHs3XU8S8Vk+FRbnr4St7cjyMXdNjuA2LjiT8e7j8xHRCH8hyZ4H/btRE4A==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] - libc: [musl] lightningcss-win32-arm64-msvc@1.26.0: resolution: {integrity: sha512-X/597/cFnCogy9VItj/+7Tgu5VLbAtDF7KZDPdSw0MaL6FL940th1y3HiOzFIlziVvAtbo0RB3NAae1Oofr+Tw==} diff --git a/src/components/GlobalStyles.astro b/src/components/GlobalStyles.astro index ce425af..f7d61ec 100644 --- a/src/components/GlobalStyles.astro +++ b/src/components/GlobalStyles.astro @@ -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)) }) @@ -242,6 +246,23 @@ color_set({ hover:decoration-[var(--link-hover)] active:decoration-[var(--link-active)] underline-offset-[0.25rem] } + .toc-hide, + .toc-not-ready { + @apply opacity-0 pointer-events-none + } + + #toc-inner-wrapper { + mask-image: linear-gradient(to bottom, transparent 0%, black 2rem, black calc(100% - 2rem), transparent 100%); + } + + .hide-scrollbar { + scrollbar-width: none; + -ms-overflow-style: none; + } + .hide-scrollbar::-webkit-scrollbar { + display: none; + } + .text-90 { @apply text-black/90 dark:text-white/90 } diff --git a/src/components/control/BackToTop.astro b/src/components/control/BackToTop.astro index 71bef8e..916d042 100644 --- a/src/components/control/BackToTop.astro +++ b/src/components/control/BackToTop.astro @@ -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) diff --git a/src/components/widget/SideBar.astro b/src/components/widget/SideBar.astro index ead29e5..7c3242c 100644 --- a/src/components/widget/SideBar.astro +++ b/src/components/widget/SideBar.astro @@ -18,13 +18,8 @@ const headings = Astro.props.headings
- diff --git a/src/components/widget/TOC.astro b/src/components/widget/TOC.astro index 57c8e90..364148a 100644 --- a/src/components/widget/TOC.astro +++ b/src/components/widget/TOC.astro @@ -1,30 +1,30 @@ --- -import WidgetLayout from './WidgetLayout.astro' import type { MarkdownHeading } from 'astro'; -import { i18n } from '../../i18n/translation' -import I18nKey from '../../i18n/i18nKey' -import ButtonLink from '../control/ButtonLink.astro' - interface Props { class?: string - style?: string headings: MarkdownHeading[] } -const { headings } = Astro.props; +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 style = Astro.props.style - -const COLLAPSED_HEIGHT = '7.5rem' -const COLLAPSE_THRESHOLD = 5 - -const isCollapsed = headings.length >= COLLAPSE_THRESHOLD - -const getMarginStyleFromHeading = (heading: MarkdownHeading) => { - return `margin-left: ${(heading.depth - 1) / 2}rem`; -} const removeTailingHash = (text: string) => { let lastIndexOfHash = text.lastIndexOf('#'); @@ -35,14 +35,26 @@ const removeTailingHash = (text: string) => { return text.substring(0, lastIndexOfHash); } +let heading1Count = 1; --- - - + {headings.filter((heading) => heading.depth <= minDepth + 1).map((heading) => + +
- {headings.map((heading) => -
- {removeTailingHash(heading.text)} -
+ {heading.depth == minDepth && heading1Count++} + {heading.depth == minDepth + 1 &&
} +
+
{removeTailingHash(heading.text)}
+
)} -
\ No newline at end of file + diff --git a/src/i18n/i18nKey.ts b/src/i18n/i18nKey.ts index d8211d9..e43eb93 100644 --- a/src/i18n/i18nKey.ts +++ b/src/i18n/i18nKey.ts @@ -8,7 +8,6 @@ enum I18nKey { categories = 'categories', recentPosts = 'recentPosts', - toc = 'toc', comments = 'comments', untitled = 'untitled', diff --git a/src/i18n/languages/en.ts b/src/i18n/languages/en.ts index dcd6bef..8aeaae5 100644 --- a/src/i18n/languages/en.ts +++ b/src/i18n/languages/en.ts @@ -11,7 +11,6 @@ export const en: Translation = { [Key.categories]: 'Categories', [Key.recentPosts]: 'Recent Posts', - [Key.toc]: 'TOC', [Key.comments]: 'Comments', [Key.untitled]: 'Untitled', diff --git a/src/i18n/languages/es.ts b/src/i18n/languages/es.ts index f63643a..24008e1 100644 --- a/src/i18n/languages/es.ts +++ b/src/i18n/languages/es.ts @@ -11,7 +11,6 @@ export const es: Translation = { [Key.categories]: 'Categorías', [Key.recentPosts]: 'Publicaciones recientes', - [Key.toc]: 'Índice', [Key.comments]: 'Comentarios', [Key.untitled]: 'Sin título', diff --git a/src/i18n/languages/ja.ts b/src/i18n/languages/ja.ts index 969b4a1..251f052 100644 --- a/src/i18n/languages/ja.ts +++ b/src/i18n/languages/ja.ts @@ -11,7 +11,6 @@ export const ja: Translation = { [Key.categories]: 'カテゴリ', [Key.recentPosts]: '最近の投稿', - [Key.toc]: '目次', [Key.comments]: 'コメント', [Key.untitled]: 'タイトルなし', diff --git a/src/i18n/languages/ko.ts b/src/i18n/languages/ko.ts index 2c26aad..c636d21 100644 --- a/src/i18n/languages/ko.ts +++ b/src/i18n/languages/ko.ts @@ -11,7 +11,6 @@ export const ko: Translation = { [Key.categories]: '카테고리', [Key.recentPosts]: '최근 게시물', - [Key.toc]: '목차', [Key.comments]: '댓글', [Key.untitled]: '제목 없음', diff --git a/src/i18n/languages/zh_CN.ts b/src/i18n/languages/zh_CN.ts index d6f857c..32c006e 100644 --- a/src/i18n/languages/zh_CN.ts +++ b/src/i18n/languages/zh_CN.ts @@ -11,7 +11,6 @@ export const zh_CN: Translation = { [Key.categories]: '分类', [Key.recentPosts]: '最新文章', - [Key.toc]: '目录', [Key.comments]: '评论', [Key.untitled]: '无标题', diff --git a/src/i18n/languages/zh_TW.ts b/src/i18n/languages/zh_TW.ts index 039450f..b5719d4 100644 --- a/src/i18n/languages/zh_TW.ts +++ b/src/i18n/languages/zh_TW.ts @@ -11,7 +11,6 @@ export const zh_TW: Translation = { [Key.categories]: '分類', [Key.recentPosts]: '最新文章', - [Key.toc]: '目錄', [Key.comments]: '評論', [Key.untitled]: '無標題', diff --git a/src/layouts/Layout.astro b/src/layouts/Layout.astro index f8b0fdf..2de032d 100644 --- a/src/layouts/Layout.astro +++ b/src/layouts/Layout.astro @@ -342,8 +342,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 @@ -374,6 +374,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 @@ -384,9 +390,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') } }); } @@ -397,6 +410,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) { @@ -407,6 +421,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 diff --git a/src/layouts/MainGridLayout.astro b/src/layouts/MainGridLayout.astro index bf54256..b532deb 100644 --- a/src/layouts/MainGridLayout.astro +++ b/src/layouts/MainGridLayout.astro @@ -7,6 +7,7 @@ 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 @@ -17,7 +18,7 @@ interface Props { headings? : MarkdownHeading[] } -const { title, banner, description, lang, setOGTypeArticle, headings } = 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 @@ -67,6 +68,17 @@ const hasBannerLink = !!siteConfig.banner.credit.url + + +
+
+
+
+ +
+
+
+