<script setup lang="ts">
import { computed } from "vue";
import { slugify } from "@/utils/markdown";

const props = defineProps<{ body: string }>();

interface TocEntry {
  depth: number;
  text: string;
  id: string;
}

const headings = computed<TocEntry[]>(() => {
  const entries: TocEntry[] = [];
  const re = /^(#{1,6})\s+(.+)$/gm;
  let match;
  while ((match = re.exec(props.body)) !== null) {
    entries.push({
      depth: match[1].length,
      text: match[2].trim(),
      id: slugify(match[2].trim()),
    });
  }
  return entries;
});

function scrollTo(id: string) {
  const el = document.getElementById(id);
  if (el) el.scrollIntoView({ behavior: "smooth" });
}
</script>

<template>
  <nav v-if="headings.length" class="toc">
    <h3 class="toc-title">Contents</h3>
    <ul class="toc-list">
      <li
        v-for="(h, i) in headings"
        :key="i"
        :style="{ paddingLeft: (h.depth - 1) * 0.75 + 'rem' }"
      >
        <a class="toc-link" @click.prevent="scrollTo(h.id)" :href="`#${h.id}`">
          {{ h.text }}
        </a>
      </li>
    </ul>
  </nav>
</template>

<style scoped>
.toc {
  position: sticky;
  top: 1rem;
  width: 200px;
  flex-shrink: 0;
  align-self: flex-start;
  font-size: 0.85rem;
  line-height: 1.4;
}
.toc-title {
  font-size: 0.8rem;
  text-transform: uppercase;
  color: var(--fs-text-tertiary);
  margin: 0 0 0.5rem;
  letter-spacing: 0.05em;
}
.toc-list {
  list-style: none;
  margin: 0;
  padding: 0;
}
.toc-list li {
  margin-bottom: 0.25rem;
}
.toc-link {
  color: var(--fs-text-tertiary);
  text-decoration: none;
  cursor: pointer;
}
.toc-link:hover {
  color: var(--fs-accent);
}
</style>
