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

    interface TocEntry {
        text: string;
        link: string;

        /**
         * possible values: 0, 1, 2, 3
        */
        indentLevel: number;
    }

    let tocEntries: TocEntry[] = $state([]);

    onMount(() => {
        let headers = getHeaders();
        headers.forEach(header => {
            tocEntries.push({
                text: `${(header as HTMLElement).innerHTML}`,
                link: `#${getHeaderId(header)}`,
                indentLevel: getHeaderLevel(header),
            });
        });
    });

    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;
        }
        return id;
    }

    function getHeaderLevel(header: Node): number {
        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>

{#snippet tocEntryLine({ entry }: { entry: TocEntry })}
    <a class="toc-level-{entry.indentLevel}" href="{entry.link}">{@html entry.text}</a>
{/snippet}

{#if tocEntries.length > 0}
    <div class="toc-container">
        <ul class="toc-list">
            {#each tocEntries as entry}
                {@render tocEntryLine({ entry })}
            {/each}
        </ul>
    </div>
{/if}

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

        .toc-list {
            padding: 0;
            margin: 0;
            width: 100%;
        }
        
        .toc-list a {
            width: 100%;
            font-size: 1.0rem;
            line-height: 1.4rem;
            padding-top: 2px;
            padding-bottom: 2px;
            padding-right: var(--padding-indent-base);
            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: var(--padding-indent-base);
        }
        .toc-level-1 {
            padding-left: calc(var(--padding-indent-base) + var(--padding-level-indent));
        }
        .toc-level-2 {
            padding-left: calc(var(--padding-indent-base) + calc(var(--padding-level-indent) * 2));
        }
        .toc-level-3 {
            padding-left: calc(var(--padding-indent-base) + calc(var(--padding-level-indent) * 3));
        }
        .toc-level-1::before, .toc-level-2::before, .toc-level-3::before {
            content: "└ ";
        }

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