diff --git a/_config.yml b/_config.yml index 56b75e7..a391495 100644 --- a/_config.yml +++ b/_config.yml @@ -86,7 +86,7 @@ website_count: # See: https://github.com/theme-next/hexo-generator-searchdb # --------------------------------------------------------------------------------------- local_search: - enable: true + enable: false # If auto, trigger search by changing input. # If manual, trigger search by pressing enter key or search button. @@ -141,7 +141,7 @@ side_tools: # Back to top # --------------------------------------------------------------------------------------- back2top: - enable: false + enable: true # --------------------------------------------------------------------------------------- diff --git a/layout/_partial/head.ejs b/layout/_partial/head.ejs index d3fcd8e..2b57725 100644 --- a/layout/_partial/head.ejs +++ b/layout/_partial/head.ejs @@ -15,10 +15,14 @@ title = __('tag') + ': ' + page.tag; } else if (page.title === 'about') { title = __('about'); + } else if (page.title === 'links') { + title = __('links'); } %> - <% if (title){ %><%= title %> | <% } %><%= config.title %> + <% if (title){ %><%= title %> | + <% } %> + <%= config.title %> <% if (theme.style.favicon){ %> diff --git a/layout/_partial/scripts.ejs b/layout/_partial/scripts.ejs index da7c3d3..f7cb5fe 100644 --- a/layout/_partial/scripts.ejs +++ b/layout/_partial/scripts.ejs @@ -1,21 +1,24 @@ <%- js([ - 'js/main.js', + 'js/utils.js', 'js/header-shrink.js', - 'js/toggle-mode.js' + 'js/dark-light-toggle.js', + 'js/main.js' ]) %> <% if (theme.back2top.enable) { %> - <%- js('js/scroll-to-top.js') %> + <%- js('js/back2top.js') %> <% } %> <% if (is_post()) { %> + <%- js('js/left-side-toggle.js') %> + <% if (theme.code_copy.enable) { %> <%- js('js/code-copy.js') %> <% } %> <% if (theme.toc.enable) { %> - <%- js(['lib/anime.min.js', 'js/toc.js', 'js/post-toc.js']) %> + <%- js(['lib/anime.min.js', 'js/toc.js']) %> <% } %> <% } %> diff --git a/scripts/helpers/export-config.js b/scripts/helpers/export-config.js index c8af5bc..2f39c2e 100644 --- a/scripts/helpers/export-config.js +++ b/scripts/helpers/export-config.js @@ -8,18 +8,21 @@ const url = require('url'); * Export theme config to js */ hexo.extend.helper.register('export_config', function () { - let {config, theme} = this; - let exportConfig = { - hostname: url.parse(config.url).hostname || config.url, - root: config.root, - localsearch: theme.local_search, - themeInfo: theme.theme_info, - codeblock: theme.codeblock - }; - if (config.search) { - exportConfig.path = config.search.path; - } - return ``; }); diff --git a/source/css/layout/common/markdown.styl b/source/css/layout/common/markdown.styl index a2abf83..1d1b0a4 100644 --- a/source/css/layout/common/markdown.styl +++ b/source/css/layout/common/markdown.styl @@ -69,15 +69,14 @@ h1, h2, h3, h4, h5, h6 { - // TODO: ... } h1 { color: var(--second-text-color); font-size: 2em; font-weight: 600; - margin-block-start: 1.1em; - margin-block-end: 1.1em; + margin-block-start: 1.4em; + margin-block-end: 1.0em; } @@ -85,16 +84,16 @@ color: var(--second-text-color); font-size: 1.8em; font-weight: 600; - margin-block-start: 1.1em; - margin-block-end: 1.1em; + margin-block-start: 1.4em; + margin-block-end: 1.0em; } h3 { color: var(--second-text-color); font-size: 1.6em; font-weight: 550; - margin-block-start: 1em; - margin-block-end: 1em; + margin-block-start: 1.2em; + margin-block-end: 0.8em; } @@ -102,16 +101,16 @@ color: var(--second-text-color); font-size: 1.4em; font-weight: 550; - margin-block-start: 1em; - margin-block-end: 1em; + margin-block-start: 1.2em; + margin-block-end: 0.8em; } h5 { color: var(--second-text-color); font-size: 1.2em; font-weight: 500; - margin-block-start: 0.9em; - margin-block-end: 0.9em; + margin-block-start: 1.0em; + margin-block-end: 0.6em; } @@ -119,8 +118,8 @@ color: var(--second-text-color); font-size: 1.2em; font-weight: 500; - margin-block-start: 0.9em; - margin-block-end: 0.9em; + margin-block-start: 1.0em; + margin-block-end: 0.6em; } diff --git a/source/js/back2top.js b/source/js/back2top.js new file mode 100644 index 0000000..10f512f --- /dev/null +++ b/source/js/back2top.js @@ -0,0 +1,35 @@ +window.addEventListener('DOMContentLoaded', () => { + ILS.utils = { + + ...ILS.utils, + + back2TopButton_dom: document.querySelector('.scroll-to-top'), + + back2top() { + const scrollTopTimer = setInterval(function () { + let top = document.body.scrollTop || document.documentElement.scrollTop; + let speed = top / 2; + if (document.body.scrollTop !== 0) { + document.body.scrollTop -= speed; + } else { + document.documentElement.scrollTop -= speed; + } + if (top === 0) { + clearInterval(scrollTopTimer); + } + }, 30); + }, + + initBack2TopButton() { + if (ILS.utils.back2TopButton_dom) { + ILS.utils.back2TopButton_dom.addEventListener('click', () => { + this.back2top(); + }); + } + }, + } + + ILS.utils.initBack2TopButton(); +}); + + diff --git a/source/js/code-copy.js b/source/js/code-copy.js index 5e09bc9..8a36266 100644 --- a/source/js/code-copy.js +++ b/source/js/code-copy.js @@ -1,45 +1,45 @@ HTMLElement.prototype.wrap = function (wrapper) { - this.parentNode.insertBefore(wrapper, this); - this.parentNode.removeChild(this); - wrapper.appendChild(this); + this.parentNode.insertBefore(wrapper, this); + this.parentNode.removeChild(this); + wrapper.appendChild(this); }; window.addEventListener('DOMContentLoaded', () => { - document.querySelectorAll('figure.highlight').forEach(element => { - const box = document.createElement('div'); - element.wrap(box); - box.classList.add('highlight-container'); - box.insertAdjacentHTML('beforeend', '
'); - var button = element.parentNode.querySelector('.copy-btn'); - button.addEventListener('click', event => { - var target = event.currentTarget; - var code = [...target.parentNode.querySelectorAll('.code .line')].map(line => line.innerText).join('\n'); - var ta = document.createElement('textarea'); - ta.style.top = window.scrollY + 'px'; // Prevent page scrolling - ta.style.position = 'absolute'; - ta.style.opacity = '0'; - ta.readOnly = true; - ta.value = code; - document.body.append(ta); - const selection = document.getSelection(); - const selected = selection.rangeCount > 0 ? selection.getRangeAt(0) : false; - ta.select(); - ta.setSelectionRange(0, code.length); - ta.readOnly = false; - var result = document.execCommand('copy'); - target.querySelector('i').className = result ? 'fa fa-check' : 'fa fa-times'; - ta.blur(); // For iOS - target.blur(); - if (selected) { - selection.removeAllRanges(); - selection.addRange(selected); - } - document.body.removeChild(ta); - }); - button.addEventListener('mouseleave', event => { - setTimeout(() => { - event.target.querySelector('i').className = 'fa fa-clipboard'; - }, 300); - }); + document.querySelectorAll('figure.highlight').forEach(element => { + const box = document.createElement('div'); + element.wrap(box); + box.classList.add('highlight-container'); + box.insertAdjacentHTML('beforeend', '
'); + var button = element.parentNode.querySelector('.copy-btn'); + button.addEventListener('click', event => { + var target = event.currentTarget; + var code = [...target.parentNode.querySelectorAll('.code .line')].map(line => line.innerText).join('\n'); + var ta = document.createElement('textarea'); + ta.style.top = window.scrollY + 'px'; // Prevent page scrolling + ta.style.position = 'absolute'; + ta.style.opacity = '0'; + ta.readOnly = true; + ta.value = code; + document.body.append(ta); + const selection = document.getSelection(); + const selected = selection.rangeCount > 0 ? selection.getRangeAt(0) : false; + ta.select(); + ta.setSelectionRange(0, code.length); + ta.readOnly = false; + var result = document.execCommand('copy'); + target.querySelector('i').className = result ? 'fa fa-check' : 'fa fa-times'; + ta.blur(); // For iOS + target.blur(); + if (selected) { + selection.removeAllRanges(); + selection.addRange(selected); + } + document.body.removeChild(ta); }); + button.addEventListener('mouseleave', event => { + setTimeout(() => { + event.target.querySelector('i').className = 'fa fa-clipboard'; + }, 300); + }); + }); }); diff --git a/source/js/dark-light-toggle.js b/source/js/dark-light-toggle.js new file mode 100644 index 0000000..398bfcb --- /dev/null +++ b/source/js/dark-light-toggle.js @@ -0,0 +1,72 @@ +window.addEventListener('DOMContentLoaded', () => { + ILS.utils.modeToggle = { + + localStorageKey: 'MAGIC', + modeToggleButton_dom: document.querySelector('.mode-toggle'), + iconDom: document.querySelector('.mode-toggle i'), + articleContent: document.querySelector('.main-content'), + + setItemUtil(modeClass, prefersColorScheme) { + document.body.classList.toggle(modeClass); + const isDark = document.body.className.indexOf(modeClass) === -1; + + if (isDark) { + this.iconDom.className = 'fa fa-moon-o'; + this.articleContent.classList.remove('night-code-theme'); + } else { + this.iconDom.className = 'fa fa-lightbulb-o'; + this.articleContent.classList.add('night-code-theme'); + } + localStorage.setItem(this.localStorageKey, JSON.stringify( + { + prefersColorScheme: prefersColorScheme, + isDark: isDark + } + )); + }, + + initModeStatus() { + this.modeConfig = JSON.parse(localStorage.getItem(this.localStorageKey)); + if (this.modeConfig) { + if (this.modeConfig.prefersColorScheme === 'dark') { + if (this.modeConfig.isDark) { + document.body.classList.remove('light-mode'); + this.articleContent.classList.remove('night-code-theme'); + this.iconDom.className = 'fa fa-lightbulb-o'; + } else { + document.body.classList.add('light-mode'); + this.articleContent.classList.add('night-code-theme'); + this.iconDom.className = 'fa fa-moon-o'; + } + } else { + + if (this.modeConfig.isDark) { + document.body.classList.remove('dark-mode'); + this.articleContent.classList.remove('night-code-theme'); + this.iconDom.className = 'fa fa-moon-o'; + } else { + document.body.classList.add('dark-mode'); + this.articleContent.classList.add('night-code-theme'); + this.iconDom.className = 'fa fa-lightbulb-o'; + } + + } + + } + }, + + initModeToggleButton() { + this.modeToggleButton_dom.addEventListener('click', () => { + if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) { + this.setItemUtil('light-mode', 'dark'); + } else { + this.setItemUtil('dark-mode', 'light'); + } + }); + } + + } + + ILS.utils.modeToggle.initModeStatus(); + ILS.utils.modeToggle.initModeToggleButton(); +}); diff --git a/source/js/header-shrink.js b/source/js/header-shrink.js index f5ba5a3..19b5ab3 100644 --- a/source/js/header-shrink.js +++ b/source/js/header-shrink.js @@ -1,36 +1,50 @@ -const pageTemplateDom = document.querySelector('.page-main-content'); -const sidebarToolsDom = document.querySelector('.sidebar-tools'); -const headerDom = document.querySelector('.header-wrapper'); -const menuBarDom = document.querySelector('.menu-bar'); -const windowMaskDom = document.querySelector('.window-mask'); +window.addEventListener('DOMContentLoaded', () => { + ILS.utils.headerShrink = { + pageTemplateDom: document.querySelector('.page-main-content'), + sidebarToolsDom: document.querySelector('.sidebar-tools'), + headerDom: document.querySelector('.header-wrapper'), + menuBarDom: document.querySelector('.menu-bar'), + windowMaskDom: document.querySelector('.window-mask'), -let isHeaderShrink = false; -const headerHeight = headerDom.getBoundingClientRect().height; + isHeaderShrink: false, -window.addEventListener('scroll', function (_e) { - const scrollTop = document.body.scrollTop || document.documentElement.scrollTop; - if (!isHeaderShrink && scrollTop > headerHeight) { - isHeaderShrink = true; - headerDom.classList.add('header-wrapper-shrink'); - pageTemplateDom.classList.add('page-main-content-top-shrink'); - sidebarToolsDom.classList.add('sidebar-tools-shrink'); + init() { + this.headerHeight = this.headerDom.getBoundingClientRect().height; + }, - } else if (isHeaderShrink && scrollTop <= headerHeight) { - isHeaderShrink = false; - headerDom.classList.remove('header-wrapper-shrink'); - pageTemplateDom.classList.remove('page-main-content-top-shrink'); - sidebarToolsDom.classList.remove('sidebar-tools-shrink'); + headerShrink() { + + const scrollTop = document.body.scrollTop || document.documentElement.scrollTop; + + if (!this.isHeaderShrink && scrollTop > this.headerHeight) { + this.isHeaderShrink = true; + this.headerDom.classList.add('header-wrapper-shrink'); + this.pageTemplateDom.classList.add('page-main-content-top-shrink'); + this.sidebarToolsDom.classList.add('sidebar-tools-shrink'); + + } else if (this.isHeaderShrink && scrollTop <= this.headerHeight) { + this.isHeaderShrink = false; + this.headerDom.classList.remove('header-wrapper-shrink'); + this.pageTemplateDom.classList.remove('page-main-content-top-shrink'); + this.sidebarToolsDom.classList.remove('sidebar-tools-shrink'); + } + + }, + + initMenuBarButton() { + this.menuBarDom.addEventListener('click', () => { + this.headerDom.classList.toggle('header-drawer-show'); + }); + }, + + initWindowMask() { + this.windowMaskDom.addEventListener('click', () => { + this.headerDom.classList.toggle('header-drawer-show'); + }); + }, } + ILS.utils.headerShrink.init(); + ILS.utils.headerShrink.initMenuBarButton(); + ILS.utils.headerShrink.initWindowMask(); }); - - -menuBarDom.addEventListener('click', function (_e) { - headerDom.classList.toggle('header-drawer-show'); -}); - -windowMaskDom.addEventListener('click', function (_e) { - headerDom.classList.toggle('header-drawer-show'); -}); - - diff --git a/source/js/left-side-toggle.js b/source/js/left-side-toggle.js new file mode 100644 index 0000000..a68d200 --- /dev/null +++ b/source/js/left-side-toggle.js @@ -0,0 +1,38 @@ +window.addEventListener('DOMContentLoaded', () => { + + ILS.utils.leftSideToggle = { + + init() { + this.toggleBar = document.querySelector('.page-aside-toggle'); + this.pageTopDom = document.querySelector('.page-main-content-top'); + this.containerDom = document.querySelector('.page-container'); + this.leftAsideDom = document.querySelector('.page-aside'); + this.headerContentDom = document.querySelector('.header-wrapper .header-content'); + this.mainContentDom = document.querySelector('.page-main-content-middle .main-content'); + this.isOpenPageAside = false; + }, + + initToggleBarButton() { + if (this.toggleBar) { + this.toggleBar.addEventListener('click', () => { + this.isOpenPageAside = !this.isOpenPageAside; + this.changePageLayoutWhenOpenToggle(this.isOpenPageAside); + }) + } + }, + + changePageLayoutWhenOpenToggle(isOpen) { + const pageAsideWidth = '258px'; + this.containerDom.style.paddingLeft = isOpen ? pageAsideWidth : '0'; + this.pageTopDom.style.paddingLeft = isOpen ? pageAsideWidth : '0'; + this.pageTopDom.style.paddingLeft = isOpen ? pageAsideWidth : '0'; + this.leftAsideDom.style.left = isOpen ? '0' : `-${pageAsideWidth}`; + this.headerContentDom.style.width = isOpen ? '76%' : '62%'; + this.mainContentDom.style.width = isOpen ? '76%' : '62%'; + }, + } + + ILS.utils.leftSideToggle.init(); + ILS.utils.leftSideToggle.initToggleBarButton(); + +}); diff --git a/source/js/main.js b/source/js/main.js index d0b32f2..08c99ee 100644 --- a/source/js/main.js +++ b/source/js/main.js @@ -1,47 +1,8 @@ window.addEventListener('DOMContentLoaded', () => { - console.log(`${CONFIG.themeInfo.name} v${CONFIG.themeInfo.version}`); + // print theme info + ILS.utils.printThemeInfo(); - pageAsideOpenToggle(); + // init scroll + ILS.utils.initWindowScroll(); }); - - -const pageAsideOpenToggle = () => { - - const toggleDom = document.querySelector('.page-aside-toggle'); - const pageTopDom = document.querySelector('.page-main-content-top'); - const containerDom = document.querySelector('.page-container'); - const leftAsideDom = document.querySelector('.page-aside'); - - const headerContentDom = document.querySelector('.header-wrapper .header-content'); - const mainContentDom = document.querySelector('.page-main-content-middle .main-content'); - - let isOpen = false; - const openToggle = (isOpen) => { - - const pageAsideWidth = '258px'; - containerDom.style.paddingLeft = isOpen ? pageAsideWidth : '0'; - pageTopDom.style.paddingLeft = isOpen ? pageAsideWidth : '0'; - pageTopDom.style.paddingLeft = isOpen ? pageAsideWidth : '0'; - leftAsideDom.style.left = isOpen ? '0' : `-${pageAsideWidth}`; - - headerContentDom.style.width = isOpen ? '76%' : '62%'; - mainContentDom.style.width = isOpen ? '76%' : '62%'; - - } - - - toggleDom.addEventListener('click', () => { - isOpen = !isOpen; - openToggle(isOpen); - }) - - - window.utils = { - openToggle: () => { - isOpen = true; - openToggle(isOpen); - } - } - -} diff --git a/source/js/post-toc.js b/source/js/post-toc.js deleted file mode 100644 index e404f3c..0000000 --- a/source/js/post-toc.js +++ /dev/null @@ -1,10 +0,0 @@ -window.addEventListener('DOMContentLoaded', () => { - const navItems = document.querySelectorAll('.post-toc-wrap .post-toc li'); - const toggleDom = document.querySelector('.page-aside-toggle'); - - if (navItems.length) { - toggleDom.style.display = 'flex'; - window.utils.openToggle(); - } - -}); diff --git a/source/js/scroll-to-top.js b/source/js/scroll-to-top.js deleted file mode 100644 index eb95d22..0000000 --- a/source/js/scroll-to-top.js +++ /dev/null @@ -1,53 +0,0 @@ -(function () { - const scrollToTopDom = document.querySelector('.scroll-to-top'); - const headerProgressDom = document.querySelector('.header-progress'); - const headerWrapper = document.querySelector('.header-wrapper'); - - const backToTop = () => { - let scrollTopTimer = setInterval(function () { - let top = document.body.scrollTop || document.documentElement.scrollTop; - let speed = top / 2; - if (document.body.scrollTop !== 0) { - document.body.scrollTop -= speed; - } else { - document.documentElement.scrollTop -= speed; - } - if (top === 0) { - clearInterval(scrollTopTimer); - } - }, 30); - }; - - scrollToTopDom.addEventListener('click', () => { - backToTop(); - }); - - let prevScroll = 0; - window.addEventListener('scroll', function (_e) { - // back to top & show scroll percent - const scrollTop = document.body.scrollTop || document.documentElement.scrollTop; - const scrollHeight = document.body.scrollHeight || document.documentElement.scrollHeight; - const clientHeight = window.innerHeight || document.documentElement.clientHeight; - const percent = Math.round(scrollTop / (scrollHeight - clientHeight) * 100).toFixed(0); - const ProgressPercent = (scrollTop / (scrollHeight - clientHeight) * 100).toFixed(3); - - if (percent === '0') { - scrollToTopDom.style.display = 'none'; - headerProgressDom.style.display = 'none'; - } else { - scrollToTopDom.style.display = 'flex'; - headerProgressDom.style.display = 'block'; - headerProgressDom.style.width = `${ProgressPercent}%`; - } - - // hide header handle - const opacity = headerWrapper.style.opacity - if (scrollTop > prevScroll && scrollTop > 360) { - if (opacity > 0) headerWrapper.style.opacity = '0'; - } else { - if (opacity < 1) headerWrapper.style.opacity = '1'; - } - prevScroll = scrollTop - }); - -})(); diff --git a/source/js/toc.js b/source/js/toc.js index e5158d6..89424d9 100644 --- a/source/js/toc.js +++ b/source/js/toc.js @@ -1,107 +1,95 @@ window.addEventListener('DOMContentLoaded', () => { - const articleToc = document.querySelector('.article-toc'); - const postTocWrap = document.querySelector('.post-toc-wrap'); - const navItems = postTocWrap.querySelectorAll('.post-toc li'); - const headerWrapper = document.querySelector('.header-wrapper'); + ILS.utils.navItems = document.querySelectorAll('.post-toc-wrap .post-toc li'); + ILS.utils.articleToc_dom = document.querySelector('.article-toc'); + ILS.utils.postTocWrap_dom = document.querySelector('.post-toc-wrap'); + ILS.utils.headerWrapper_dom = document.querySelector('.header-wrapper'); - if (navItems.length > 0) { + if (ILS.utils.navItems.length > 0) { - const sections = [...navItems].map(element => { - let link = element.querySelector('a.nav-link'); - // TOC item animation navigate. - link.addEventListener('click', event => { - event.preventDefault(); - let target = document.getElementById(event.currentTarget.getAttribute('href').replace('#', '')); - let offset = target.getBoundingClientRect().top + window.scrollY - 18; - window.anime({ - targets: document.scrollingElement, - duration: 500, - easing: 'linear', - scrollTop: offset, - complete: function () { - setTimeout(() => { - if (headerWrapper.style.opacity !== '0') headerWrapper.style.opacity = '0' - }, 100) - } + ILS.utils = { + + ...ILS.utils, + + findActiveIndexByTOC() { + if (!Array.isArray(ILS.utils.sections)) return; + let index = ILS.utils.sections.findIndex(element => { + return element && element.getBoundingClientRect().top - 20 > 0; }); - }); - return document.getElementById(link.getAttribute('href').replace('#', '')); - }); - - - function activateNavByIndex(target) { - if (target.classList.contains('active-current')) return; - document.querySelectorAll('.post-toc .active').forEach(element => { - element.classList.remove('active', 'active-current'); - }); - target.classList.add('active', 'active-current'); - let parent = target.parentNode; - while (!parent.matches('.post-toc')) { - if (parent.matches('li')) parent.classList.add('active'); - parent = parent.parentNode; - } - // Scrolling to center active TOC element if TOC content is taller then viewport. - window.anime({ - targets: postTocWrap, - duration: 200, - easing: 'linear', - scrollTop: postTocWrap.scrollTop - (postTocWrap.offsetHeight / 2) + target.getBoundingClientRect().top - postTocWrap.getBoundingClientRect().top - }); - } - - function findIndex(entries) { - let index = 0; - let entry = entries[index]; - if (entry.boundingClientRect.top > 0) { - index = sections.indexOf(entry.target); - return index === 0 ? 0 : index - 1; - } - for (; index < entries.length; index++) { - if (entries[index].boundingClientRect.top <= 0) { - entry = entries[index]; - } else { - return sections.indexOf(entry.target); + if (index === -1) { + index = ILS.utils.sections.length - 1; + } else if (index > 0) { + index--; } - } - return sections.indexOf(entry.target); - } + ILS.utils.activateNavByIndex(index); + }, - function createIntersectionObserver(marginTop) { + registerSidebarTOC() { + ILS.utils.sections = [...document.querySelectorAll('.post-toc li a.nav-link')].map(element => { + const target = document.getElementById(decodeURI(element.getAttribute('href')).replace('#', '')); + element.addEventListener('click', event => { + event.preventDefault(); + const offset = target.getBoundingClientRect().top + window.scrollY; + window.anime({ + targets: document.scrollingElement, + duration: 500, + easing: 'linear', + scrollTop: offset - 10, + complete: function () { + setTimeout(() => { + if (ILS.utils.headerWrapper_dom.style.opacity !== '0') ILS.utils.headerWrapper_dom.style.opacity = '0' + }, 100) + } + }); + }); + return target; + }); + }, - marginTop = Math.floor(marginTop + 10000); - let intersectionObserver = new IntersectionObserver((entries, observe) => { - let scrollHeight = document.documentElement.scrollHeight + 100; - if (scrollHeight > marginTop) { - observe.disconnect(); - createIntersectionObserver(scrollHeight); - return; + activateNavByIndex: function (index) { + const target = document.querySelectorAll('.post-toc li a.nav-link')[index]; + if (!target || target.classList.contains('active-current')) return; + + document.querySelectorAll('.post-toc .active').forEach(element => { + element.classList.remove('active', 'active-current'); + }); + target.classList.add('active', 'active-current'); + let parent = target.parentNode; + while (!parent.matches('.post-toc')) { + if (parent.matches('li')) parent.classList.add('active'); + parent = parent.parentNode; } - let index = findIndex(entries); - activateNavByIndex(navItems[index]); - }, { - rootMargin: marginTop + 'px 0px -100% 0px', - threshold: 0 - }); - sections.forEach(element => { - element && intersectionObserver.observe(element); - }); + // Scrolling to center active TOC element if TOC content is taller then viewport. + const tocElement = document.querySelector('.post-toc-wrap'); + window.anime({ + targets: tocElement, + duration: 200, + easing: 'linear', + scrollTop: tocElement.scrollTop - (tocElement.offsetHeight / 2) + target.getBoundingClientRect().top - tocElement.getBoundingClientRect().top + }); + }, + + showPageAsideWhenHasTOC() { + ILS.utils.leftSideToggle.toggleBar.style.display = 'flex'; + ILS.utils.leftSideToggle.isOpenPageAside = true; + ILS.utils.leftSideToggle.changePageLayoutWhenOpenToggle(ILS.utils.leftSideToggle.isOpenPageAside); + } } - createIntersectionObserver(document.documentElement.scrollHeight); + ILS.utils.showPageAsideWhenHasTOC(); + ILS.utils.registerSidebarTOC(); + } else { - if (postTocWrap) { - postTocWrap.innerHTML = ''; - postTocWrap.style.display = 'none'; + if (ILS.utils.postTocWrap_dom) { + ILS.utils.postTocWrap_dom.innerHTML = ''; + ILS.utils.postTocWrap_dom.style.display = 'none'; } - if (articleToc) { - articleToc.style.display = 'none'; + if (ILS.utils.articleToc_dom) { + ILS.utils.articleToc_dom.style.display = 'none'; } } - - }); diff --git a/source/js/toggle-mode.js b/source/js/toggle-mode.js deleted file mode 100644 index 9d09bff..0000000 --- a/source/js/toggle-mode.js +++ /dev/null @@ -1,70 +0,0 @@ -/** - * 日间/夜间 模式切换 - */ -const localStorageKey = 'MAGIC' -const modeToggleBtn = document.querySelector('.mode-toggle'); -const iconDom = modeToggleBtn.querySelector('i'); -const articleContent = document.querySelector('.main-content'); -const modeConfig = JSON.parse(localStorage.getItem(localStorageKey)); -if (modeConfig) { - - if (modeConfig.prefersColorScheme === 'dark') { - - if (modeConfig.isDark) { - document.body.classList.remove('light-mode'); - articleContent.classList.remove('night-code-theme'); - iconDom.className = 'fa fa-lightbulb-o'; - } else { - iconDom.className = 'fa fa-moon-o'; - document.body.classList.add('light-mode'); - articleContent.classList.add('night-code-theme'); - } - - } else { - - if (modeConfig.isDark) { - document.body.classList.remove('dark-mode'); - articleContent.classList.remove('night-code-theme'); - iconDom.className = 'fa fa-moon-o'; - } else { - document.body.classList.add('dark-mode'); - iconDom.className = 'fa fa-lightbulb-o'; - articleContent.classList.add('night-code-theme'); - } - - } - -} - -const setItemUtil = (modeClass, prefersColorScheme) => { - document.body.classList.toggle(modeClass); - const isDark = document.body.className.indexOf(modeClass) === -1; - - if (isDark) { - iconDom.className = 'fa fa-moon-o'; - articleContent.classList.remove('night-code-theme'); - } else { - iconDom.className = 'fa fa-lightbulb-o'; - articleContent.classList.add('night-code-theme'); - } - localStorage.setItem(localStorageKey, JSON.stringify( - { - prefersColorScheme: prefersColorScheme, - isDark: isDark - } - )); - - -}; - -modeToggleBtn.addEventListener('click', function (e) { - - if ( - window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches - ) { - setItemUtil('light-mode', 'dark'); - } else { - setItemUtil('dark-mode', 'light'); - } - -}); diff --git a/source/js/utils.js b/source/js/utils.js new file mode 100644 index 0000000..075021b --- /dev/null +++ b/source/js/utils.js @@ -0,0 +1,60 @@ +ILS.utils = { + printThemeInfo() { + console.log(`${CONFIG.themeInfo.name} v${CONFIG.themeInfo.version}`); + } +} + +ILS.utils = { + + ...ILS.utils, + + headerProgress_dom: document.querySelector('.header-progress'), + headerWrapper_dom: document.querySelector('.header-wrapper'), + + // Scroll Style Handle + prevScrollValue: 0, + styleHandleWhenScroll() { + const scrollTop = document.body.scrollTop || document.documentElement.scrollTop; + const scrollHeight = document.body.scrollHeight || document.documentElement.scrollHeight; + const clientHeight = window.innerHeight || document.documentElement.clientHeight; + const percent = Math.round(scrollTop / (scrollHeight - clientHeight) * 100).toFixed(0); + const ProgressPercent = (scrollTop / (scrollHeight - clientHeight) * 100).toFixed(3); + + if (CONFIG.back2top.enable && ILS.utils.back2TopButton_dom) { + ILS.utils.back2TopButton_dom.style.display = percent === '0' ? 'none' : 'flex'; + } + + if (ILS.utils.headerProgress_dom) { + ILS.utils.headerProgress_dom.style.display = percent === '0' ? 'none' : 'block'; + ILS.utils.headerProgress_dom.style.width = `${ProgressPercent}%`; + } + + // hide header handle + const opacity = ILS.utils.headerWrapper_dom.style.opacity; + if (scrollTop > ILS.utils.prevScrollValue && scrollTop > 500) { + if (opacity !== '0') ILS.utils.headerWrapper_dom.style.opacity = '0'; + } else { + if (opacity !== '1') ILS.utils.headerWrapper_dom.style.opacity = '1'; + } + ILS.utils.prevScrollValue = scrollTop; + }, + + // 初始 window scroll 事件 + initWindowScroll() { + window.addEventListener('scroll', function (_e) { + // style handle when scroll + ILS.utils.styleHandleWhenScroll(); + + // TOC scroll handle + if (CONFIG.toc.enable && ILS.utils.hasOwnProperty('findActiveIndexByTOC')) { + ILS.utils.findActiveIndexByTOC(); + } + + // header shrink + ILS.utils.headerShrink.headerShrink(); + }); + }, +} + + +