{"version":3,"sources":["jsdelivr-header.js","/gh/GreedyLabs/ghost-toc-plugin@1.0.5/toc.js"],"names":[],"mappings":"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","file":"/gh/GreedyLabs/ghost-toc-plugin@1.0.5/toc.js","sourceRoot":"","sourcesContent":["/**\n * Minified by jsDelivr using Terser v5.48.0.\n * Original file: /gh/GreedyLabs/ghost-toc-plugin@1.0.5/toc.js\n *\n * Do NOT use SRI with dynamically generated files! More information: https://www.jsdelivr.com/using-sri-with-dynamic-files\n */\n","/*!\n * ghost-toc-plugin — a portable, theme-independent floating table of contents.\n * https://github.com/GreedyLabs/ghost-toc-plugin\n * MIT License\n *\n * Embed (e.g. Ghost → Settings → Code Injection → Site Footer):\n *   <link rel=\"stylesheet\" href=\".../toc.css\">\n *   <script src=\".../toc.js\"\n *           data-content=\".gh-content\"\n *           data-headings=\"h2,h3\"\n *           data-position=\"right\"\n *           data-title=\"목차\"></script>\n *\n * All data-* options (with defaults):\n *   data-content       CSS selector for the article body   (\".gh-content, article, main, .post-content, .entry-content\")\n *   data-headings      headings to include                 (\"h2,h3\")\n *   data-position      \"right\" | \"left\"                    (\"right\")\n *   data-title         heading shown above the list         (\"목차\")  — empty string hides it\n *   data-accent        active-item color (any CSS color)    (theme default)\n *   data-min-width     hide below this viewport width (px)   (1200)\n *   data-min-headings  don't render below this many headings (2)\n *   data-top           distance from top of viewport (px)    (100)\n *   data-width         panel width (px)                      (240)\n *   data-gap           gap between content and panel (px)    (28)\n *   data-auto          set to \"false\" to skip auto-init      (\"true\")\n *\n * Programmatic API (for tools / live previews):\n *   var toc = GreedyLabsGhostTOC.create({ content: '.article', position: 'left', ... });\n *   toc.destroy();   // removes the panel and all listeners\n *\n * Everything is namespaced under the unique class \"greedylabs-ghost-toc\"\n * (and --greedylabs-ghost-toc-* CSS variables) to avoid clashes with any theme.\n */\n(function () {\n    'use strict';\n\n    var NS = 'greedylabs-ghost-toc';\n\n    var DEFAULTS = {\n        content: '.gh-content, article, main, .post-content, .entry-content',\n        headings: 'h2,h3',\n        position: 'right',\n        title: '목차',\n        accent: '',\n        minWidth: 1200,\n        minHeadings: 2,\n        top: 100,\n        width: 240,\n        gap: 28\n    };\n\n    // Merge defined option values over DEFAULTS and normalise `position`.\n    function resolveConfig(options) {\n        var cfg = {}, k;\n        for (k in DEFAULTS) { if (DEFAULTS.hasOwnProperty(k)) { cfg[k] = DEFAULTS[k]; } }\n        if (options) {\n            for (k in options) {\n                if (options.hasOwnProperty(k) && options[k] !== undefined && options[k] !== null) { cfg[k] = options[k]; }\n            }\n        }\n        cfg.position = cfg.position === 'left' ? 'left' : 'right';\n        return cfg;\n    }\n\n    // Return a function that turns heading text into a unique, URL-safe slug id.\n    function slugifier() {\n        var used = {};\n        return function (text) {\n            var s = (text || '').trim().toLowerCase()\n                .replace(/\\s+/g, '-')\n                .replace(/[^\\p{L}\\p{N}-]+/gu, '')\n                .replace(/-+/g, '-')\n                .replace(/^-+|-+$/g, '');\n            if (!s) { s = 'section'; }\n            if (used[s] === undefined) { used[s] = 0; return s; }\n            used[s] += 1;\n            return s + '-' + used[s];\n        };\n    }\n\n    // Build the panel DOM (title + linked list); returns { panel, linkMap }.\n    // Also assigns ids and scroll-margin to the headings as a side effect.\n    function buildPanel(cfg, headings, slugify) {\n        var panel = document.createElement('aside');\n        panel.className = NS + ' ' + NS + '--' + cfg.position;\n        panel.style.setProperty('--' + NS + '-top', cfg.top + 'px');\n        panel.style.setProperty('--' + NS + '-width', cfg.width + 'px');\n        if (cfg.accent) { panel.style.setProperty('--' + NS + '-accent', cfg.accent); }\n\n        var nav = document.createElement('nav');\n        nav.className = NS + '__inner';\n        nav.setAttribute('aria-label', cfg.title || 'Table of contents');\n\n        if (cfg.title) {\n            var titleEl = document.createElement('p');\n            titleEl.className = NS + '__title';\n            titleEl.textContent = cfg.title;\n            nav.appendChild(titleEl);\n        }\n\n        var list = document.createElement('ul');\n        list.className = NS + '__list';\n\n        var linkMap = {};\n        headings.forEach(function (h) {\n            if (!h.id) { h.id = slugify(h.textContent); }\n            h.style.scrollMarginTop = cfg.top + 'px';\n\n            var li = document.createElement('li');\n            li.className = NS + '__item ' + NS + '__item--' + h.tagName.toLowerCase();\n\n            var a = document.createElement('a');\n            a.className = NS + '__link';\n            a.href = '#' + h.id;\n            a.textContent = h.textContent || '';\n\n            li.appendChild(a);\n            list.appendChild(li);\n            linkMap[h.id] = a;\n        });\n\n        nav.appendChild(list);\n        panel.appendChild(nav);\n        return { panel: panel, linkMap: linkMap };\n    }\n\n    // Create a TOC instance. Returns { element, destroy } or null if there's\n    // nothing to render (no content element, or too few headings).\n    function create(options) {\n        var cfg = resolveConfig(options);\n\n        var content = typeof cfg.content === 'string' ? document.querySelector(cfg.content) : cfg.content;\n        if (!content) { return null; }\n\n        var headings = Array.prototype.slice.call(content.querySelectorAll(cfg.headings));\n        if (headings.length < cfg.minHeadings) { return null; }\n\n        var built = buildPanel(cfg, headings, slugifier());\n        var panel = built.panel, linkMap = built.linkMap;\n        document.body.appendChild(panel);\n\n        var ACTIVE = NS + '__link--active';\n        var activeId = null;\n\n        // Place the panel beside the readable text column and hide it when it\n        // won't fit. Aligns to the first heading, not the content wrapper (in Ghost\n        // .gh-content is a full-width grid whose edge is the page edge).\n        function layout() {\n            var vw = document.documentElement.clientWidth;\n            if (vw < cfg.minWidth) { panel.style.display = 'none'; return; }\n\n            var rect = headings[0].getBoundingClientRect();\n            if (!rect.width) { rect = content.getBoundingClientRect(); }\n            var left;\n            if (cfg.position === 'left') {\n                left = rect.left - cfg.gap - cfg.width;\n                if (left < 8) { panel.style.display = 'none'; return; }\n            } else {\n                left = rect.right + cfg.gap;\n                if (left + cfg.width > vw - 8) { panel.style.display = 'none'; return; }\n            }\n            panel.style.display = 'block';\n            panel.style.left = Math.round(left) + 'px';\n            verticalAlign();\n        }\n\n        // Keep the panel within the article vertically: pinned at `cfg.top`, but\n        // capped to the article box so it never overlaps the header or scrolls past\n        // the content end (behaves like an in-flow sticky TOC).\n        function verticalAlign() {\n            if (panel.style.display === 'none') { return; }\n            var cr = content.getBoundingClientRect();\n            var top = Math.max(cfg.top, cr.top);\n            var maxTop = cr.bottom - panel.offsetHeight;\n            if (top > maxTop) { top = maxTop; }\n            panel.style.top = Math.round(top) + 'px';\n        }\n\n        // Move the --active class to the link for `id` (no-op if unchanged).\n        function setActive(id) {\n            if (id === activeId) { return; }\n            if (activeId && linkMap[activeId]) { linkMap[activeId].classList.remove(ACTIVE); }\n            activeId = id;\n            if (id && linkMap[id]) { linkMap[id].classList.add(ACTIVE); }\n        }\n\n        // Index of the heading the reader is currently in. Each heading has an\n        // activation scroll point (where its top reaches the reading line at\n        // `cfg.top`); the active one is the last point already passed. Reachable\n        // headings keep their exact point (precise); a tail too close to the page\n        // bottom to ever reach the line is spread across the final scroll so those\n        // headings still activate in order, the last one exactly at the bottom.\n        function activeIndex() {\n            var scrollY = window.scrollY;\n            var maxScroll = Math.max(0, document.documentElement.scrollHeight - window.innerHeight);\n\n            var pts = headings.map(function (h) {\n                return h.getBoundingClientRect().top + scrollY - cfg.top;\n            });\n\n            var tail = -1;\n            for (var i = 0; i < pts.length; i++) { if (pts[i] > maxScroll) { tail = i; break; } }\n            if (tail !== -1) {\n                var anchor = tail > 0 ? Math.min(pts[tail - 1], maxScroll) : 0;\n                var n = pts.length - tail;\n                for (var j = tail; j < pts.length; j++) {\n                    pts[j] = anchor + (maxScroll - anchor) * ((j - tail + 1) / n);\n                }\n            }\n\n            var idx = 0;\n            for (var k = 0; k < pts.length; k++) { if (scrollY + 1 >= pts[k]) { idx = k; } }\n            return idx;\n        }\n\n        // Recompute and apply the active heading.\n        function updateActive() { setActive(headings[activeIndex()].id); }\n\n        // Coalesce scroll / content-grow events into one realign + recompute per frame.\n        var ticking = false;\n        function tick() {\n            if (ticking) { return; }\n            ticking = true;\n            window.requestAnimationFrame(function () { verticalAlign(); updateActive(); ticking = false; });\n        }\n\n        // Full re-place (used on resize, where the horizontal fit can change too).\n        function relayout() { layout(); updateActive(); }\n\n        layout();\n        updateActive();\n        window.addEventListener('scroll', tick, { passive: true });\n        window.addEventListener('resize', relayout);\n\n        // The page can grow after load — lazy images, embeds, comment widgets\n        // (giscus/Disqus), ad slots. That shifts which headings are reachable, so\n        // recompute on document-height changes, not only on scroll.\n        var ro = window.ResizeObserver ? new ResizeObserver(tick) : null;\n        if (ro) { ro.observe(document.documentElement); }\n\n        return {\n            element: panel,\n            destroy: function () {\n                window.removeEventListener('scroll', tick);\n                window.removeEventListener('resize', relayout);\n                if (ro) { ro.disconnect(); }\n                if (panel.parentNode) { panel.parentNode.removeChild(panel); }\n            }\n        };\n    }\n\n    // Expose the programmatic API.\n    window.GreedyLabsGhostTOC = { create: create, defaults: DEFAULTS };\n\n    // Auto-init from this script's own data-* attributes (unless data-auto=\"false\").\n    var thisScript = document.currentScript;\n    function ready(fn) {\n        if (document.readyState !== 'loading') { fn(); }\n        else { document.addEventListener('DOMContentLoaded', fn); }\n    }\n    ready(function () {\n        var script = thisScript || document.querySelector('script[src*=\"toc.js\"]');\n        if (!script || script.getAttribute('data-auto') === 'false') { return; }\n        function num(name, def) {\n            var v = script.getAttribute('data-' + name);\n            return v === null ? def : parseInt(v, 10);\n        }\n        function str(name, def) {\n            var v = script.getAttribute('data-' + name);\n            return v === null ? def : v;\n        }\n        create({\n            content: str('content', undefined),\n            headings: str('headings', undefined),\n            position: str('position', undefined),\n            title: script.getAttribute('data-title'), // allow empty string\n            accent: str('accent', undefined),\n            minWidth: num('min-width', undefined),\n            minHeadings: num('min-headings', undefined),\n            top: num('top', undefined),\n            width: num('width', undefined),\n            gap: num('gap', undefined)\n        });\n    });\n})();\n"]}