diff --git a/.editorconfig b/.editorconfig
index a384dc4..17feeda 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -1,3 +1,11 @@
[*.html]
indent_style = "space"
-indent_size = 4
\ No newline at end of file
+indent_size = 4
+
+[*.scss]
+indent_style = "space"
+indent_size = 4
+
+[*.js]
+indent_style = "space"
+indent_size = 2
\ No newline at end of file
diff --git a/assets/sass/researcher.scss b/assets/sass/researcher.scss
index 2066192..f708d4d 100644
--- a/assets/sass/researcher.scss
+++ b/assets/sass/researcher.scss
@@ -1,6 +1,7 @@
// Sizes
$max-width: {{ .Param "style.pageWidth" | default "750px;" }};
$avatar-size: {{ .Param "style.avatarSize" | default "90px;" }};
+$toc-width: {{ .Param "style.tocWidth" | default "350px;" }};
// Colors
$black: {{ .Param "style.colorBlack" | default "#222222" }};
@@ -48,9 +49,105 @@ $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;
+}
+.table-of-contents {
+ order: 0;
+ ul {
+ padding-left: 1.0rem !important;
+ & > li {
+ margin-left: 0.3em !important;
+ }
+ }
+
+ a.active {
+ font-weight: bold;
+ }
+
+ a:hover {
+ cursor: pointer;
+ }
+
+ @media(max-width: 578px) {
+ align-self: center;
+ }
+}
.container {
max-width: $max-width;
+ order: 1
}
+#title-large-screen {
+ display: none;
+}
+#title-small-screen {
+ margin-left: 15px !important;
+
+ @media(max-width: 578px) {
+ align-self: center;
+ }
+}
+
+@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);
+ }
+ #actual-content {
+ margin: 0;
+ }
+}
+
+@media(min-width: $toc-left-width) {
+ .root {
+ flex-direction: row;
+ }
+
+ .table-of-contents {
+ width: $toc-width;
+ order: 2;
+ position: sticky;
+ top: 0px;
+ padding: 1em;
+ align-self: start;
+ scrollbar-width: thin;
+
+ .table-of-contents-text {
+ overflow-x: hidden;
+ overflow-y: auto;
+ max-height: calc(100vh - 155px);
+ }
+
+ .hidden {
+ display: none;
+ }
+ }
+
+ #title-small-screen {
+ display: none;
+ }
+ #title-large-screen {
+ display: block;
+ }
+}
+
.navbar-brand {
@extend %link-dark;
font-size: 2rem;
diff --git a/config.toml b/config.toml
index 020e453..3614ddc 100644
--- a/config.toml
+++ b/config.toml
@@ -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
\ No newline at end of file
diff --git a/layouts/_default/single.html b/layouts/_default/single.html
index 140759a..443deaa 100644
--- a/layouts/_default/single.html
+++ b/layouts/_default/single.html
@@ -1,6 +1,18 @@
{{ define "main" }}
-
-
{{ .Title }}
- {{ .Content }}
+
+
{{ end }}
diff --git a/scripts/publish-configs.el b/scripts/publish-configs.el
index bf71c9c..42453e9 100644
--- a/scripts/publish-configs.el
+++ b/scripts/publish-configs.el
@@ -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"))
@@ -52,7 +55,11 @@
file))
file 'overwrite))
-;; (copy-directory (expand-file-name "~/dot-stats/img") "dot-stats/img" t t)
+(copy-directory
+ (expand-file-name
+ (format "%s/repos/dotfiles/dot-imgs/"
+ (vc-find-root default-directory ".git")))
+ "dot-imgs" t t)
(dolist (file my/config-files)
(with-temp-buffer
diff --git a/static/js/dynamic-toc.js b/static/js/dynamic-toc.js
new file mode 100644
index 0000000..2292873
--- /dev/null
+++ b/static/js/dynamic-toc.js
@@ -0,0 +1,121 @@
+const tocId = "TableOfContents";
+const actualContentId = "actual-content";
+let showAll = false;
+let currentActiveLinkId = null;
+let elemsToHide = [];
+let linksById = {};
+
+let headerObserver = null;
+
+function observeHeadings() {
+ const links = document.querySelectorAll(`#${tocId} a`);
+ const headings = document.querySelectorAll(`${actualContentId} h1,h2,h3,h4`);
+
+ 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) => {
+ for (const entry of entries) {
+ if (entry.isIntersecting && linksById[`#${entry.target.id}`]) {
+ currentActiveLinkId = `#${entry.target.id}`;
+ break;
+ }
+ }
+ if (currentActiveLinkId) {
+ for (const link of links) {
+ link.classList.remove("active");
+ }
+ linksById[currentActiveLinkId].classList.add("active");
+
+ if (!showAll) {
+ hideHeadings();
+ }
+ }
+ },
+ {
+ threshold: 0.1,
+ root: document.querySelector(`${actualContentId}`),
+ }
+ );
+
+ for (const heading of headings) {
+ headerObserver.observe(heading);
+ }
+ hideHeadings();
+}
+
+function observeButtons() {
+ const unhideButton = document.getElementById("unhide-all-button");
+ const hideButton = document.getElementById("hide-all-button");
+ unhideButton.addEventListener("click", () => {
+ showAll = true;
+ showHeadings();
+ unhideButton.classList.add("hidden");
+ hideButton.classList.remove("hidden");
+ });
+ hideButton.addEventListener("click", () => {
+ showAll = false;
+ hideHeadings();
+ hideButton.classList.add("hidden");
+ unhideButton.classList.remove("hidden");
+ });
+ unhideButton.classList.remove("hidden");
+}
+
+function hideHeadings() {
+ for (const elem of elemsToHide) {
+ elem.classList.add("hidden");
+ }
+ if (!currentActiveLinkId) {
+ return;
+ }
+ for (
+ let elem = linksById[currentActiveLinkId];
+ (elem = elem.parentElement);
+ elem.id !== tocId
+ ) {
+ elem.classList.remove("hidden");
+ }
+ for (const elem of linksById[currentActiveLinkId].parentElement.children) {
+ elem.classList.remove("hidden");
+ }
+}
+
+function showHeadings() {
+ for (const elem of elemsToHide) {
+ elem.classList.remove("hidden");
+ }
+}
+
+function setUpObserver() {
+ if (document.documentElement.clientWidth >= (750 + 350 + 25)) {
+ if (headerObserver === null) {
+ observeHeadings();
+ observeButtons();
+ }
+ } else {
+ if (headerObserver !== null) {
+ headerObserver.disconnect();
+ headerObserver = null;
+ showHeadings();
+ }
+ }
+}
+
+window.addEventListener("load", (event) => {
+ if ("IntersectionObserver" in window) {
+ setUpObserver();
+ window.addEventListener("resize", setUpObserver);
+ }
+});
+
+window.addEventListener("unload", (event) => {
+ headerObserver.disconnect();
+});