refactor: partial code refactoring && optimization TOC
This commit is contained in:
parent
72bb6ac530
commit
b3a397f7dd
|
@ -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
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------------------
|
||||
|
|
|
@ -15,10 +15,14 @@
|
|||
title = __('tag') + ': ' + page.tag;
|
||||
} else if (page.title === 'about') {
|
||||
title = __('about');
|
||||
} else if (page.title === 'links') {
|
||||
title = __('links');
|
||||
}
|
||||
%>
|
||||
<title>
|
||||
<% if (title){ %><%= title %> | <% } %><%= config.title %>
|
||||
<% if (title){ %><%= title %> |
|
||||
<% } %>
|
||||
<%= config.title %>
|
||||
</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
||||
<% if (theme.style.favicon){ %>
|
||||
|
|
|
@ -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']) %>
|
||||
<% } %>
|
||||
<% } %>
|
||||
|
||||
|
|
|
@ -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 `<script id="hexo-configurations">
|
||||
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,
|
||||
toc: theme.toc,
|
||||
back2top: theme.back2top
|
||||
};
|
||||
if (config.search) {
|
||||
exportConfig.path = config.search.path;
|
||||
}
|
||||
return `<script id="hexo-configurations">
|
||||
let ILS = window.ILS || {};
|
||||
let CONFIG = ${JSON.stringify(exportConfig)};
|
||||
</script>`;
|
||||
});
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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();
|
||||
});
|
||||
|
||||
|
|
@ -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', '<div class="copy-btn"><i class="fa fa-clipboard"></i></div>');
|
||||
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', '<div class="copy-btn"><i class="fa fa-clipboard"></i></div>');
|
||||
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);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -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();
|
||||
});
|
|
@ -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');
|
||||
});
|
||||
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
||||
});
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
});
|
|
@ -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
|
||||
});
|
||||
|
||||
})();
|
162
source/js/toc.js
162
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';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
});
|
||||
|
||||
|
|
|
@ -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');
|
||||
}
|
||||
|
||||
});
|
|
@ -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();
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue