mirror of
https://github.com/SqrtMinusOne/sqrtminusone.github.io.git
synced 2025-12-10 07:43:03 +03:00
feat(toc): dynamic heading
This commit is contained in:
parent
598050748c
commit
fb5996755b
6 changed files with 107 additions and 22 deletions
|
|
@ -4,4 +4,8 @@ indent_size = 4
|
|||
|
||||
[*.scss]
|
||||
indent_style = "space"
|
||||
indent_size = 4
|
||||
indent_size = 4
|
||||
|
||||
[*.js]
|
||||
indent_style = "space"
|
||||
indent_size = 2
|
||||
|
|
@ -49,30 +49,26 @@ $y-medium: 1.0rem;
|
|||
font-family: $font-family;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
$toc-left-width: $toc-width + $max-width + 25px;
|
||||
|
||||
.root {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
@media(max-width: $toc-width + $max-width) {
|
||||
margin-right: auto;
|
||||
margin-left: auto;
|
||||
width: 100%;
|
||||
max-width: $max-width;
|
||||
}
|
||||
}
|
||||
.table-of-contents {
|
||||
order: 0;
|
||||
@media(max-width: $toc-width + $max-width) {
|
||||
padding-left: 15px;
|
||||
padding-right: 15px;
|
||||
}
|
||||
|
||||
ul {
|
||||
padding-left: 1.0rem !important;
|
||||
& > li {
|
||||
margin-left: 0.3em !important;
|
||||
}
|
||||
}
|
||||
|
||||
a.active {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
@media(max-width: 578px) {
|
||||
align-self: center;
|
||||
}
|
||||
|
|
@ -92,16 +88,30 @@ $y-medium: 1.0rem;
|
|||
}
|
||||
}
|
||||
|
||||
@media (max-width: $toc-left-width) {
|
||||
.root {
|
||||
margin-right: auto;
|
||||
margin-left: auto;
|
||||
width: 100%;
|
||||
max-width: $max-width;
|
||||
}
|
||||
|
||||
.table-of-contents {
|
||||
padding-left: 15px;
|
||||
padding-right: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: $toc-width * 1.5 + $max-width) {
|
||||
.root {
|
||||
margin-left: calc((100vw - 750px) / 2);
|
||||
}
|
||||
.content {
|
||||
#actual-content {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@media(min-width: $toc-width + $max-width + 25px) {
|
||||
@media(min-width: $toc-left-width) {
|
||||
.root {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
|
@ -114,19 +124,16 @@ $y-medium: 1.0rem;
|
|||
padding: 1em;
|
||||
align-self: start;
|
||||
scrollbar-width: thin;
|
||||
// flex-grow: 1;
|
||||
|
||||
.table-of-contents-text {
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
max-height: calc(100vh - 155px);
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
.content {
|
||||
// flex-grow: 1;
|
||||
.hidden {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
#title-small-screen {
|
||||
|
|
|
|||
|
|
@ -45,6 +45,8 @@ staticDir = ["static"]
|
|||
noHl = false
|
||||
style = 'pygments'
|
||||
tabWidth = 4
|
||||
[markup.tableOfContents]
|
||||
endLevel = 4
|
||||
|
||||
[markup.goldmark.renderer]
|
||||
unsafe = true # allow raw HTML in markdown files
|
||||
|
|
@ -1,7 +1,8 @@
|
|||
{{ define "main" }}
|
||||
<script defer language="javascript" type="text/javascript" src="{{ "/js/dynamic-toc.js" | urlize | relURL }}"></script>
|
||||
<div class="root">
|
||||
<h1 id="title-small-screen">{{ .Title }}</h1>
|
||||
<div class="container content">
|
||||
<div class="container" id="actual-content">
|
||||
<h1 id="title-large-screen">{{ .Title }}</h1>
|
||||
{{ .Content }}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -31,6 +31,9 @@
|
|||
:ensure t)
|
||||
|
||||
(setq org-make-toc-link-type-fn #'org-make-toc--link-entry-org)
|
||||
(setq org-hugo-anchor-functions '(org-hugo-get-page-or-bundle-name
|
||||
org-hugo-get-custom-id
|
||||
org-hugo-get-md5))
|
||||
|
||||
(setq org-hugo-section "configs")
|
||||
(setq org-hugo-base-dir (vc-find-root default-directory ".git"))
|
||||
|
|
|
|||
68
static/js/dynamic-toc.js
Normal file
68
static/js/dynamic-toc.js
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
const tocId = "TableOfContents";
|
||||
const actualContentId = "actual-content";
|
||||
let headerObserver;
|
||||
|
||||
function observeHeadings() {
|
||||
const links = document.querySelectorAll(`#${tocId} a`);
|
||||
const headings = document.querySelectorAll(`${actualContentId} h1,h2,h3,h4`);
|
||||
const elemsToHide = [];
|
||||
const linksById = {};
|
||||
|
||||
for (const link of links) {
|
||||
linksById[link.getAttribute("href")] = link;
|
||||
}
|
||||
for (const elem of document.querySelectorAll(`#${tocId} ul`)) {
|
||||
if (elem.parentElement.id !== tocId) {
|
||||
elemsToHide.push(elem);
|
||||
}
|
||||
}
|
||||
|
||||
headerObserver = new IntersectionObserver(
|
||||
(entries) => {
|
||||
let newActiveLinkId;
|
||||
for (const entry of entries) {
|
||||
if (entry.isIntersecting && linksById[`#${entry.target.id}`]) {
|
||||
newActiveLinkId = `#${entry.target.id}`;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (newActiveLinkId) {
|
||||
for (const link of links) {
|
||||
link.classList.remove("active");
|
||||
}
|
||||
for (const elem of elemsToHide) {
|
||||
elem.classList.add("hidden");
|
||||
}
|
||||
linksById[newActiveLinkId].classList.add("active");
|
||||
for (
|
||||
let elem = linksById[newActiveLinkId];
|
||||
(elem = elem.parentElement);
|
||||
elem.id !== tocId
|
||||
) {
|
||||
elem.classList.remove("hidden");
|
||||
}
|
||||
for (const elem of linksById[newActiveLinkId].parentElement.children) {
|
||||
elem.classList.remove("hidden");
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
threshold: 0.1,
|
||||
root: document.querySelector(`${actualContentId}`),
|
||||
}
|
||||
);
|
||||
|
||||
for (const heading of headings) {
|
||||
headerObserver.observe(heading);
|
||||
}
|
||||
}
|
||||
|
||||
window.addEventListener("load", (event) => {
|
||||
if ("IntersectionObserver" in window) {
|
||||
observeHeadings();
|
||||
}
|
||||
});
|
||||
|
||||
window.addEventListener("unload", (event) => {
|
||||
headerObserver.disconnect();
|
||||
});
|
||||
Loading…
Add table
Reference in a new issue