From c8fc0803e3bf6eddb3df85dc321970e0de1cae24 Mon Sep 17 00:00:00 2001 From: Helen Chong <119173961+helenclx@users.noreply.github.com> Date: Sat, 6 Apr 2024 14:18:12 +0800 Subject: [PATCH] Aff table of contents if the toc variable is truthy --- _site/assets/css/style-toc.css | 68 ++++++++++++++++++++++++++++++ _site/assets/css/toc.css | 68 ++++++++++++++++++++++++++++++ _site/assets/js/toc.js | 76 ++++++++++++++++++++++++++++++++++ _site/home/index.html | 3 ++ src/_includes/layouts/main.njk | 5 +++ src/assets/css/toc.css | 68 ++++++++++++++++++++++++++++++ src/assets/js/toc.js | 76 ++++++++++++++++++++++++++++++++++ 7 files changed, 364 insertions(+) create mode 100644 _site/assets/css/style-toc.css create mode 100644 _site/assets/css/toc.css create mode 100644 _site/assets/js/toc.js create mode 100644 src/assets/css/toc.css create mode 100644 src/assets/js/toc.js diff --git a/_site/assets/css/style-toc.css b/_site/assets/css/style-toc.css new file mode 100644 index 00000000..873e19f9 --- /dev/null +++ b/_site/assets/css/style-toc.css @@ -0,0 +1,68 @@ +/* Article Table of Contents */ +.toc { + background-color: var(--clr-quote-bg); + max-width: max-content; + padding: 1rem 1.3rem 0.3rem 1.3rem; + margin-top: 1rem; + outline: 1px solid var(--clr-title-border); + position: relative; + border-radius: 0.4rem; +} + +.toc-heading { + font-size: 1.1rem; + font-weight: 700; + margin-bottom: 0.5rem; + margin-right: 2rem; + cursor: pointer; +} + +.toc ol { + border-top: 1px solid var(--clr-title-border); + padding: 0.8em 0 0 1em; + line-height: 1.8; +} + +.toc ol ul { + list-style-type: disc; + line-height: 1.5; + padding-left: 1em; +} + +.toc a { + font-size: 1.1rem; + padding-left: 0.4rem; +} + +.toc ul a { + padding: 0; + font-size: 1rem; +} + +/* Sidebar Table of Contents */ +.sidebar__toc { + position: sticky; + top: 4rem; +} + +.sidebar__toc-title { + font-size: 1.3rem; + font-weight: bold; +} + +.sidebar__toc ol { + list-style: none; + margin-left: 0; + padding-left: 0; + font-size: 1rem; +} + +.sidebar__toc ol li { + margin-bottom: 0.5em; +} + +.sidebar__toc ol ul { + padding-top: 0.5em; + padding-left: 1.25rem; + list-style-type: disc; +} \ No newline at end of file diff --git a/_site/assets/css/toc.css b/_site/assets/css/toc.css new file mode 100644 index 00000000..873e19f9 --- /dev/null +++ b/_site/assets/css/toc.css @@ -0,0 +1,68 @@ +/* Article Table of Contents */ +.toc { + background-color: var(--clr-quote-bg); + max-width: max-content; + padding: 1rem 1.3rem 0.3rem 1.3rem; + margin-top: 1rem; + outline: 1px solid var(--clr-title-border); + position: relative; + border-radius: 0.4rem; +} + +.toc-heading { + font-size: 1.1rem; + font-weight: 700; + margin-bottom: 0.5rem; + margin-right: 2rem; + cursor: pointer; +} + +.toc ol { + border-top: 1px solid var(--clr-title-border); + padding: 0.8em 0 0 1em; + line-height: 1.8; +} + +.toc ol ul { + list-style-type: disc; + line-height: 1.5; + padding-left: 1em; +} + +.toc a { + font-size: 1.1rem; + padding-left: 0.4rem; +} + +.toc ul a { + padding: 0; + font-size: 1rem; +} + +/* Sidebar Table of Contents */ +.sidebar__toc { + position: sticky; + top: 4rem; +} + +.sidebar__toc-title { + font-size: 1.3rem; + font-weight: bold; +} + +.sidebar__toc ol { + list-style: none; + margin-left: 0; + padding-left: 0; + font-size: 1rem; +} + +.sidebar__toc ol li { + margin-bottom: 0.5em; +} + +.sidebar__toc ol ul { + padding-top: 0.5em; + padding-left: 1.25rem; + list-style-type: disc; +} \ No newline at end of file diff --git a/_site/assets/js/toc.js b/_site/assets/js/toc.js new file mode 100644 index 00000000..f09cd89d --- /dev/null +++ b/_site/assets/js/toc.js @@ -0,0 +1,76 @@ +// Auto generate table of contents +// Code based on https://techindetail.com/table-of-contents-javascript/ +window.addEventListener('DOMContentLoaded', (event) => { + const article = document.querySelector("article"); + const headings = article.querySelectorAll("h2, h3"); + const toc = document.querySelector(".toc"); + const tocSidebar = document.querySelector(".sidebar__toc"); + const leftSidebar = document.querySelector('.left-sidebar'); + const totalHeadings = headings.length; + let tocOl = document.createElement("ol"); + let tocFragment = new DocumentFragment(); + let mainLi = null; + let subUl = null; + let subLi = null; + let isSibling = false; + + if (totalHeadings > 1) { + for (let element of headings) { + let anchor = document.createElement("a"); + let anchorText = element.innerText; + anchor.innerText = anchorText; + let elementId = anchorText.replaceAll(" ", "-").toLowerCase(); + anchor.href = "#" + elementId; + element.id = elementId; + let level = element.nodeName; + + if ("H3" === level) { + if (mainLi) { + subLi = document.createElement("li"); + subLi.appendChild(anchor); + + if (isSibling === false) { + subUl = document.createElement("ul"); + } + subUl.appendChild(subLi); + mainLi.appendChild(subUl); + + isSibling = true; + } + } else { + mainLi = document.createElement("li"); + mainLi.appendChild(anchor); + tocFragment.appendChild(mainLi); + isSibling = false; + subUl = null; + } + } + tocOl.append(tocFragment); + toc.append(tocOl); + + const tocClone = tocOl.cloneNode(true); + if (tocSidebar) { + tocSidebar.appendChild(tocClone); + } + } else { + toc.classList.add('hidden'); + leftSidebar.classList.add('hidden'); + } + + // Close article ToC accordion and the left sidebar for small screen sizes + if (window.innerWidth < 480) { + toc.removeAttribute("open"); + leftSidebar.classList.add("hidden"); + } else { + toc.setAttribute("open", true); + } + + // Remove the stickiness of the sidebar ToC if it is larger than screen height + function preventSidebarOverflow() { + if (document.documentElement.clientHeight < tocSidebar.offsetHeight + 50) { + tocSidebar.style.marginTop = "0"; + tocSidebar.style.position = "static"; + } + } + preventSidebarOverflow(); +}); \ No newline at end of file diff --git a/_site/home/index.html b/_site/home/index.html index db8418a9..fc9a4656 100644 --- a/_site/home/index.html +++ b/_site/home/index.html @@ -14,6 +14,7 @@ + @@ -25,6 +26,7 @@ + @@ -33,6 +35,7 @@ + Home | Leilukin's Hub diff --git a/src/_includes/layouts/main.njk b/src/_includes/layouts/main.njk index b9dd4049..a41ad78b 100644 --- a/src/_includes/layouts/main.njk +++ b/src/_includes/layouts/main.njk @@ -14,10 +14,14 @@ {# CSS #} + {% if toc %} + + {% endif %} {# CDNs #} {% include "components/cdn.njk" %} + {# Favicon #} @@ -26,6 +30,7 @@ {# JavaScript #} + {% if toc %} {% endif %} {{ title }} | Leilukin's Hub diff --git a/src/assets/css/toc.css b/src/assets/css/toc.css new file mode 100644 index 00000000..873e19f9 --- /dev/null +++ b/src/assets/css/toc.css @@ -0,0 +1,68 @@ +/* Article Table of Contents */ +.toc { + background-color: var(--clr-quote-bg); + max-width: max-content; + padding: 1rem 1.3rem 0.3rem 1.3rem; + margin-top: 1rem; + outline: 1px solid var(--clr-title-border); + position: relative; + border-radius: 0.4rem; +} + +.toc-heading { + font-size: 1.1rem; + font-weight: 700; + margin-bottom: 0.5rem; + margin-right: 2rem; + cursor: pointer; +} + +.toc ol { + border-top: 1px solid var(--clr-title-border); + padding: 0.8em 0 0 1em; + line-height: 1.8; +} + +.toc ol ul { + list-style-type: disc; + line-height: 1.5; + padding-left: 1em; +} + +.toc a { + font-size: 1.1rem; + padding-left: 0.4rem; +} + +.toc ul a { + padding: 0; + font-size: 1rem; +} + +/* Sidebar Table of Contents */ +.sidebar__toc { + position: sticky; + top: 4rem; +} + +.sidebar__toc-title { + font-size: 1.3rem; + font-weight: bold; +} + +.sidebar__toc ol { + list-style: none; + margin-left: 0; + padding-left: 0; + font-size: 1rem; +} + +.sidebar__toc ol li { + margin-bottom: 0.5em; +} + +.sidebar__toc ol ul { + padding-top: 0.5em; + padding-left: 1.25rem; + list-style-type: disc; +} \ No newline at end of file diff --git a/src/assets/js/toc.js b/src/assets/js/toc.js new file mode 100644 index 00000000..f09cd89d --- /dev/null +++ b/src/assets/js/toc.js @@ -0,0 +1,76 @@ +// Auto generate table of contents +// Code based on https://techindetail.com/table-of-contents-javascript/ +window.addEventListener('DOMContentLoaded', (event) => { + const article = document.querySelector("article"); + const headings = article.querySelectorAll("h2, h3"); + const toc = document.querySelector(".toc"); + const tocSidebar = document.querySelector(".sidebar__toc"); + const leftSidebar = document.querySelector('.left-sidebar'); + const totalHeadings = headings.length; + let tocOl = document.createElement("ol"); + let tocFragment = new DocumentFragment(); + let mainLi = null; + let subUl = null; + let subLi = null; + let isSibling = false; + + if (totalHeadings > 1) { + for (let element of headings) { + let anchor = document.createElement("a"); + let anchorText = element.innerText; + anchor.innerText = anchorText; + let elementId = anchorText.replaceAll(" ", "-").toLowerCase(); + anchor.href = "#" + elementId; + element.id = elementId; + let level = element.nodeName; + + if ("H3" === level) { + if (mainLi) { + subLi = document.createElement("li"); + subLi.appendChild(anchor); + + if (isSibling === false) { + subUl = document.createElement("ul"); + } + subUl.appendChild(subLi); + mainLi.appendChild(subUl); + + isSibling = true; + } + } else { + mainLi = document.createElement("li"); + mainLi.appendChild(anchor); + tocFragment.appendChild(mainLi); + isSibling = false; + subUl = null; + } + } + tocOl.append(tocFragment); + toc.append(tocOl); + + const tocClone = tocOl.cloneNode(true); + if (tocSidebar) { + tocSidebar.appendChild(tocClone); + } + } else { + toc.classList.add('hidden'); + leftSidebar.classList.add('hidden'); + } + + // Close article ToC accordion and the left sidebar for small screen sizes + if (window.innerWidth < 480) { + toc.removeAttribute("open"); + leftSidebar.classList.add("hidden"); + } else { + toc.setAttribute("open", true); + } + + // Remove the stickiness of the sidebar ToC if it is larger than screen height + function preventSidebarOverflow() { + if (document.documentElement.clientHeight < tocSidebar.offsetHeight + 50) { + tocSidebar.style.marginTop = "0"; + tocSidebar.style.position = "static"; + } + } + preventSidebarOverflow(); +}); \ No newline at end of file