diff --git a/plugins/GmeekTOC.js b/plugins/GmeekTOC.js index 4ba9551..eb8a9d2 100644 --- a/plugins/GmeekTOC.js +++ b/plugins/GmeekTOC.js @@ -1,59 +1,92 @@ -function loadResource(type, attributes, callback) { - var element; - if (type === 'script') { - element = document.createElement('script'); - element.src = attributes.src; - element.onload = callback; - } else if (type === 'link') { - element = document.createElement('link'); - element.rel = attributes.rel; - element.href = attributes.href; - } else if (type === 'style') { - element = document.createElement('style'); - element.rel = 'stylesheet'; - element.appendChild(document.createTextNode(attributes.css)); - } - document.head.appendChild(element); -} - function createTOC() { var tocElement = document.createElement('div'); tocElement.className = 'toc'; var contentContainer = document.getElementById('content'); - if (contentContainer.firstChild) { - contentContainer.insertBefore(tocElement, contentContainer.firstChild); - } else { - contentContainer.appendChild(tocElement); - } + contentContainer.prepend(tocElement); + const headings = contentContainer.querySelectorAll('h1, h2, h3, h4, h5, h6'); + tocElement.insertAdjacentHTML('afterbegin', '
文章目录
'); + headings.forEach(heading => { + if (!heading.id) { + heading.id = heading.textContent.trim().replace(/\s+/g, '-').toLowerCase(); + } + const link = document.createElement('a'); + link.href = '#' + heading.id; + link.textContent = heading.textContent; + link.className = 'toc-link'; + link.style.paddingLeft = `${(parseInt(heading.tagName.charAt(1)) - 1) * 10}px`; + tocElement.appendChild(link); + }); + tocElement.insertAdjacentHTML('beforeend', 'Top'); } + document.addEventListener("DOMContentLoaded", function() { createTOC(); - var css = '.toc {position:fixed;top:130px;left:50%;transform: translateX(50%) translateX(300px);width:200px;padding-left:30px;}@media (max-width: 1249px) {.toc{position:static;top:auto;left:auto;transform:none;padding:10px;margin-bottom:20px;background-color:#eee;}}'; - loadResource('style', {css: css}); + var css = ` + .toc { + position:fixed; + top:130px; + left:50%; + transform: translateX(50%) translateX(320px); + width:200px; + border: 1px solid #e1e4e8; + border-radius: 6px; + padding: 10px; + overflow-y: auto; + box-shadow: 0 2px 10px rgba(0,0,0,0.1); + max-height: 70vh; + } + .toc-title{ + font-weight: bold; + text-align: center; + border-bottom: 1px solid #ddd; + padding-bottom: 8px; + } + .toc-end{ + font-weight: bold; + text-align: center; + visibility: hidden; + } + .toc a { + display: block; + color: var(--color-diff-blob-addition-num-text); + text-decoration: none; + padding: 5px 0; + font-size: 14px; + line-height: 1.5; + border-bottom: 1px solid #e1e4e8; + } + .toc a:last-child { + border-bottom: none; + } + .toc a:hover { + background-color:var(--color-select-menu-tap-focus-bg); + } - loadResource('script', { src: 'https://cdnjs.cloudflare.com/ajax/libs/tocbot/4.27.4/tocbot.min.js' }, function() { - tocbot.init({ - tocSelector: '.toc', - contentSelector: '.markdown-body', - headingSelector: 'h1, h2, h3, h4, h5, h6', - scrollSmooth: true, - scrollSmoothOffset: -10, - headingsOffset: 10, - }); - }); - - loadResource('link', { rel: 'stylesheet', href: 'https://cdnjs.cloudflare.com/ajax/libs/tocbot/4.27.4/tocbot.css' }); - - const headings = document.querySelectorAll('.markdown-body h1, .markdown-body h2, .markdown-body h3, .markdown-body h4, .markdown-body h5, .markdown-body h6'); - headings.forEach((heading) => { - if (!heading.id) { - heading.id = heading.textContent.trim().replace(/\s+/g, '-'); + @media (max-width: 1249px) + { + .toc{ + position:static; + top:auto; + left:auto; + transform:none; + padding:10px; + margin-bottom:20px; } - }); + }`; + + const style = document.createElement('style'); + style.textContent = css; + document.head.appendChild(style); + + window.onscroll = function() { + const backToTopButton = document.querySelector('.toc-end'); + if (document.body.scrollTop > 20 || document.documentElement.scrollTop > 20) { + backToTopButton.style="visibility: visible;" + } else { + backToTopButton.style="visibility: hidden;" + } + }; - var footerPlaceholder = document.createElement('div'); - footerPlaceholder.style.height = window.innerHeight + 'px'; - document.body.appendChild(footerPlaceholder); console.log("\n %c GmeekTOC Plugins https://github.com/Meekdai/Gmeek \n","padding:5px 0;background:#C333D0;color:#fff"); -}); +}); \ No newline at end of file diff --git a/plugins/GmeekTocBot.js b/plugins/GmeekTocBot.js new file mode 100644 index 0000000..fc216dd --- /dev/null +++ b/plugins/GmeekTocBot.js @@ -0,0 +1,59 @@ +function loadResource(type, attributes, callback) { + var element; + if (type === 'script') { + element = document.createElement('script'); + element.src = attributes.src; + element.onload = callback; + } else if (type === 'link') { + element = document.createElement('link'); + element.rel = attributes.rel; + element.href = attributes.href; + } else if (type === 'style') { + element = document.createElement('style'); + element.rel = 'stylesheet'; + element.appendChild(document.createTextNode(attributes.css)); + } + document.head.appendChild(element); +} + +function createTOC() { + var tocElement = document.createElement('div'); + tocElement.className = 'toc'; + var contentContainer = document.getElementById('content'); + if (contentContainer.firstChild) { + contentContainer.insertBefore(tocElement, contentContainer.firstChild); + } else { + contentContainer.appendChild(tocElement); + } +} + +document.addEventListener("DOMContentLoaded", function() { + createTOC(); + var css = '.toc {position:fixed;top:130px;left:50%;transform: translateX(50%) translateX(300px);width:200px;padding-left:30px;}@media (max-width: 1249px) {.toc{position:static;top:auto;left:auto;transform:none;padding:10px;margin-bottom:20px;background-color:var(--color-open-muted);}}'; + loadResource('style', {css: css}); + + loadResource('script', { src: 'https://cdnjs.cloudflare.com/ajax/libs/tocbot/4.27.4/tocbot.min.js' }, function() { + tocbot.init({ + tocSelector: '.toc', + contentSelector: '.markdown-body', + headingSelector: 'h1, h2, h3, h4, h5, h6', + scrollSmooth: true, + scrollSmoothOffset: -10, + headingsOffset: 10, + }); + }); + + loadResource('link', { rel: 'stylesheet', href: 'https://cdnjs.cloudflare.com/ajax/libs/tocbot/4.27.4/tocbot.css' }); + + const headings = document.querySelectorAll('.markdown-body h1, .markdown-body h2, .markdown-body h3, .markdown-body h4, .markdown-body h5, .markdown-body h6'); + headings.forEach((heading) => { + if (!heading.id) { + heading.id = heading.textContent.trim().replace(/\s+/g, '-'); + } + }); + + var footerPlaceholder = document.createElement('div'); + footerPlaceholder.style.height = window.innerHeight + 'px'; + document.body.appendChild(footerPlaceholder); + console.log("\n %c GmeekTocBot Plugins https://github.com/Meekdai/Gmeek \n","padding:5px 0;background:#C333D0;color:#fff"); +}); diff --git a/plugins/articletoc.js b/plugins/articletoc.js new file mode 100644 index 0000000..67b9af0 --- /dev/null +++ b/plugins/articletoc.js @@ -0,0 +1,158 @@ +function loadResource(type, attributes) { + if (type === 'style') { + const style = document.createElement('style'); + style.textContent = attributes.css; + document.head.appendChild(style); + } +} + +function createTOC() { + const tocElement = document.createElement('div'); + tocElement.className = 'toc'; + const contentContainer = document.querySelector('.markdown-body'); + contentContainer.appendChild(tocElement); + + const headings = contentContainer.querySelectorAll('h1, h2, h3, h4, h5, h6'); + headings.forEach(heading => { + if (!heading.id) { + heading.id = heading.textContent.trim().replace(/\s+/g, '-').toLowerCase(); + } + const link = document.createElement('a'); + link.href = '#' + heading.id; + link.textContent = heading.textContent; + link.className = 'toc-link'; + link.style.paddingLeft = `${(parseInt(heading.tagName.charAt(1)) - 1) * 10}px`; + tocElement.appendChild(link); + }); +} + +function toggleTOC() { + const tocElement = document.querySelector('.toc'); + const tocIcon = document.querySelector('.toc-icon'); + if (tocElement) { + tocElement.classList.toggle('show'); + tocIcon.classList.toggle('active'); + tocIcon.textContent = tocElement.classList.contains('show') ? '✖' : '☰'; + } +} + +document.addEventListener("DOMContentLoaded", function() { + createTOC(); + const css = ` + :root { + --toc-bg: #fff; + --toc-border: #e1e4e8; + --toc-text: #24292e; + --toc-hover: #f6f8fa; + --toc-icon-bg: #fff; + --toc-icon-color: #ad6598; + --toc-icon-active-bg: #813c85; + --toc-icon-active-color: #fff; + } + + @media (prefers-color-scheme: dark) { + :root { + --toc-bg: #2d333b; + --toc-border: #444c56; + --toc-text: #adbac7; + --toc-hover: #373e47; + --toc-icon-bg: #22272e; + --toc-icon-color: #ad6598; + --toc-icon-active-bg: #813c85; + --toc-icon-active-color: #adbac7; + } + } + + .toc { + position: fixed; + bottom: 60px; + right: 20px; + width: 250px; + max-height: 70vh; + background-color: var(--toc-bg); + border: 1px solid var(--toc-border); + border-radius: 6px; + padding: 10px; + box-shadow: 0 2px 10px rgba(0,0,0,0.1); + overflow-y: auto; + z-index: 1000; + opacity: 0; + visibility: hidden; + transform: translateY(20px) scale(0.9); + transition: opacity 0.3s ease, transform 0.3s ease, visibility 0.3s; + } + .toc.show { + opacity: 1; + visibility: visible; + transform: translateY(0) scale(1); + } + .toc a { + display: block; + color: var(--toc-text); + text-decoration: none; + padding: 5px 0; + font-size: 14px; + line-height: 1.5; + border-bottom: 1px solid var(--toc-border); + transition: background-color 0.2s ease, padding-left 0.2s ease; + } + .toc a:last-child { + border-bottom: none; + } + .toc a:hover { + background-color: var(--toc-hover); + padding-left: 5px; + } + .toc-icon { + position: fixed; + bottom: 20px; + right: 20px; + cursor: pointer; + font-size: 24px; + background-color: var(--toc-icon-bg); + color: var(--toc-icon-color); + border: 2px solid var(--toc-icon-color); + border-radius: 50%; + width: 40px; + height: 40px; + display: flex; + align-items: center; + justify-content: center; + box-shadow: 0 1px 3px rgba(0,0,0,0.12); + z-index: 1001; + transition: all 0.3s ease; + user-select: none; + -webkit-tap-highlight-color: transparent; + outline: none; + } + .toc-icon:hover { + transform: scale(1.1); + } + .toc-icon:active { + transform: scale(0.9); + } + .toc-icon.active { + background-color: var(--toc-icon-active-bg); + color: var(--toc-icon-active-color); + border-color: var(--toc-icon-active-bg); + transform: rotate(90deg); + } + `; + loadResource('style', {css: css}); + + const tocIcon = document.createElement('div'); + tocIcon.className = 'toc-icon'; + tocIcon.textContent = '☰'; + tocIcon.onclick = (e) => { + e.stopPropagation(); + toggleTOC(); + }; + document.body.appendChild(tocIcon); + + document.addEventListener('click', (e) => { + const tocElement = document.querySelector('.toc'); + if (tocElement && tocElement.classList.contains('show') && !tocElement.contains(e.target) && !e.target.classList.contains('toc-icon')) { + toggleTOC(); + } + }); +});