aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Kagamino Lehoux <martin@lehoux.net>2026-06-14 16:44:29 +0200
committerMartin Kagamino Lehoux <martin@lehoux.net>2026-06-14 16:44:29 +0200
commitb07d4ff0dfe2267013e3be729b58fb2a83c2deb8 (patch)
tree447d336e4302205d0eb729f15ccddb9d224e127e
parent8a9ca0e0bac3284ecb8c028029380532a1978a9d (diff)
feat: Table of content
-rw-r--r--archetypes/posts.md4
-rw-r--r--assets/css/main.css85
-rw-r--r--layouts/_default/single.html2
-rw-r--r--layouts/partials/single/default.html2
-rw-r--r--layouts/partials/single/table-of-contents.html17
5 files changed, 91 insertions, 19 deletions
diff --git a/archetypes/posts.md b/archetypes/posts.md
index 5413dc2..2f66efc 100644
--- a/archetypes/posts.md
+++ b/archetypes/posts.md
@@ -2,10 +2,10 @@
title: "{{ replace .Name '-' ' ' | title }}"
date: {{ .Date }}
draft: true # Set 'false' to publish
-tableOfContents: false # Enable/disable Table of Contents
description: ''
+# tableOfContents: false # Uncomment to disable Table of Contents
categories:
- - Sem categoria
+ - Uncategorized
tags:
-
---
diff --git a/assets/css/main.css b/assets/css/main.css
index d34ea94..de8924b 100644
--- a/assets/css/main.css
+++ b/assets/css/main.css
@@ -480,35 +480,100 @@ button {
color: var(--color-error-text);
}
-/* Table of contents */
+/* ========================================
+ Table of Contents (collapsible + sticky)
+ ======================================== */
+
#content .table-of-contents {
+ position: sticky;
+ top: 1rem;
+ z-index: 10;
background-color: var(--color-bg-muted);
- color: var(--color-text);
- padding: 1rem;
border: 1px solid var(--color-border);
border-radius: 0.5rem;
+ margin-bottom: 1.25rem;
+ overflow: hidden;
+}
+
+#content .table-of-contents[open] {
+ padding: 0 1rem 0.75rem 1rem;
+}
+
+#content .toc-header {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ cursor: pointer;
+ list-style: none;
+ user-select: none;
+ font-weight: 700;
+ font-size: 0.875rem;
+ color: var(--color-heading);
+ padding: 0.65rem 1rem;
+ background-color: var(--color-bg-muted);
+ border-radius: 0.5rem;
+ transition: background-color 0.15s;
+}
+
+#content .table-of-contents[open] .toc-header {
+ border-bottom: 1px solid var(--color-border);
+ margin-bottom: 0.75rem;
+ padding-left: 0;
+ padding-right: 0;
+ border-radius: 0;
+}
+
+/* Hide default marker in Safari/Firefox */
+#content .toc-header::-webkit-details-marker {
+ display: none;
+}
+
+#content .toc-header:hover {
+ background-color: var(--color-bg-hover);
+}
+
+#content .table-of-contents[open] .toc-header:hover {
+ background-color: transparent;
+}
+
+#content .toc-chevron {
+ flex-shrink: 0;
+ transition: transform 0.2s ease;
+ color: var(--color-muted);
+}
+
+#content .table-of-contents[open] .toc-chevron {
+ transform: rotate(180deg);
}
#content .table-of-contents #TableOfContents ul {
- list-style-type: decimal;
- list-style-position: inside;
+ list-style: none;
+ margin-left: 0;
+ margin-bottom: 0;
+}
+
+#content .table-of-contents #TableOfContents ul ul {
margin-left: 1rem;
}
#content .table-of-contents #TableOfContents ul li {
- margin: 0.5rem 0;
- font-size: 1rem;
+ margin: 0.35rem 0;
+ font-size: 0.9rem;
+ line-height: 1.4;
}
#content .table-of-contents #TableOfContents ul li a {
font-weight: 400;
text-decoration: none;
- color: var(--color-text);
+ color: var(--color-muted);
+ display: block;
+ padding: 0.15rem 0;
+ transition: color 0.15s;
}
#content .table-of-contents #TableOfContents ul li a:hover {
+ color: var(--color-accent);
text-decoration: underline;
- color: var(--color-accent-hover);
}
/* Pagination button */
@@ -606,6 +671,7 @@ button {
.gap-1 { gap: 0.25rem; }
.gap-2 { gap: 0.5rem; }
.gap-3 { gap: 0.75rem; }
+.gap-4 { gap: 1rem; }
.gap-5 { gap: 1.25rem; }
.gap-7 { gap: 1.75rem; }
.gap-10 { gap: 2.5rem; }
@@ -665,6 +731,7 @@ button {
@media (min-width: 640px) {
.sm\:flex-row { flex-direction: row; }
+ .sm\:gap-4 { gap: 1rem; }
.sm\:gap-10 { gap: 2.5rem; }
.sm\:grid-cols-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.sm\:text-left { text-align: left; }
diff --git a/layouts/_default/single.html b/layouts/_default/single.html
index d20343b..d8ae6b6 100644
--- a/layouts/_default/single.html
+++ b/layouts/_default/single.html
@@ -1,6 +1,6 @@
{{ define "main" }}
-<article class="flex flex-col gap-10">
+<article class="flex flex-col gap-4">
<header class="flex flex-col gap-2">
<h2 class="title-large">{{ .Title }}</h2>
diff --git a/layouts/partials/single/default.html b/layouts/partials/single/default.html
index 25cda09..9b9b9c3 100644
--- a/layouts/partials/single/default.html
+++ b/layouts/partials/single/default.html
@@ -1,4 +1,4 @@
-<article class="flex flex-col gap-10">
+<article class="flex flex-col gap-4">
<header class="flex flex-col gap-2">
{{ partial "single/components/title/large" . }}
<div class="text-sm font-semibold text-gray-500 flex gap-3">
diff --git a/layouts/partials/single/table-of-contents.html b/layouts/partials/single/table-of-contents.html
index b8489bc..05689a1 100644
--- a/layouts/partials/single/table-of-contents.html
+++ b/layouts/partials/single/table-of-contents.html
@@ -1,6 +1,11 @@
-{{ if and .TableOfContents .Params.tableOfContents }}
- <aside class="table-of-contents">
- <h2 class="title-small">{{ i18n "summary" }}</h2>
- {{ .TableOfContents }}
- </aside>
-{{ end }} \ No newline at end of file
+{{ if and .TableOfContents (ne .Params.tableOfContents false) }}
+<details class="table-of-contents">
+ <summary class="toc-header">
+ <span>On this page</span>
+ <svg class="toc-chevron" width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
+ <polyline points="4 6 8 10 12 6" />
+ </svg>
+ </summary>
+ {{ .TableOfContents }}
+</details>
+{{ end }}