Skip to content

Commit 61b4fea

Browse files
authored
Merge pull request #28 from DecimalTurn/toc
Update layout and logo
2 parents d247d1b + eece8f1 commit 61b4fea

7 files changed

Lines changed: 367 additions & 20 deletions

File tree

_layouts/default.html

Lines changed: 105 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -26,30 +26,127 @@
2626
</svg>
2727
</a>
2828
{% endif %}
29-
<a class="header-logo-link" href="{{ '/' | relative_url }}" aria-label="JSONC home">
30-
<img class="header-logo" src="{{ '/assets/logo.png' | relative_url }}" alt="JSONC logo">
31-
</a>
32-
<h1 class="project-name">{{ page.title | default: site.title | default: site.github.repository_name }}</h1>
33-
<h2 class="project-tagline">{{ page.description | default: site.description | default: site.github.project_tagline }}</h2>
29+
<div class="header-inner">
30+
<a class="header-logo-link" href="{{ '/' | relative_url }}" aria-label="JSONC home">
31+
<img class="header-logo" src="{{ '/assets/logo.png' | relative_url }}" alt="JSONC logo">
32+
</a>
33+
<h1 class="project-name">{{ page.title | default: site.title | default: site.github.repository_name }}</h1>
34+
</div>
3435
{% if site.show_downloads %}
3536
<a href="{{ site.github.zip_url }}" class="btn">Download .zip</a>
3637
<a href="{{ site.github.tar_url }}" class="btn">Download .tar.gz</a>
3738
{% endif %}
3839
</header>
3940

40-
<main id="content" class="main-content" role="main">
41-
{{ content }}
41+
<button class="toc-toggle" aria-label="Open table of contents" aria-expanded="false" aria-controls="toc">
42+
<span class="toc-toggle-bar"></span>
43+
<span class="toc-toggle-bar"></span>
44+
<span class="toc-toggle-bar"></span>
45+
</button>
46+
<div class="toc-backdrop" aria-hidden="true"></div>
47+
48+
<div class="page-body">
49+
<nav id="toc" class="toc-sidebar" aria-label="Table of contents">
50+
<div class="toc-inner">
51+
<p class="toc-title">Contents</p>
52+
<ol class="toc-list"></ol>
53+
</div>
54+
</nav>
55+
56+
<main id="content" class="main-content" role="main">
57+
{{ content }}
4258

4359
<footer class="site-footer">
4460
{% if site.github.is_project_page %}
4561
<span class="site-footer-owner"><a href="{{ site.github.repository_url }}">{{ site.github.repository_name }}</a> is maintained by <a href="{{ site.github.owner_url }}">{{ site.github.owner_name }}</a>.</span>
4662
{% endif %}
4763
<span class="site-footer-credits">This page was generated by <a href="https://pages.github.com">GitHub Pages</a>.</span>
4864
</footer>
49-
</main>
65+
</main>
66+
</div>
5067
</body>
5168
<script>hljs.highlightAll();</script>
5269

70+
<!-- TOC burger toggle -->
71+
<script>
72+
(function () {
73+
var btn = document.querySelector('.toc-toggle');
74+
var toc = document.getElementById('toc');
75+
var backdrop = document.querySelector('.toc-backdrop');
76+
function openToc() {
77+
toc.classList.add('toc-open');
78+
backdrop.classList.add('toc-backdrop-visible');
79+
btn.setAttribute('aria-expanded', 'true');
80+
document.body.style.overflow = 'hidden';
81+
}
82+
function closeToc() {
83+
toc.classList.remove('toc-open');
84+
backdrop.classList.remove('toc-backdrop-visible');
85+
btn.setAttribute('aria-expanded', 'false');
86+
document.body.style.overflow = '';
87+
}
88+
btn.addEventListener('click', function () {
89+
toc.classList.contains('toc-open') ? closeToc() : openToc();
90+
});
91+
backdrop.addEventListener('click', closeToc);
92+
toc.addEventListener('click', function (e) {
93+
if (e.target.tagName === 'A') closeToc();
94+
});
95+
})();
96+
</script>
97+
98+
<!-- Table of Contents -->
99+
<script>
100+
(function () {
101+
const headings = document.querySelectorAll('.main-content h2, .main-content h3');
102+
const tocList = document.querySelector('.toc-list');
103+
if (!tocList || headings.length === 0) return;
104+
105+
let currentH2Item = null;
106+
headings.forEach(function (heading) {
107+
if (!heading.id) {
108+
heading.id = heading.textContent.trim().toLowerCase()
109+
.replace(/[^\w\s-]/g, '').replace(/\s+/g, '-');
110+
}
111+
const link = document.createElement('a');
112+
link.href = '#' + heading.id;
113+
link.textContent = heading.textContent;
114+
115+
const li = document.createElement('li');
116+
li.appendChild(link);
117+
118+
if (heading.tagName === 'H2') {
119+
li.classList.add('toc-h2');
120+
tocList.appendChild(li);
121+
currentH2Item = li;
122+
} else {
123+
li.classList.add('toc-h3');
124+
let subList = currentH2Item && currentH2Item.querySelector('ol');
125+
if (!subList) {
126+
subList = document.createElement('ol');
127+
if (currentH2Item) currentH2Item.appendChild(subList);
128+
else tocList.appendChild(subList);
129+
}
130+
subList.appendChild(li);
131+
}
132+
});
133+
134+
// Highlight active section on scroll
135+
const allLinks = tocList.querySelectorAll('a');
136+
const observer = new IntersectionObserver(function (entries) {
137+
entries.forEach(function (entry) {
138+
if (entry.isIntersecting) {
139+
allLinks.forEach(function (a) { a.classList.remove('toc-active'); });
140+
const active = tocList.querySelector('a[href="#' + entry.target.id + '"]');
141+
if (active) active.classList.add('toc-active');
142+
}
143+
});
144+
}, { rootMargin: '0px 0px -80% 0px' });
145+
146+
headings.forEach(function (h) { observer.observe(h); });
147+
})();
148+
</script>
149+
53150
<!-- Invalid syntax highlighting-->
54151
<script>
55152
function markInvalidNumbers(codeBlock) {

assets/css/style.scss

Lines changed: 214 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,37 @@
33

44
@import 'jekyll-theme-cayman';
55

6+
body {
7+
font-family: Arial, sans-serif;
8+
}
9+
610
.page-header {
711
position: relative;
12+
padding: 1rem 1rem 0.9rem;
13+
}
14+
15+
.header-inner {
16+
max-width: 1200px;
17+
margin: 0 auto;
18+
display: grid;
19+
grid-template-columns: 244px 1fr;
20+
column-gap: 1.5rem;
21+
align-items: center;
22+
min-height: 130px;
23+
}
24+
25+
.project-name {
26+
margin: 0;
27+
font-size: clamp(1.8rem, 5vw, 2.3rem);
28+
align-self: center;
29+
justify-self: start;
30+
text-align: left;
831
}
932

1033
.header-repo-link {
1134
position: absolute;
12-
top: 1.5rem;
13-
right: 1.5rem;
35+
top: 1rem;
36+
right: 1rem;
1437
color: rgba(255, 255, 255, 0.92);
1538
line-height: 0;
1639
transition: opacity 160ms ease, transform 160ms ease;
@@ -22,27 +45,210 @@
2245
}
2346

2447
.header-repo-icon {
25-
width: 24px;
26-
height: 24px;
48+
width: 32px;
49+
height: 32px;
2750
display: block;
2851
}
2952

3053
.header-logo-link {
3154
display: inline-block;
32-
margin-bottom: 0.85rem;
55+
margin: 0;
56+
justify-self: center;
3357
line-height: 0;
3458
}
3559

3660
.header-logo {
37-
width: 56px;
61+
width: 128px;
3862
height: auto;
3963
display: block;
4064
}
4165

4266
@media screen and (max-width: 42em) {
67+
.page-header {
68+
padding: 1.1rem 0.8rem 0.9rem;
69+
}
70+
71+
.header-inner {
72+
grid-template-columns: 1fr;
73+
row-gap: 0.35rem;
74+
justify-items: center;
75+
min-height: 0;
76+
}
77+
78+
.project-name {
79+
font-size: 1.65rem;
80+
justify-self: center;
81+
}
82+
83+
.header-logo {
84+
width: 98px;
85+
}
86+
4387
.header-repo-link {
44-
top: 1rem;
45-
right: 1rem;
88+
top: 0.7rem;
89+
right: 0.7rem;
90+
}
91+
}
92+
93+
/* Page layout with TOC sidebar */
94+
.page-body {
95+
display: flex;
96+
align-items: flex-start;
97+
max-width: 1200px;
98+
margin: 0 auto;
99+
}
100+
101+
.toc-sidebar {
102+
flex: 0 0 244px;
103+
position: sticky;
104+
top: 1.5rem;
105+
max-height: calc(100vh - 3rem);
106+
overflow-y: auto;
107+
padding: 1rem 1rem 1rem 1.5rem;
108+
font-size: 0.95rem;
109+
line-height: 1.5;
110+
border-right: 1px solid #e0e0e0;
111+
scrollbar-width: thin;
112+
}
113+
114+
.toc-inner {
115+
padding: 0;
116+
}
117+
118+
.toc-title {
119+
font-weight: 700;
120+
text-transform: uppercase;
121+
font-size: 0.85rem;
122+
letter-spacing: 0.08em;
123+
color: #555;
124+
margin: 0 0 0.6rem 0;
125+
}
126+
127+
.toc-list,
128+
.toc-list ol {
129+
list-style: none;
130+
margin: 0;
131+
padding: 0;
132+
}
133+
134+
.toc-list li {
135+
margin: 0.2rem 0;
136+
}
137+
138+
.toc-list a {
139+
color: #555;
140+
text-decoration: none;
141+
display: block;
142+
padding: 0.1rem 0.3rem;
143+
border-radius: 3px;
144+
transition: background 120ms, color 120ms;
145+
}
146+
147+
.toc-list a:hover {
148+
background: #f0f0f0;
149+
color: #155799;
150+
}
151+
152+
.toc-list a.toc-active {
153+
color: #155799;
154+
font-weight: 600;
155+
background: #eef4fb;
156+
}
157+
158+
.toc-h3 {
159+
padding-left: 0.8rem;
160+
font-size: 0.88rem;
161+
}
162+
163+
.main-content {
164+
flex: 1;
165+
min-width: 0;
166+
padding-left: 1.5rem;
167+
}
168+
169+
/* Burger toggle button — hidden on wide screens */
170+
.toc-toggle {
171+
display: none;
172+
}
173+
174+
@media screen and (max-width: 64em) {
175+
.toc-sidebar {
176+
/* Hidden by default on small screens; slides in as a drawer */
177+
position: fixed;
178+
top: 0;
179+
left: 0;
180+
height: 100%;
181+
width: 260px;
182+
max-height: 100%;
183+
background: #fff;
184+
box-shadow: 2px 0 12px rgba(0,0,0,0.18);
185+
transform: translateX(-110%);
186+
transition: transform 240ms ease;
187+
z-index: 200;
188+
padding-top: 3.5rem;
189+
}
190+
191+
.toc-sidebar.toc-open {
192+
transform: translateX(0);
193+
}
194+
195+
.toc-list li {
196+
margin: 3px 0;
197+
}
198+
199+
.toc-list a {
200+
padding: 0.35rem 0.3rem;
201+
}
202+
203+
.toc-backdrop {
204+
display: none;
205+
position: fixed;
206+
inset: 0;
207+
background: rgba(0,0,0,0.35);
208+
z-index: 199;
209+
}
210+
211+
.toc-backdrop.toc-backdrop-visible {
212+
display: block;
213+
}
214+
215+
/* Burger button */
216+
.toc-toggle {
217+
display: flex;
218+
flex-direction: column;
219+
justify-content: center;
220+
gap: 5px;
221+
position: fixed;
222+
bottom: 1.2rem;
223+
right: 1.2rem;
224+
z-index: 201;
225+
width: 46px;
226+
height: 46px;
227+
border-radius: 50%;
228+
border: none;
229+
background: #155799;
230+
cursor: pointer;
231+
padding: 11px 10px;
232+
box-shadow: 0 2px 8px rgba(0,0,0,0.25);
233+
align-items: center;
234+
}
235+
236+
.toc-toggle-bar {
237+
display: block;
238+
width: 22px;
239+
height: 2px;
240+
background: #fff;
241+
border-radius: 2px;
242+
transition: opacity 160ms;
243+
}
244+
245+
.toc-toggle:hover {
246+
background: #1a6db5;
247+
}
248+
249+
.main-content {
250+
padding-left: 1.2rem;
251+
padding-right: 1rem;
46252
}
47253
}
48254

assets/logo.png

3.06 KB
Loading

0 commit comments

Comments
 (0)