Generate toc from titles
by uto usui
HTML
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/css/bootstrap.min.css">
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/js/bootstrap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-easing/1.4.1/jquery.easing.min.js"></script>
<h1 class="h1">Generate toc from titles</h1>
<div class="wrap">
<div class="inner" id="js-toc">
<section class="section">
<h2 class="h2">section 1</h2>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Enim quasi quos, quia officia, laborum aut ullam vitae aliquam tenetur rem libero, rerum consequuntur iusto odio vero odit porro perferendis error?</p>
<h3 class="h3">child 1-1</h3>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Quasi a veritatis porro soluta deleniti cum id pariatur aut voluptatibus, sint sunt reiciendis itaque excepturi asperiores minus nesciunt voluptates delectus labore!</p>
<h3 class="h3">child 1-2</h3>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Quasi a veritatis porro soluta deleniti cum id pariatur aut voluptatibus, sint sunt reiciendis itaque excepturi asperiores minus nesciunt voluptates delectus labore!</p>
<h2 class="h2">section 2</h2>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Sunt magnam velit, adipisci dolor, eius voluptate, animi suscipit cumque dicta blanditiis molestiae voluptatem molestias veritatis laborum autem odit laboriosam impedit non!</p>
<h3 class="h3">child 2-1</h3>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Quasi a veritatis porro soluta deleniti cum id pariatur aut voluptatibus, sint sunt reiciendis itaque excepturi asperiores minus nesciunt voluptates delectus labore!</p>
<h2 class="h2">section 3</h2>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Eum dolorem nam eos qui ab placeat optio vitae rem, deserunt incidunt consequatur animi quisquam...
SCSS
body {
width: 100%;
min-height: 100vh;
background-image: linear-gradient(60deg, #F7CAC9 15%, #91A8D0 85%);
}
p {
text-align: justify;
}
.h1 {
margin: 1.2em;
font-family: 'Dancing Script', cursive;
color: rgba(white, .85);
}
.h2 {
font-size: 42px;
font-family: 'Dancing Script', cursive;
color: rgba(white, .85);
}
.h3 {
font-size: 24px;
font-family: 'Dancing Script', cursive;
color: rgba(white, .85);
}
.wrap {
display: flex;
justify-content: center;
align-items: center;
}
.inner {
padding-right: 1em;
padding-left: 1em;
min-width: 300px;
}
.list {
display: flex;
}
.item {
font-size: 2em;
+ .item {
margin-left: 2em;
}
}
.section {
max-width: 480px;
padding: 1em;
border: 6px double currentColor;
}
// toc
// - - - - - - - - - -
.toc {
position: fixed;
top: 1em;
left: 1em;
overflow: auto;
padding: 1em;
height: auto;
max-height: calc(100vh - 2em);
transition: .25s ease-out;
border: 2px solid currentColor;
opacity: .3;
//
&.is-active {
background-color: rgba(#fff, .45);
border-color: rgba(#000,0);
box-shadow: 0 0 20px rgba(#000,.1);
opacity: 1;
}
&:hover {
opacity: 1;
}
}
.toc_title {
text-transform: uppercase;
letter-spacing: .2em;
cursor: pointer;
}
.toc_list {
display: none;
}
.toc_item {
text-transform: capitalize;
letter-spacing: .1em;
font-style: italic;
font-size: 20px;
//
+ .toc_item {
margin-top: 1em;
}
}
.toc_item-child {
font-size: 14px;
padding-left: 1em;
}
Babel + JSX
const generateToc = (target) => {
if (target.length) {
let toc = $('<section class="toc"></section>'),
title = $('<h2 class="toc_title">toc<br>ー</h2>'),
ul = $('<ul class="toc_list"></ul>'),
html = toc.prepend(title),
h2 = target.find('h2'),
anchorName = 'section',
text,
childText;
// - -
// create list item
// - - - - - - - - -
const createItem = () => {
for (let i = 0, len = h2.length; i < len; i++) {
let child = $('<ul class="toc_child"></ul>'),
anchorId = anchorName + i;
$(h2[i]).attr('id', anchorId).nextUntil('h2').filter('h3').each((ci, cv) => {
let anchorChildId = anchorId + '-' + ci;
childText = $(cv).attr('id', anchorChildId).html();
$('<li class="toc_item-child"></li>').text(childText).appendTo(child).wrapInner(() => {
return '<a class="toc_target" href="#' + anchorChildId + '"></a>';
});
});
text = $(h2[i]).html();
$('<li class="toc_item"></li>').wrapInner(() => {
return '<a class="toc_target" href="#' + anchorId + '">' + text + '</a>';
}).appendTo(ul).append(child);
}
};
createItem();
// - -
// insert toc
// - - - - - - - - -
const insertToc = () => {
if (ul.find('li').length > 1) {
html.append(ul);
target.before(html);
}
};
insertToc();
// - -
// toggle button
// - - - - - - - - - -
const clickBtn = () => {
title.on('click', () => {
toc.toggleClass('is-active');
ul.stop().slideToggle(250);
});
};
clickBtn();
// - -
// page scroll
// - - - - - - - - - -
const scroll = () => {
toc.find('a').on('click', function(e) {
let anchor = $(this.hash),
time = 550,
topDistance = 15,
anchorOffset = anchor.offset().top - topDistance;
...