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
|
# See: https://github.com/theme-next/hexo-generator-searchdb
|
||||||
# ---------------------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------------------
|
||||||
local_search:
|
local_search:
|
||||||
enable: true
|
enable: false
|
||||||
|
|
||||||
# If auto, trigger search by changing input.
|
# If auto, trigger search by changing input.
|
||||||
# If manual, trigger search by pressing enter key or search button.
|
# If manual, trigger search by pressing enter key or search button.
|
||||||
|
@ -141,7 +141,7 @@ side_tools:
|
||||||
# Back to top
|
# Back to top
|
||||||
# ---------------------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------------------
|
||||||
back2top:
|
back2top:
|
||||||
enable: false
|
enable: true
|
||||||
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------------------
|
||||||
|
|
|
@ -15,10 +15,14 @@
|
||||||
title = __('tag') + ': ' + page.tag;
|
title = __('tag') + ': ' + page.tag;
|
||||||
} else if (page.title === 'about') {
|
} else if (page.title === 'about') {
|
||||||
title = __('about');
|
title = __('about');
|
||||||
|
} else if (page.title === 'links') {
|
||||||
|
title = __('links');
|
||||||
}
|
}
|
||||||
%>
|
%>
|
||||||
<title>
|
<title>
|
||||||
<% if (title){ %><%= title %> | <% } %><%= config.title %>
|
<% if (title){ %><%= title %> |
|
||||||
|
<% } %>
|
||||||
|
<%= config.title %>
|
||||||
</title>
|
</title>
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
||||||
<% if (theme.style.favicon){ %>
|
<% if (theme.style.favicon){ %>
|
||||||
|
|
|
@ -1,21 +1,24 @@
|
||||||
<%- js([
|
<%- js([
|
||||||
'js/main.js',
|
'js/utils.js',
|
||||||
'js/header-shrink.js',
|
'js/header-shrink.js',
|
||||||
'js/toggle-mode.js'
|
'js/dark-light-toggle.js',
|
||||||
|
'js/main.js'
|
||||||
]) %>
|
]) %>
|
||||||
|
|
||||||
<% if (theme.back2top.enable) { %>
|
<% if (theme.back2top.enable) { %>
|
||||||
<%- js('js/scroll-to-top.js') %>
|
<%- js('js/back2top.js') %>
|
||||||
<% } %>
|
<% } %>
|
||||||
|
|
||||||
<% if (is_post()) { %>
|
<% if (is_post()) { %>
|
||||||
|
|
||||||
|
<%- js('js/left-side-toggle.js') %>
|
||||||
|
|
||||||
<% if (theme.code_copy.enable) { %>
|
<% if (theme.code_copy.enable) { %>
|
||||||
<%- js('js/code-copy.js') %>
|
<%- js('js/code-copy.js') %>
|
||||||
<% } %>
|
<% } %>
|
||||||
|
|
||||||
<% if (theme.toc.enable) { %>
|
<% 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
|
* Export theme config to js
|
||||||
*/
|
*/
|
||||||
hexo.extend.helper.register('export_config', function () {
|
hexo.extend.helper.register('export_config', function () {
|
||||||
let {config, theme} = this;
|
let {config, theme} = this;
|
||||||
let exportConfig = {
|
let exportConfig = {
|
||||||
hostname: url.parse(config.url).hostname || config.url,
|
hostname: url.parse(config.url).hostname || config.url,
|
||||||
root: config.root,
|
root: config.root,
|
||||||
localsearch: theme.local_search,
|
localsearch: theme.local_search,
|
||||||
themeInfo: theme.theme_info,
|
themeInfo: theme.theme_info,
|
||||||
codeblock: theme.codeblock
|
codeblock: theme.codeblock,
|
||||||
};
|
toc: theme.toc,
|
||||||
if (config.search) {
|
back2top: theme.back2top
|
||||||
exportConfig.path = config.search.path;
|
};
|
||||||
}
|
if (config.search) {
|
||||||
return `<script id="hexo-configurations">
|
exportConfig.path = config.search.path;
|
||||||
|
}
|
||||||
|
return `<script id="hexo-configurations">
|
||||||
|
let ILS = window.ILS || {};
|
||||||
let CONFIG = ${JSON.stringify(exportConfig)};
|
let CONFIG = ${JSON.stringify(exportConfig)};
|
||||||
</script>`;
|
</script>`;
|
||||||
});
|
});
|
||||||
|
|
|
@ -69,15 +69,14 @@
|
||||||
|
|
||||||
|
|
||||||
h1, h2, h3, h4, h5, h6 {
|
h1, h2, h3, h4, h5, h6 {
|
||||||
// TODO: ...
|
|
||||||
}
|
}
|
||||||
|
|
||||||
h1 {
|
h1 {
|
||||||
color: var(--second-text-color);
|
color: var(--second-text-color);
|
||||||
font-size: 2em;
|
font-size: 2em;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
margin-block-start: 1.1em;
|
margin-block-start: 1.4em;
|
||||||
margin-block-end: 1.1em;
|
margin-block-end: 1.0em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -85,16 +84,16 @@
|
||||||
color: var(--second-text-color);
|
color: var(--second-text-color);
|
||||||
font-size: 1.8em;
|
font-size: 1.8em;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
margin-block-start: 1.1em;
|
margin-block-start: 1.4em;
|
||||||
margin-block-end: 1.1em;
|
margin-block-end: 1.0em;
|
||||||
}
|
}
|
||||||
|
|
||||||
h3 {
|
h3 {
|
||||||
color: var(--second-text-color);
|
color: var(--second-text-color);
|
||||||
font-size: 1.6em;
|
font-size: 1.6em;
|
||||||
font-weight: 550;
|
font-weight: 550;
|
||||||
margin-block-start: 1em;
|
margin-block-start: 1.2em;
|
||||||
margin-block-end: 1em;
|
margin-block-end: 0.8em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -102,16 +101,16 @@
|
||||||
color: var(--second-text-color);
|
color: var(--second-text-color);
|
||||||
font-size: 1.4em;
|
font-size: 1.4em;
|
||||||
font-weight: 550;
|
font-weight: 550;
|
||||||
margin-block-start: 1em;
|
margin-block-start: 1.2em;
|
||||||
margin-block-end: 1em;
|
margin-block-end: 0.8em;
|
||||||
}
|
}
|
||||||
|
|
||||||
h5 {
|
h5 {
|
||||||
color: var(--second-text-color);
|
color: var(--second-text-color);
|
||||||
font-size: 1.2em;
|
font-size: 1.2em;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
margin-block-start: 0.9em;
|
margin-block-start: 1.0em;
|
||||||
margin-block-end: 0.9em;
|
margin-block-end: 0.6em;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -119,8 +118,8 @@
|
||||||
color: var(--second-text-color);
|
color: var(--second-text-color);
|
||||||
font-size: 1.2em;
|
font-size: 1.2em;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
margin-block-start: 0.9em;
|
margin-block-start: 1.0em;
|
||||||
margin-block-end: 0.9em;
|
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) {
|
HTMLElement.prototype.wrap = function (wrapper) {
|
||||||
this.parentNode.insertBefore(wrapper, this);
|
this.parentNode.insertBefore(wrapper, this);
|
||||||
this.parentNode.removeChild(this);
|
this.parentNode.removeChild(this);
|
||||||
wrapper.appendChild(this);
|
wrapper.appendChild(this);
|
||||||
};
|
};
|
||||||
|
|
||||||
window.addEventListener('DOMContentLoaded', () => {
|
window.addEventListener('DOMContentLoaded', () => {
|
||||||
document.querySelectorAll('figure.highlight').forEach(element => {
|
document.querySelectorAll('figure.highlight').forEach(element => {
|
||||||
const box = document.createElement('div');
|
const box = document.createElement('div');
|
||||||
element.wrap(box);
|
element.wrap(box);
|
||||||
box.classList.add('highlight-container');
|
box.classList.add('highlight-container');
|
||||||
box.insertAdjacentHTML('beforeend', '<div class="copy-btn"><i class="fa fa-clipboard"></i></div>');
|
box.insertAdjacentHTML('beforeend', '<div class="copy-btn"><i class="fa fa-clipboard"></i></div>');
|
||||||
var button = element.parentNode.querySelector('.copy-btn');
|
var button = element.parentNode.querySelector('.copy-btn');
|
||||||
button.addEventListener('click', event => {
|
button.addEventListener('click', event => {
|
||||||
var target = event.currentTarget;
|
var target = event.currentTarget;
|
||||||
var code = [...target.parentNode.querySelectorAll('.code .line')].map(line => line.innerText).join('\n');
|
var code = [...target.parentNode.querySelectorAll('.code .line')].map(line => line.innerText).join('\n');
|
||||||
var ta = document.createElement('textarea');
|
var ta = document.createElement('textarea');
|
||||||
ta.style.top = window.scrollY + 'px'; // Prevent page scrolling
|
ta.style.top = window.scrollY + 'px'; // Prevent page scrolling
|
||||||
ta.style.position = 'absolute';
|
ta.style.position = 'absolute';
|
||||||
ta.style.opacity = '0';
|
ta.style.opacity = '0';
|
||||||
ta.readOnly = true;
|
ta.readOnly = true;
|
||||||
ta.value = code;
|
ta.value = code;
|
||||||
document.body.append(ta);
|
document.body.append(ta);
|
||||||
const selection = document.getSelection();
|
const selection = document.getSelection();
|
||||||
const selected = selection.rangeCount > 0 ? selection.getRangeAt(0) : false;
|
const selected = selection.rangeCount > 0 ? selection.getRangeAt(0) : false;
|
||||||
ta.select();
|
ta.select();
|
||||||
ta.setSelectionRange(0, code.length);
|
ta.setSelectionRange(0, code.length);
|
||||||
ta.readOnly = false;
|
ta.readOnly = false;
|
||||||
var result = document.execCommand('copy');
|
var result = document.execCommand('copy');
|
||||||
target.querySelector('i').className = result ? 'fa fa-check' : 'fa fa-times';
|
target.querySelector('i').className = result ? 'fa fa-check' : 'fa fa-times';
|
||||||
ta.blur(); // For iOS
|
ta.blur(); // For iOS
|
||||||
target.blur();
|
target.blur();
|
||||||
if (selected) {
|
if (selected) {
|
||||||
selection.removeAllRanges();
|
selection.removeAllRanges();
|
||||||
selection.addRange(selected);
|
selection.addRange(selected);
|
||||||
}
|
}
|
||||||
document.body.removeChild(ta);
|
document.body.removeChild(ta);
|
||||||
});
|
|
||||||
button.addEventListener('mouseleave', event => {
|
|
||||||
setTimeout(() => {
|
|
||||||
event.target.querySelector('i').className = 'fa fa-clipboard';
|
|
||||||
}, 300);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
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');
|
window.addEventListener('DOMContentLoaded', () => {
|
||||||
const sidebarToolsDom = document.querySelector('.sidebar-tools');
|
ILS.utils.headerShrink = {
|
||||||
const headerDom = document.querySelector('.header-wrapper');
|
|
||||||
const menuBarDom = document.querySelector('.menu-bar');
|
|
||||||
const windowMaskDom = document.querySelector('.window-mask');
|
|
||||||
|
|
||||||
|
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;
|
isHeaderShrink: false,
|
||||||
const headerHeight = headerDom.getBoundingClientRect().height;
|
|
||||||
|
|
||||||
window.addEventListener('scroll', function (_e) {
|
init() {
|
||||||
const scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
|
this.headerHeight = this.headerDom.getBoundingClientRect().height;
|
||||||
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');
|
|
||||||
|
|
||||||
} else if (isHeaderShrink && scrollTop <= headerHeight) {
|
headerShrink() {
|
||||||
isHeaderShrink = false;
|
|
||||||
headerDom.classList.remove('header-wrapper-shrink');
|
const scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
|
||||||
pageTemplateDom.classList.remove('page-main-content-top-shrink');
|
|
||||||
sidebarToolsDom.classList.remove('sidebar-tools-shrink');
|
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', () => {
|
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', () => {
|
window.addEventListener('DOMContentLoaded', () => {
|
||||||
|
|
||||||
const articleToc = document.querySelector('.article-toc');
|
ILS.utils.navItems = document.querySelectorAll('.post-toc-wrap .post-toc li');
|
||||||
const postTocWrap = document.querySelector('.post-toc-wrap');
|
ILS.utils.articleToc_dom = document.querySelector('.article-toc');
|
||||||
const navItems = postTocWrap.querySelectorAll('.post-toc li');
|
ILS.utils.postTocWrap_dom = document.querySelector('.post-toc-wrap');
|
||||||
const headerWrapper = document.querySelector('.header-wrapper');
|
ILS.utils.headerWrapper_dom = document.querySelector('.header-wrapper');
|
||||||
|
|
||||||
if (navItems.length > 0) {
|
if (ILS.utils.navItems.length > 0) {
|
||||||
|
|
||||||
const sections = [...navItems].map(element => {
|
ILS.utils = {
|
||||||
let link = element.querySelector('a.nav-link');
|
|
||||||
// TOC item animation navigate.
|
...ILS.utils,
|
||||||
link.addEventListener('click', event => {
|
|
||||||
event.preventDefault();
|
findActiveIndexByTOC() {
|
||||||
let target = document.getElementById(event.currentTarget.getAttribute('href').replace('#', ''));
|
if (!Array.isArray(ILS.utils.sections)) return;
|
||||||
let offset = target.getBoundingClientRect().top + window.scrollY - 18;
|
let index = ILS.utils.sections.findIndex(element => {
|
||||||
window.anime({
|
return element && element.getBoundingClientRect().top - 20 > 0;
|
||||||
targets: document.scrollingElement,
|
|
||||||
duration: 500,
|
|
||||||
easing: 'linear',
|
|
||||||
scrollTop: offset,
|
|
||||||
complete: function () {
|
|
||||||
setTimeout(() => {
|
|
||||||
if (headerWrapper.style.opacity !== '0') headerWrapper.style.opacity = '0'
|
|
||||||
}, 100)
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
});
|
if (index === -1) {
|
||||||
return document.getElementById(link.getAttribute('href').replace('#', ''));
|
index = ILS.utils.sections.length - 1;
|
||||||
});
|
} else if (index > 0) {
|
||||||
|
index--;
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
ILS.utils.activateNavByIndex(index);
|
||||||
return sections.indexOf(entry.target);
|
},
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
activateNavByIndex: function (index) {
|
||||||
let intersectionObserver = new IntersectionObserver((entries, observe) => {
|
const target = document.querySelectorAll('.post-toc li a.nav-link')[index];
|
||||||
let scrollHeight = document.documentElement.scrollHeight + 100;
|
if (!target || target.classList.contains('active-current')) return;
|
||||||
if (scrollHeight > marginTop) {
|
|
||||||
observe.disconnect();
|
document.querySelectorAll('.post-toc .active').forEach(element => {
|
||||||
createIntersectionObserver(scrollHeight);
|
element.classList.remove('active', 'active-current');
|
||||||
return;
|
});
|
||||||
|
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);
|
// Scrolling to center active TOC element if TOC content is taller then viewport.
|
||||||
activateNavByIndex(navItems[index]);
|
const tocElement = document.querySelector('.post-toc-wrap');
|
||||||
}, {
|
window.anime({
|
||||||
rootMargin: marginTop + 'px 0px -100% 0px',
|
targets: tocElement,
|
||||||
threshold: 0
|
duration: 200,
|
||||||
});
|
easing: 'linear',
|
||||||
sections.forEach(element => {
|
scrollTop: tocElement.scrollTop - (tocElement.offsetHeight / 2) + target.getBoundingClientRect().top - tocElement.getBoundingClientRect().top
|
||||||
element && intersectionObserver.observe(element);
|
});
|
||||||
});
|
},
|
||||||
|
|
||||||
|
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 {
|
} else {
|
||||||
|
|
||||||
if (postTocWrap) {
|
if (ILS.utils.postTocWrap_dom) {
|
||||||
postTocWrap.innerHTML = '';
|
ILS.utils.postTocWrap_dom.innerHTML = '';
|
||||||
postTocWrap.style.display = 'none';
|
ILS.utils.postTocWrap_dom.style.display = 'none';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (articleToc) {
|
if (ILS.utils.articleToc_dom) {
|
||||||
articleToc.style.display = 'none';
|
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