<script lang="ts">
    import {onMount} from 'svelte';

    let {
        stickyScrolling,
    }: {
        stickyScrolling?: boolean;
    } = $props();

    let idCounter: number = 0;

    let root: HTMLElement;
    let container: HTMLElement;

    onMount(() => {
        let headers = getHeaders();
        headers.forEach(header => {
            let headerId = getHeaderId(header);
            var element = document.createElement("a");
            element.classList += "toc-level-" + getHeaderLevel(header);
            element.href = `#${headerId}`;
            element.innerHTML = `${(header as HTMLElement).innerHTML}`;
            container.appendChild(element);
        });

        // Hide table of contents if no valid entries have been found
        if (headers.length == 0) {
            root.style.display = "none";
        }
    });

    let getHeaders = function(): NodeList {
        return document.querySelectorAll("h2, h3, h4, h5");
    }

    // Generates an ID for a given header node. Does not override
    // any existing ID.
    let getHeaderId = function(header: Node): string {
        var id = (header as HTMLElement).id;
        
        if (!id) {
            var text = (header as HTMLElement).innerText.toLowerCase();
            text = text.replaceAll(/[^a-zA-Z0-9]/gi, "-");
            id = text;
            (header as HTMLElement).id = id;
            idCounter += 1;
        }
        return id;
    }

    let getHeaderLevel = function(header: Node): string {
        switch ((header as HTMLElement).tagName) {
            case "H2":
                return "0";
            case "H3":
                return "1";
            case "H4":
                return "2";
            case "H5":
                return "3";
            default:
                return "0";
        }
    }
</script>

{#if stickyScrolling}
    <div class="toc-container sticky-toc" bind:this={root}>
        {@render tocList()}
    </div>
{:else}
    <div class="toc-container" bind:this={root}>
        {@render tocList()}
    </div>
{/if}

{#snippet tocList()}
    <ul class="toc-list" bind:this={container}></ul>
{/snippet}

<style>
    :global {
        .toc-container {
            width: 70%;
            margin-left: auto;
            margin-right: auto;
            background-color: var(--color-background-highlight);
            padding: 16px 0;
            border: dashed var(--border-dash-size) var(--color-highlight);
            backdrop-filter: blur(var(--blur-radius-background));
        }

        .sticky-toc {
            position: sticky;
            top: 20px;
        }

        .toc-list {
            padding: 0;
            margin: 0;
        }
        
        .toc-list a {
            width: 100%;
            font-size: 1.0rem;
            line-height: 1.4rem;
            padding-top: 2px;
            padding-bottom: 2px;
            padding-right: 24px;
            margin: 0;
            display: inline-block;
            text-decoration: none;
            box-sizing: border-box;
            transition: color var(--duration-animation) ease-out,
                        background-color var(--duration-animation) ease-out;
        }
        .toc-list a, .toc-list a:link, .toc-list a:visited {
            color: var(--color-text);
        }
        .toc-list a:hover {
            color: var(--color-text-dark);
            background-color: var(--color-highlight);
        }

        .toc-level-0 {
            font-weight: 800;
            padding-left: 44px;
        }
        .toc-level-1 {
            padding-left: 68px;
        }
        .toc-level-2 {
            padding-left: 92px;
        }
        .toc-level-3 {
            padding-left: 116px;
        }
        .toc-level-1::before, .toc-level-2::before, .toc-level-3::before {
            content: "└ ";
        }

        @media screen and (max-width: 550px) {
            .toc-container {
                width: 95%;
            }
        }
    }
</style>