Skip to content

Commit 0357e19

Browse files
committed
feat: back to top & post toc
1 parent febbc1d commit 0357e19

3 files changed

Lines changed: 170 additions & 0 deletions

File tree

layout/_includes/footer.ejs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,43 @@
88
<span style="text-align: left;"><%- theme.footer %></span>
99
</div>
1010
</div>
11+
12+
<!-- Buttons -->
13+
<div class="fab">
14+
<% if (is_post()) { %>
15+
<a aria-label="文章目录" class="fab-btn" id="toc-btn" href="javascript:;" title="文章目录">
16+
<svg
17+
xmlns="http://www.w3.org/2000/svg"
18+
aria-hidden="true"
19+
focusable="false"
20+
data-icon="list-ul"
21+
class="svg-inline--fa fa-list-ul fa-w-16"
22+
role="img"
23+
viewBox="0 0 512 512"
24+
height="20"
25+
width="20"
26+
>
27+
<path
28+
fill="currentColor"
29+
d="M48 48a48 48 0 1 0 48 48 48 48 0 0 0-48-48zm0 160a48 48 0 1 0 48 48 48 48 0 0 0-48-48zm0 160a48 48 0 1 0 48 48 48 48 0 0 0-48-48zm448 16H176a16 16 0 0 0-16 16v32a16 16 0 0 0 16 16h320a16 16 0 0 0 16-16v-32a16 16 0 0 0-16-16zm0-320H176a16 16 0 0 0-16 16v32a16 16 0 0 0 16 16h320a16 16 0 0 0 16-16V80a16 16 0 0 0-16-16zm0 160H176a16 16 0 0 0-16 16v32a16 16 0 0 0 16 16h320a16 16 0 0 0 16-16v-32a16 16 0 0 0-16-16z"
30+
/>
31+
</svg>
32+
</a>
33+
<% } %>
34+
<a aria-label="回到顶部" class="fab-btn" href="#" title="回到顶部">
35+
<svg
36+
xmlns="http://www.w3.org/2000/svg"
37+
aria-hidden="true"
38+
focusable="false"
39+
role="img"
40+
viewBox="0 0 320 512"
41+
height="20"
42+
width="20"
43+
>
44+
<path
45+
fill="currentColor"
46+
d="M168.5 164.2l148 146.8c4.7 4.7 4.7 12.3 0 17l-19.8 19.8c-4.7 4.7-12.3 4.7-17 0L160 229.3 40.3 347.8c-4.7 4.7-12.3 4.7-17 0L3.5 328c-4.7-4.7-4.7-12.3 0-17l148-146.8c4.7-4.7 12.3-4.7 17 0z"
47+
/>
48+
</svg>
49+
</a>
50+
</div>

layout/post.ejs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,3 +43,36 @@
4343
<%- partial("_includes/gitalk") %>
4444
<%- partial("_includes/valine") %>
4545
</div>
46+
47+
<div class="post-toc" id="post-toc">
48+
<div class="toc-label">
49+
<div>文章目录</div>
50+
<a href="javascript:;" id="post-toc-close">
51+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512" height="16" width="16">
52+
<path d="M193.94 256L296.5 153.44l21.15-21.15c3.12-3.12 3.12-8.19 0-11.31l-22.63-22.63c-3.12-3.12-8.19-3.12-11.31 0L160 222.06 36.29 98.34c-3.12-3.12-8.19-3.12-11.31 0L2.34 120.97c-3.12 3.12-3.12 8.19 0 11.31L126.06 256 2.34 379.71c-3.12 3.12-3.12 8.19 0 11.31l22.63 22.63c3.12 3.12 8.19 3.12 11.31 0L160 289.94 262.56 392.5l21.15 21.15c3.12 3.12 8.19 3.12 11.31 0l22.63-22.63c3.12-3.12 3.12-8.19 0-11.31L193.94 256z" fill="currentColor" />
53+
</svg>
54+
</a>
55+
</div>
56+
<%- toc(page.content, { class: 'toc', list_number: false, max_depth: 4, min_depth: 2 }) || '(无目录)' %>
57+
</div>
58+
59+
<script>
60+
document.addEventListener('DOMContentLoaded', function () {
61+
var tocBtn = document.getElementById('toc-btn');
62+
var postToc = document.getElementById('post-toc');
63+
var tocClose = document.getElementById('post-toc-close');
64+
if (tocBtn && postToc) {
65+
tocBtn.addEventListener('click', function () {
66+
postToc.classList.add('active');
67+
});
68+
tocClose.addEventListener('click', function () {
69+
postToc.classList.remove('active');
70+
});
71+
Array.from(document.getElementsByClassName('toc-link')).forEach(function (el) {
72+
el.addEventListener('click', function () {
73+
postToc.classList.remove('active');
74+
});
75+
});
76+
}
77+
});
78+
</script>

source/styles/_includes/footer.less

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,100 @@
1717
display: none;
1818
}
1919
}
20+
21+
.fab {
22+
position: fixed;
23+
bottom: 3rem;
24+
right: 1.5rem;
25+
contain: layout;
26+
27+
.fab-btn {
28+
-webkit-appearance: none;
29+
-moz-appearance: none;
30+
appearance: none;
31+
align-items: center;
32+
margin-top: 0.5rem;
33+
font-size: 0.75rem;
34+
background-color: var(--theme-second);
35+
display: flex;
36+
padding: 1rem;
37+
box-shadow: 0 0.3rem 0.5rem rgba(48, 55, 66, 15%);
38+
border: none;
39+
border-radius: 0.5rem;
40+
line-height: 1;
41+
color: var(--content-first);
42+
cursor: pointer;
43+
transition: all 0.3s;
44+
45+
&:hover {
46+
background-color: var(--border);
47+
}
48+
}
49+
}
50+
51+
.post-toc {
52+
display: none;
53+
position: fixed;
54+
right: 1rem;
55+
bottom: 1rem;
56+
padding: 1.5rem;
57+
z-index: 100;
58+
background: var(--theme-first);
59+
box-shadow: 0 0.3rem 0.5rem rgba(48, 55, 66, 15%);
60+
border-radius: 5px;
61+
max-height: calc(91vh - 5rem);
62+
63+
@media (max-width: 1023px) {
64+
left: 0;
65+
right: 0;
66+
margin: 1rem;
67+
}
68+
69+
@media (min-width: 1000px) {
70+
width: 400px;
71+
}
72+
73+
&.active {
74+
display: block;
75+
}
76+
77+
.toc-label {
78+
font-weight: bold;
79+
padding-bottom: 0.75rem;
80+
display: flex;
81+
justify-content: space-between;
82+
83+
a {
84+
padding: 0 0 0 0.5rem;
85+
color: var(--content-first) !important;
86+
}
87+
}
88+
89+
.toc {
90+
overflow-y: auto;
91+
overflow-x: hidden;
92+
max-height: calc(91vh - 10rem);
93+
padding: 0;
94+
95+
.toc-item {
96+
list-style: none;
97+
98+
a {
99+
display: flex;
100+
padding: 0.5rem 0.75rem;
101+
color: var(--content-first) !important;
102+
transition: all 0.3s;
103+
104+
&:hover {
105+
background: var(--theme-second);
106+
}
107+
}
108+
}
109+
110+
.toc-child {
111+
border-left: 2px solid var(--border);
112+
margin: 0.25rem 0.75rem;
113+
padding-left: 0.75rem;
114+
}
115+
}
116+
}

0 commit comments

Comments
 (0)