<commit_before><template>
    <nav v-if="toc && toc.length > 0" aria-label="Page table of contents">
        <b-nav vertical
               v-b-scrollspy.75
               class="m-toc section-nav">
          <template v-for="h2 in toc">
            <b-nav v-if="isArray(h2) && h2.length > 0" vertical class="mb-1">
                <b-nav-item vertical pills v-for="h3 in h2"
                            :key="h3.href"
                            :href="h3.href"
                            class="toc-entry toc-h3 mb-1"
                            @click="scrollIntoView($event, h3.href)"
                ><span v-html="h3.label"></span></b-nav-item>
            </b-nav>
            <b-nav-item v-else 
                        :key="h2.href"
                        :href="h2.href"
                        class="toc-entry toc-h2 mb-1"
                        @click="scrollIntoView($event, h2.href)"
            ><span v-html="h2.label"></span></b-nav-item>
          </template>
        </b-nav>
    </nav>
</template>

<style scoped>
.m-toc.section-nav .nav-link {
     line-height: 1.2;
}

.m-toc.section-nav .toc-entry a {
    padding-left: 12px;
    padding-left: 0.75rem;
}

.m-toc.section-nav .nav-link.active {
     color: #563d7c;
     background: transparent;
}
</style>

<script>
export default {
    data() {
        return {
            toc: [],
            readme: ''
        }
    },
    methods: {
        isArray(arg) {
            return Object.prototype.toString.call(arg) === "[object Array]";
        },
        update(readme) {
            if (!readme) {
                this.toc = [];
                return;
            }
            if (readme === this.readme) {
                return;
            }
            const toc = [];
            // Grab all the H2 and H3 tags with ID's from readme
            const headings = readme.match(/<h[23].*? id="[^"]+".+?<\/h\d>/g) || [];
            let h2Idx = 0;
            headings.forEach(heading => {
                // Pase teh link, label and heading level
                const matches = heading.match(/^<(h[23]).*? id="([^"]+)"[^>]*>(.+?)<\/h\d>$/);
                const tag = matches[1];
                const href = `#${matches[2]}`;
                // Remove any HTML markup in the label
                const label = matches[3].replace(/<[^>]+>/g, '');
                if (tag === 'h2') {
                    toc.push({ href, label });
                    h2Idx = toc.length;
                } else if (tag === 'h3') {
                    toc[h2Idx] = toc[h2Idx] || [];
                    toc[h2Idx].push({ href, label });
                }
            });
            this.toc = toc;
        },
        scrollIntoView(e, href) {
            e.preventDefault();
            e.stopPropagation();
            const el = href ? document.querySelector(href) : null;
            if (el) {
                // scroll heding into view (minus offset to account for nav top height
                (document.documentElement || document.body).scrollTop = el.offsetTop - 75;
                // Set a tab index and then focus header for a11y support
                el.tabIndex = -1;
                el.focus();
            }
        }
    },<commit_msg>chore(docs): TOC add smooth scroll on click<commit_after><template>
    <nav v-if="toc && toc.length > 0" aria-label="Page table of contents">
        <b-nav vertical
               v-b-scrollspy.75
               class="m-toc section-nav">
          <template v-for="h2 in toc">
            <b-nav v-if="isArray(h2) && h2.length > 0" vertical class="mb-1">
                <b-nav-item vertical pills v-for="h3 in h2"
                            :key="h3.href"
                            :href="h3.href"
                            class="toc-entry toc-h3 mb-1"
                            @click="scrollIntoView($event, h3.href)"
                ><span v-html="h3.label"></span></b-nav-item>
            </b-nav>
            <b-nav-item v-else 
                        :key="h2.href"
                        :href="h2.href"
                        class="toc-entry toc-h2 mb-1"
                        @click="scrollIntoView($event, h2.href)"
            ><span v-html="h2.label"></span></b-nav-item>
          </template>
        </b-nav>
    </nav>
</template>

<style scoped>
.m-toc.section-nav .nav-link {
     line-height: 1.2;
}

.m-toc.section-nav .toc-entry a {
    padding-left: 12px;
    padding-left: 0.75rem;
}

.m-toc.section-nav .nav-link.active {
     color: #563d7c;
     background: transparent;
}
</style>

<script>
function easeInOutQuad(t, b, c, d) {
    t /= d/2;
    if (t < 1) return c/2*t*t + b;
    t--;
    return -c/2 * (t*(t-2) - 1) + b;
}

function scrollTo(element, to, duration, cb) {
    const start = element.scrollTop
    const change = to - start
    const increment = 20;
    let currentTime = 0;
    const animateScroll = function(){        
        currentTime += increment;
        const val = easeInOutQuad(currentTime, start, change, duration);
        element.scrollTop = val;
        if(currentTime < duration) {
            setTimeout(animateScroll, increment);
        } else {
            cb();
        }
    };
    animateScroll();
}

export default {
    data() {
        return {
            toc: [],
            readme: ''
        }
    },
    methods: {
        isArray(arg) {
            return Object.prototype.toString.call(arg) === "[object Array]";
        },
        update(readme) {
            if (!readme) {
                this.toc = [];
                return;
            }
            if (readme === this.readme) {
                return;
            }
            const toc = [];
            // Grab all the H2 and H3 tags with ID's from readme
            const headings = readme.match(/<h[23].*? id="[^"]+".+?<\/h\d>/g) || [];
            let h2Idx = 0;
            headings.forEach(heading => {
                // Pase teh link, label and heading level
                const matches = heading.match(/^<(h[23]).*? id="([^"]+)"[^>]*>(.+?)<\/h\d>$/);
                const tag = matches[1];
                const href = `#${matches[2]}`;
                // Remove any HTML markup in the label
                const label = matches[3].replace(/<[^>]+>/g, '');
                if (tag === 'h2') {
                    toc.push({ href, label });
                    h2Idx = toc.length;
                } else if (tag === 'h3') {
                    toc[h2Idx] = toc[h2Idx] || [];
                    toc[h2Idx].push({ href, label });
                }
            });
            this.toc = toc;
        },
        scrollIntoView(e, href) {
            e.preventDefault();
            e.stopPropagation();
            const el = href ? document.querySelector(href) : null;
            if (el) {
                // Set a tab index so we can focus header for a11y support
                el.tabIndex = -1;
                // scroll heding into view (minus offset to account for nav top height
                scrollTo((document.documentElement || document.body), el.offsetTop -70, 100, () => {
                    el.focus();
                });
//                // Jump scroll with offset. 
//                (document.documentElement || document.body).scrollTop = el.offsetTop - 70;
//                el.focus();
            }
        }
    },
{'fraction_non_alphanumeric': 0.1534579184285909, 'fraction_numerical': 0.0169144727867958, 'mean_word_length': 1.2664605873261205, 'pattern_counts': {'":': 0, '<': 57, '<?xml version=': 0, '>': 64, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7220821', 'n_tokens_mistral': 2329, 'n_tokens_neox': 2186, 'n_words': 484}