hexo-theme-shokax 0.3.13 → 0.4.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/_config.yml +11 -5
- package/layout/_mixin/comment.pug +4 -4
- package/package.json +4 -4
- package/scripts/filters/locals.d.ts +1 -0
- package/scripts/filters/locals.ts +59 -0
- package/scripts/filters/post.d.ts +0 -0
- package/scripts/filters/post.ts +6 -0
- package/scripts/generaters/archive.d.ts +1 -0
- package/scripts/generaters/archive.ts +144 -0
- package/scripts/generaters/config.d.ts +1 -0
- package/scripts/generaters/config.ts +52 -0
- package/scripts/generaters/images.d.ts +1 -0
- package/scripts/generaters/images.ts +26 -0
- package/scripts/generaters/index.d.ts +1 -0
- package/scripts/generaters/index.ts +110 -0
- package/scripts/generaters/pages.d.ts +0 -0
- package/scripts/generaters/pages.ts +16 -0
- package/scripts/generaters/script.d.ts +1 -0
- package/scripts/generaters/script.js +22 -6
- package/scripts/generaters/script.ts +110 -0
- package/scripts/helpers/asset.d.ts +1 -0
- package/scripts/helpers/asset.ts +158 -0
- package/scripts/helpers/engine.d.ts +1 -0
- package/scripts/helpers/engine.ts +171 -0
- package/scripts/helpers/list_categories.d.ts +1 -0
- package/scripts/helpers/list_categories.ts +104 -0
- package/scripts/helpers/summary_ai.d.ts +1 -0
- package/scripts/helpers/summary_ai.ts +100 -0
- package/scripts/helpers/symbols_count_time.d.ts +1 -0
- package/scripts/helpers/symbols_count_time.ts +76 -0
- package/scripts/plugin/check.d.ts +1 -0
- package/scripts/plugin/check.ts +35 -0
- package/scripts/plugin/index.d.ts +6 -0
- package/scripts/plugin/index.ts +52 -0
- package/scripts/plugin/lib/injects-point.d.ts +5 -0
- package/scripts/plugin/lib/injects-point.ts +20 -0
- package/scripts/plugin/lib/injects.d.ts +2 -0
- package/scripts/plugin/lib/injects.ts +101 -0
- package/scripts/tags/links.d.ts +1 -0
- package/scripts/tags/links.ts +75 -0
- package/scripts/tags/media.d.ts +1 -0
- package/scripts/tags/media.ts +19 -0
- package/source/js/_app/components/sidebar.ts +237 -0
- package/source/js/_app/globals/globalVars.ts +98 -0
- package/source/js/_app/globals/handles.ts +122 -0
- package/source/js/_app/globals/themeColor.ts +64 -0
- package/source/js/_app/globals/thirdparty.ts +63 -0
- package/source/js/_app/globals/tools.ts +74 -0
- package/source/js/_app/library/anime.ts +109 -0
- package/source/js/_app/library/declare.d.ts +117 -0
- package/source/js/_app/library/dom.ts +26 -0
- package/source/js/_app/library/libtype.d.ts +4 -0
- package/source/js/_app/library/loadFile.ts +41 -0
- package/source/js/_app/library/proto.ts +143 -0
- package/source/js/_app/library/scriptPjax.ts +72 -0
- package/source/js/_app/library/storage.ts +12 -0
- package/source/js/_app/library/vue.ts +60 -0
- package/source/js/_app/page/common.ts +42 -0
- package/source/js/_app/page/fancybox.ts +70 -0
- package/source/js/_app/page/post.ts +265 -0
- package/source/js/_app/page/search.ts +129 -0
- package/source/js/_app/page/tab.ts +59 -0
- package/source/js/_app/pjax/domInit.ts +95 -0
- package/source/js/_app/pjax/refresh.ts +75 -0
- package/source/js/_app/pjax/siteInit.ts +67 -0
- package/source/js/_app/player.ts +798 -0
- package/source/js/_app/components/sidebar.js +0 -209
- package/source/js/_app/fireworks.js +0 -10
- package/source/js/_app/globals/globalVars.js +0 -80
- package/source/js/_app/globals/handles.js +0 -98
- package/source/js/_app/globals/themeColor.js +0 -62
- package/source/js/_app/globals/thirdparty.js +0 -62
- package/source/js/_app/globals/tools.js +0 -66
- package/source/js/_app/library/anime.js +0 -106
- package/source/js/_app/library/dom.js +0 -34
- package/source/js/_app/library/loadFile.js +0 -36
- package/source/js/_app/library/proto.js +0 -163
- package/source/js/_app/library/scriptPjax.js +0 -70
- package/source/js/_app/library/storage.js +0 -12
- package/source/js/_app/library/vue.js +0 -53
- package/source/js/_app/page/comment.js +0 -23
- package/source/js/_app/page/common.js +0 -41
- package/source/js/_app/page/fancybox.js +0 -65
- package/source/js/_app/page/post.js +0 -244
- package/source/js/_app/page/search.js +0 -118
- package/source/js/_app/page/tab.js +0 -53
- package/source/js/_app/pjax/domInit.js +0 -76
- package/source/js/_app/pjax/refresh.js +0 -52
- package/source/js/_app/pjax/siteInit.js +0 -51
- package/source/js/_app/player.js +0 -771
@@ -0,0 +1,76 @@
|
|
1
|
+
'use strict'
|
2
|
+
/* global hexo */
|
3
|
+
/*!
|
4
|
+
hexo-symbols-count-time by theme-next
|
5
|
+
under GNU Lesser General Public License v3.0 or later
|
6
|
+
https://github.com/theme-next/hexo-symbols-count-time/blob/master/LICENSE
|
7
|
+
*/
|
8
|
+
|
9
|
+
import { stripHTML } from 'hexo-util'
|
10
|
+
|
11
|
+
const config = hexo.config.symbols_count_time = Object.assign({
|
12
|
+
symbols: true,
|
13
|
+
time: true,
|
14
|
+
total_symbols: true,
|
15
|
+
total_time: true,
|
16
|
+
exclude_codeblock: false,
|
17
|
+
awl: 4,
|
18
|
+
wpm: 275,
|
19
|
+
suffix: 'mins.'
|
20
|
+
}, hexo.config.symbols_count_time)
|
21
|
+
|
22
|
+
function getSymbols (post) {
|
23
|
+
return post?._content?.length ?? post?.content?.length ?? post.length
|
24
|
+
}
|
25
|
+
|
26
|
+
function getSymbolsTotal (site) {
|
27
|
+
let symbolsResultCount = 0
|
28
|
+
site.posts.forEach((post) => {
|
29
|
+
symbolsResultCount += getSymbols(post)
|
30
|
+
})
|
31
|
+
return symbolsResultCount
|
32
|
+
}
|
33
|
+
|
34
|
+
function getFormatTime (minutes, suffix) {
|
35
|
+
const fHours = Math.floor(minutes / 60)
|
36
|
+
let fMinutes = Math.floor(minutes - (fHours * 60))
|
37
|
+
if (fMinutes < 1) {
|
38
|
+
fMinutes = 1 // 0 => 1
|
39
|
+
}
|
40
|
+
return fHours < 1
|
41
|
+
? fMinutes + ' ' + suffix // < 59 => 59 mins.
|
42
|
+
: fHours + ':' + ('00' + fMinutes).slice(-2) // = 61 => 1:01
|
43
|
+
}
|
44
|
+
|
45
|
+
hexo.extend.helper.register('symbolsCount', function (post) {
|
46
|
+
let symbolsResult = getSymbols(post)
|
47
|
+
if (symbolsResult > 9999) {
|
48
|
+
symbolsResult = Math.round(symbolsResult / 1000) + 'k' // > 9999 => 11k
|
49
|
+
} else if (symbolsResult > 999) {
|
50
|
+
symbolsResult = Math.round(symbolsResult / 100) / 10 + 'k' // > 999 => 1.1k
|
51
|
+
} // < 999 => 111
|
52
|
+
return symbolsResult
|
53
|
+
})
|
54
|
+
|
55
|
+
hexo.extend.helper.register('symbolsTime', function (post, awl = config.awl, wpm = config.wpm, suffix = config.suffix) {
|
56
|
+
const minutes = Math.round(getSymbols(post) / (awl * wpm))
|
57
|
+
return getFormatTime(minutes, suffix)
|
58
|
+
})
|
59
|
+
|
60
|
+
hexo.extend.helper.register('symbolsCountTotal', function (site) {
|
61
|
+
const symbolsResultTotal = getSymbolsTotal(site)
|
62
|
+
return symbolsResultTotal < 1000000
|
63
|
+
? Math.round(symbolsResultTotal / 1000) + 'k' // < 999k => 111k
|
64
|
+
: Math.round(symbolsResultTotal / 100000) / 10 + 'm' // > 999k => 1.1m
|
65
|
+
})
|
66
|
+
|
67
|
+
hexo.extend.helper.register('symbolsTimeTotal', function (site, awl = config.awl, wpm = config.wpm, suffix = config.suffix) {
|
68
|
+
const minutes = Math.round(getSymbolsTotal(site) / (awl * wpm))
|
69
|
+
return getFormatTime(minutes, suffix)
|
70
|
+
})
|
71
|
+
|
72
|
+
hexo.extend.filter.register('after_post_render', (data) => {
|
73
|
+
let { content } = data
|
74
|
+
if (config.exclude_codeblock) content = content.replace(/<pre>.*?<\/pre>/g, '')
|
75
|
+
data.length = stripHTML(content).replace(/\r?\n|\r/g, '').replace(/\s+/g, '').length
|
76
|
+
}, 0)
|
@@ -0,0 +1 @@
|
|
1
|
+
declare let findProblem: boolean;
|
@@ -0,0 +1,35 @@
|
|
1
|
+
/* global hexo */
|
2
|
+
|
3
|
+
let findProblem = false
|
4
|
+
|
5
|
+
hexo.on('generateBefore', function () {
|
6
|
+
if (hexo.config.syntax_highlighter) {
|
7
|
+
findProblem = true
|
8
|
+
hexo.log.error('[SXEC 101] Highlight.js or Prismjs enabled. The code block will render incomplete')
|
9
|
+
}
|
10
|
+
if (!hexo.config.markdown) {
|
11
|
+
findProblem = true
|
12
|
+
hexo.log.error(`[SXEC 102] Critical rendering plugins are missing or incorrectly configured.
|
13
|
+
Some features will be disabled or render incorrectly`)
|
14
|
+
}
|
15
|
+
if (parseInt(process.version.match(/\d{2,3}/)[0]) < 18) {
|
16
|
+
findProblem = true
|
17
|
+
hexo.log.error('[SXEC 103] Too old Node.js version, install the latest LTS version')
|
18
|
+
}
|
19
|
+
if (!hexo.config.title || !hexo.config.description || !hexo.config.language || !hexo.config.timezone || !hexo.config.url) {
|
20
|
+
findProblem = true
|
21
|
+
hexo.log.warn('[SXEC 201] Essential information(title, desc, lang, etc) config incorrectly, Page will render incorrectly')
|
22
|
+
}
|
23
|
+
if (hexo.theme.config.gitalk?.clientID || hexo.theme.config.giscus?.repo) {
|
24
|
+
findProblem = true
|
25
|
+
hexo.log.warn('[SXEC 202] You are using an deprecated feature and it was removed in the v0.3.10')
|
26
|
+
}
|
27
|
+
})
|
28
|
+
|
29
|
+
hexo.on('generateAfter', function () {
|
30
|
+
if (findProblem) {
|
31
|
+
hexo.log.warn(`The environment check found some problems that can lead to rendering errors, effect errors,
|
32
|
+
performance degradation, not working correctly, etc`)
|
33
|
+
hexo.log.warn('ShokaX has output them into console, read them to get more information. You can search error code in docs(For example, SXEC 101)')
|
34
|
+
}
|
35
|
+
})
|
@@ -0,0 +1,52 @@
|
|
1
|
+
/*!
|
2
|
+
index.js in next-theme/hexo-theme-next by next-theme
|
3
|
+
under GNU AFFERO GENERAL PUBLIC LICENSE v3.0 OR LATER
|
4
|
+
https://github.com/next-theme/hexo-theme-next/blob/master/LICENSE.md
|
5
|
+
*/
|
6
|
+
|
7
|
+
import injects from './lib/injects'
|
8
|
+
import { version } from '../../package.json'
|
9
|
+
import * as fs from 'node:fs'
|
10
|
+
|
11
|
+
hexo.on('generateBefore', () => {
|
12
|
+
// 加载`theme_injects`过滤器
|
13
|
+
injects(hexo)
|
14
|
+
if (fs.existsSync('request.lock')) {
|
15
|
+
fs.unlinkSync('request.lock')
|
16
|
+
}
|
17
|
+
if (fs.existsSync('requested.lock')) {
|
18
|
+
fs.unlinkSync('requested.lock')
|
19
|
+
}
|
20
|
+
})
|
21
|
+
|
22
|
+
hexo.on('generateAfter', () => {
|
23
|
+
// 检查版本更新
|
24
|
+
fetch('https://api.github.com/repos/theme-shoka-x/hexo-theme-shokaX/releases/latest').then((res) => {
|
25
|
+
res.json().then((resp) => {
|
26
|
+
try {
|
27
|
+
const latest = resp.tag_name.replace('v', '').split('.')
|
28
|
+
const current = version.split('.')
|
29
|
+
let isOutdated = false
|
30
|
+
for (let i = 0; i < Math.max(latest.length, current.length); i++) {
|
31
|
+
if (!current[i] || latest[i] > current[i]) {
|
32
|
+
isOutdated = true
|
33
|
+
break
|
34
|
+
}
|
35
|
+
if (latest[i] < current[i]) {
|
36
|
+
break
|
37
|
+
}
|
38
|
+
}
|
39
|
+
if (isOutdated) {
|
40
|
+
hexo.log.warn(`Your theme ShokaX is outdated. Current version: v${current.join('.')}, latest version: v${latest.join('.')}`)
|
41
|
+
hexo.log.warn('Visit https://github.com/theme-shoka-x/hexo-theme-shokaX/releases for more information.')
|
42
|
+
}
|
43
|
+
} catch (e) {
|
44
|
+
hexo.log.warn('Failed to detect version info. Error message:')
|
45
|
+
hexo.log.warn(e)
|
46
|
+
}
|
47
|
+
}).catch((e) => {
|
48
|
+
hexo.log.warn('Failed to detect version info. Error message:')
|
49
|
+
hexo.log.warn(e)
|
50
|
+
})
|
51
|
+
})
|
52
|
+
})
|
@@ -0,0 +1,101 @@
|
|
1
|
+
'use strict'
|
2
|
+
|
3
|
+
/*!
|
4
|
+
inject.js in next-theme/hexo-theme-next by next-theme
|
5
|
+
under GNU AFFERO GENERAL PUBLIC LICENSE v3.0 OR LATER
|
6
|
+
https://github.com/next-theme/hexo-theme-next/blob/master/LICENSE.md
|
7
|
+
*/
|
8
|
+
import fs from 'node:fs'
|
9
|
+
import path from 'node:path'
|
10
|
+
import points from './injects-point'
|
11
|
+
const defaultExtname = '.pug'
|
12
|
+
|
13
|
+
interface viewConfig {
|
14
|
+
layout: string,
|
15
|
+
locals: object,
|
16
|
+
options: object,
|
17
|
+
order: number
|
18
|
+
}
|
19
|
+
class StylusInject {
|
20
|
+
files: Array<string>
|
21
|
+
base_dir: string
|
22
|
+
constructor (base_dir) {
|
23
|
+
this.base_dir = base_dir
|
24
|
+
this.files = []
|
25
|
+
}
|
26
|
+
|
27
|
+
push (file) {
|
28
|
+
this.files.push(path.resolve(this.base_dir, file))
|
29
|
+
}
|
30
|
+
}
|
31
|
+
|
32
|
+
// Defining view types
|
33
|
+
class ViewInject {
|
34
|
+
base_dir:string
|
35
|
+
raws: Array<object>
|
36
|
+
constructor (base_dir) {
|
37
|
+
this.base_dir = base_dir
|
38
|
+
this.raws = []
|
39
|
+
}
|
40
|
+
|
41
|
+
raw (name, raw, ...args) {
|
42
|
+
// Set default extname
|
43
|
+
if (path.extname(name) === '') {
|
44
|
+
name += defaultExtname
|
45
|
+
}
|
46
|
+
this.raws.push({ name, raw, args })
|
47
|
+
}
|
48
|
+
|
49
|
+
file (name, file, ...args) {
|
50
|
+
// Set default extname from file's extname
|
51
|
+
if (path.extname(name) === '') {
|
52
|
+
name += path.extname(file)
|
53
|
+
}
|
54
|
+
// Get absolute path base on hexo dir
|
55
|
+
this.raw(name, fs.readFileSync(path.resolve(this.base_dir, file), 'utf8'), ...args)
|
56
|
+
}
|
57
|
+
}
|
58
|
+
|
59
|
+
// Init injects
|
60
|
+
function initInject (base_dir) {
|
61
|
+
const injects = {}
|
62
|
+
points.styles.forEach(item => {
|
63
|
+
injects[item] = new StylusInject(base_dir)
|
64
|
+
})
|
65
|
+
points.views.forEach(item => {
|
66
|
+
injects[item] = new ViewInject(base_dir)
|
67
|
+
})
|
68
|
+
return injects
|
69
|
+
}
|
70
|
+
|
71
|
+
export default (hexo) => {
|
72
|
+
// Exec theme_inject filter
|
73
|
+
const injects = initInject(hexo.base_dir)
|
74
|
+
hexo.execFilterSync('theme_inject', injects)
|
75
|
+
hexo.theme.config.injects = {}
|
76
|
+
|
77
|
+
// Inject stylus
|
78
|
+
points.styles.forEach(type => {
|
79
|
+
hexo.theme.config.injects[type] = injects[type].files
|
80
|
+
})
|
81
|
+
|
82
|
+
// Inject views
|
83
|
+
points.views.forEach(type => {
|
84
|
+
const configs = Object.create(null)
|
85
|
+
hexo.theme.config.injects[type] = []
|
86
|
+
// Add or override view.
|
87
|
+
injects[type].raws.forEach((injectObj, index) => {
|
88
|
+
const name = `inject/${type}/${injectObj.name}`
|
89
|
+
hexo.theme.setView(name, injectObj.raw)
|
90
|
+
configs[name] = {
|
91
|
+
layout: name,
|
92
|
+
locals: injectObj.args[0],
|
93
|
+
options: injectObj.args[1],
|
94
|
+
order: injectObj.args[2] || index
|
95
|
+
}
|
96
|
+
})
|
97
|
+
// Views sort.
|
98
|
+
hexo.theme.config.injects[type] = Object.values(configs)
|
99
|
+
.sort((x:viewConfig, y:viewConfig) => x.order - y.order)
|
100
|
+
})
|
101
|
+
}
|
@@ -0,0 +1 @@
|
|
1
|
+
export {};
|
@@ -0,0 +1,75 @@
|
|
1
|
+
import fs from 'node:fs'
|
2
|
+
import path from 'node:path'
|
3
|
+
import yaml from 'js-yaml'
|
4
|
+
|
5
|
+
/*
|
6
|
+
{% links %}
|
7
|
+
- site: #main title
|
8
|
+
owner: #alternate title for image tooltip (nullable)
|
9
|
+
url: #link of site
|
10
|
+
desc: #description (nullable)
|
11
|
+
image: #icon image (nullable)
|
12
|
+
color: #block color (nullable)
|
13
|
+
{% endlinks %}
|
14
|
+
|
15
|
+
{% linksfile [path] %}
|
16
|
+
*/
|
17
|
+
|
18
|
+
interface siteLink {
|
19
|
+
site: string
|
20
|
+
owner?: string
|
21
|
+
url: string
|
22
|
+
desc?: string
|
23
|
+
image?: string
|
24
|
+
color?: string
|
25
|
+
}
|
26
|
+
|
27
|
+
function linkGrid (args:string[], content:string) {
|
28
|
+
const theme = hexo.theme.config as any
|
29
|
+
|
30
|
+
if (!args[0] && !content) {
|
31
|
+
return
|
32
|
+
}
|
33
|
+
|
34
|
+
if (args[0]) {
|
35
|
+
const filepath = path.join(hexo.source_dir, args[0])
|
36
|
+
if (fs.existsSync(filepath)) {
|
37
|
+
content = fs.readFileSync(filepath, { encoding: 'utf-8' })
|
38
|
+
}
|
39
|
+
}
|
40
|
+
|
41
|
+
if (!content) {
|
42
|
+
return
|
43
|
+
}
|
44
|
+
|
45
|
+
const list = yaml.load(content) as Array<siteLink>
|
46
|
+
|
47
|
+
let result = ''
|
48
|
+
|
49
|
+
list.forEach((item) => {
|
50
|
+
if (!item.url || !item.site) {
|
51
|
+
return
|
52
|
+
}
|
53
|
+
|
54
|
+
let item_image = item.image || theme.assets + '/404.png'
|
55
|
+
|
56
|
+
if (!item_image.startsWith('//') && !item_image.startsWith('http')) {
|
57
|
+
item_image = theme.statics + item_image
|
58
|
+
}
|
59
|
+
|
60
|
+
item.color = item.color ? ` style="--block-color:${item.color};"` : ''
|
61
|
+
|
62
|
+
result += `<div class="item" title="${item.owner || item.site}"${item.color}>`
|
63
|
+
|
64
|
+
result += `<a href="${item.url}" class="image" data-background-image="${item_image}"></a>
|
65
|
+
<div class="info">
|
66
|
+
<a href="${item.url}" class="title">${item.site}</a>
|
67
|
+
<p class="desc">${item.desc || item.url}</p>
|
68
|
+
</div></div>`
|
69
|
+
})
|
70
|
+
|
71
|
+
return `<div class="links">${result}</div>`
|
72
|
+
}
|
73
|
+
|
74
|
+
hexo.extend.tag.register('links', linkGrid, { ends: true })
|
75
|
+
hexo.extend.tag.register('linksfile', linkGrid, { ends: false, async: true })
|
@@ -0,0 +1 @@
|
|
1
|
+
export {};
|
@@ -0,0 +1,19 @@
|
|
1
|
+
'use strict'
|
2
|
+
/* global hexo */
|
3
|
+
import yaml from 'js-yaml'
|
4
|
+
|
5
|
+
function postMedia (args, content) {
|
6
|
+
if (!args[0] || !content) {
|
7
|
+
return
|
8
|
+
}
|
9
|
+
const list = yaml.load(content)
|
10
|
+
switch (args[0]) {
|
11
|
+
case 'video':
|
12
|
+
case 'audio':
|
13
|
+
return `<div class="media-container"><div class="player" data-type="${args[0]}" data-src='${JSON.stringify(list)}'></div></div>`
|
14
|
+
}
|
15
|
+
}
|
16
|
+
|
17
|
+
hexo.extend.tag.register('media', postMedia, { ends: true })
|
18
|
+
|
19
|
+
// return `<video src="${args}" preload="metadata" controls playsinline poster="">Sorry, your browser does not support the video tag.</video>`;
|
@@ -0,0 +1,237 @@
|
|
1
|
+
/* 边栏分区 */
|
2
|
+
|
3
|
+
import { Container, diffY, menuToggle, showContents, sideBar } from '../globals/globalVars'
|
4
|
+
import { clipBoard } from '../globals/tools'
|
5
|
+
import { pageScroll, transition } from '../library/anime'
|
6
|
+
import { $dom } from '../library/dom'
|
7
|
+
|
8
|
+
export const sideBarToggleHandle = (event:Event, force?:number) => {
|
9
|
+
if (sideBar.hasClass('on')) {
|
10
|
+
sideBar.removeClass('on')
|
11
|
+
menuToggle.removeClass('close')
|
12
|
+
if (force) {
|
13
|
+
// @ts-ignore
|
14
|
+
// noinspection JSConstantReassignment
|
15
|
+
sideBar.style = ''
|
16
|
+
} else {
|
17
|
+
transition(sideBar, 'slideRightOut')
|
18
|
+
}
|
19
|
+
} else {
|
20
|
+
if (force) {
|
21
|
+
// @ts-ignore
|
22
|
+
// noinspection JSConstantReassignment
|
23
|
+
sideBar.style = ''
|
24
|
+
} else {
|
25
|
+
transition(sideBar, 'slideRightIn', () => {
|
26
|
+
sideBar.addClass('on')
|
27
|
+
menuToggle.addClass('close')
|
28
|
+
})
|
29
|
+
}
|
30
|
+
}
|
31
|
+
}
|
32
|
+
|
33
|
+
export const sideBarTab = () => {
|
34
|
+
const sideBarInner = sideBar.child('.inner')
|
35
|
+
|
36
|
+
if (sideBar.child('.tab')) {
|
37
|
+
sideBarInner.removeChild(sideBar.child('.tab'))
|
38
|
+
}
|
39
|
+
|
40
|
+
const list = document.createElement('ul'); let active = 'active'
|
41
|
+
list.className = 'tab';
|
42
|
+
|
43
|
+
['contents', 'related', 'overview'].forEach((item) => {
|
44
|
+
const element = sideBar.child('.panel.' + item)
|
45
|
+
|
46
|
+
if (element.innerHTML.trim().length < 1) {
|
47
|
+
if (item === 'contents') {
|
48
|
+
showContents.display('none')
|
49
|
+
}
|
50
|
+
return
|
51
|
+
}
|
52
|
+
|
53
|
+
if (item === 'contents') {
|
54
|
+
showContents.display('')
|
55
|
+
}
|
56
|
+
|
57
|
+
const tab = document.createElement('li')
|
58
|
+
const span = document.createElement('span')
|
59
|
+
const text = document.createTextNode(element.getAttribute('data-title'))
|
60
|
+
span.appendChild(text)
|
61
|
+
tab.appendChild(span)
|
62
|
+
tab.addClass(item + ' item')
|
63
|
+
|
64
|
+
if (active) {
|
65
|
+
element.addClass(active)
|
66
|
+
tab.addClass(active)
|
67
|
+
} else {
|
68
|
+
element.removeClass('active')
|
69
|
+
}
|
70
|
+
tab.addEventListener('click', (event) => {
|
71
|
+
const target = event.currentTarget as HTMLElement
|
72
|
+
if (target.hasClass('active')) return
|
73
|
+
|
74
|
+
sideBar.find('.tab .item').forEach((element) => {
|
75
|
+
element.removeClass('active')
|
76
|
+
})
|
77
|
+
|
78
|
+
sideBar.find('.panel').forEach((element) => {
|
79
|
+
element.removeClass('active')
|
80
|
+
})
|
81
|
+
|
82
|
+
sideBar.child('.panel.' + target.className.replace(' item', '')).addClass('active')
|
83
|
+
|
84
|
+
target.addClass('active')
|
85
|
+
})
|
86
|
+
|
87
|
+
list.appendChild(tab)
|
88
|
+
active = ''
|
89
|
+
})
|
90
|
+
|
91
|
+
if (list.childNodes.length > 1) {
|
92
|
+
sideBarInner.insertBefore(list, sideBarInner.childNodes[0])
|
93
|
+
sideBar.child('.panels').style.paddingTop = ''
|
94
|
+
} else {
|
95
|
+
sideBar.child('.panels').style.paddingTop = '.625rem'
|
96
|
+
}
|
97
|
+
}
|
98
|
+
|
99
|
+
export const sidebarTOC = () => {
|
100
|
+
const activateNavByIndex = (index:number): void => {
|
101
|
+
const target = navItems[index]
|
102
|
+
|
103
|
+
if (!target) return
|
104
|
+
|
105
|
+
if (target.hasClass('current')) {
|
106
|
+
return
|
107
|
+
}
|
108
|
+
|
109
|
+
$dom.each('.toc .active', (element) => {
|
110
|
+
element && element.removeClass('active current')
|
111
|
+
})
|
112
|
+
|
113
|
+
sections.forEach((element) => {
|
114
|
+
element && element.removeClass('active')
|
115
|
+
})
|
116
|
+
|
117
|
+
target.addClass('active current')
|
118
|
+
sections[index] && sections[index].addClass('active')
|
119
|
+
|
120
|
+
let parent = <Element> target.parentNode
|
121
|
+
|
122
|
+
while (!parent.matches('.contents')) {
|
123
|
+
if (parent.matches('li')) {
|
124
|
+
parent.addClass('active')
|
125
|
+
const t = $dom(parent.child('a.toc-link').getAttribute('href'))
|
126
|
+
if (t) {
|
127
|
+
t.addClass('active')
|
128
|
+
}
|
129
|
+
}
|
130
|
+
parent = <Element> parent.parentNode
|
131
|
+
}
|
132
|
+
// Scrolling to center active TOC element if TOC content is taller than viewport.
|
133
|
+
if (getComputedStyle(sideBar).display !== 'none' && tocElement.hasClass('active')) {
|
134
|
+
pageScroll(tocElement, target.offsetTop - (tocElement.offsetHeight / 4))
|
135
|
+
}
|
136
|
+
}
|
137
|
+
const navItems = $dom.all('.contents li')
|
138
|
+
|
139
|
+
if (navItems.length < 1) {
|
140
|
+
return
|
141
|
+
}
|
142
|
+
|
143
|
+
let sections = [...navItems]
|
144
|
+
let activeLock = null
|
145
|
+
|
146
|
+
sections = sections.map((element, index) => {
|
147
|
+
const link = element.child('a.toc-link')
|
148
|
+
const anchor = $dom(decodeURI(link.getAttribute('href')))
|
149
|
+
if (!anchor) return null
|
150
|
+
const alink = anchor.child('a.anchor')
|
151
|
+
|
152
|
+
const anchorScroll = (event:MouseEvent) => {
|
153
|
+
event.preventDefault()
|
154
|
+
const target = $dom(decodeURI((event.currentTarget as HTMLElement).getAttribute('href')))
|
155
|
+
|
156
|
+
activeLock = index
|
157
|
+
pageScroll(target, null, () => {
|
158
|
+
activateNavByIndex(index)
|
159
|
+
activeLock = null
|
160
|
+
})
|
161
|
+
}
|
162
|
+
|
163
|
+
// TOC item animation navigate.
|
164
|
+
link.addEventListener('click', anchorScroll)
|
165
|
+
alink && alink.addEventListener('click', (event) => {
|
166
|
+
anchorScroll(event)
|
167
|
+
clipBoard(CONFIG.hostname + '/' + LOCAL.path + (event.currentTarget as HTMLElement).getAttribute('href'))
|
168
|
+
})
|
169
|
+
return anchor
|
170
|
+
})
|
171
|
+
|
172
|
+
const tocElement = sideBar.child('.contents.panel')
|
173
|
+
|
174
|
+
const findIndex = (entries: IntersectionObserverEntry[]) => {
|
175
|
+
let index = 0
|
176
|
+
let entry = entries[index]
|
177
|
+
|
178
|
+
if (entry.boundingClientRect.top > 0) {
|
179
|
+
index = sections.indexOf(entry.target as HTMLElement)
|
180
|
+
return index === 0 ? 0 : index - 1
|
181
|
+
}
|
182
|
+
for (; index < entries.length; index++) {
|
183
|
+
if (entries[index].boundingClientRect.top <= 0) {
|
184
|
+
entry = entries[index]
|
185
|
+
} else {
|
186
|
+
return sections.indexOf(entry.target as HTMLElement)
|
187
|
+
}
|
188
|
+
}
|
189
|
+
return sections.indexOf(entry.target as HTMLElement)
|
190
|
+
}
|
191
|
+
|
192
|
+
const createIntersectionObserver = () => {
|
193
|
+
const observer = new IntersectionObserver((entries) => {
|
194
|
+
const index = findIndex(entries) + (diffY < 0 ? 1 : 0)
|
195
|
+
if (activeLock === null) {
|
196
|
+
activateNavByIndex(index)
|
197
|
+
}
|
198
|
+
}, {
|
199
|
+
rootMargin: '0px 0px -100% 0px', threshold: 0
|
200
|
+
})
|
201
|
+
|
202
|
+
sections.forEach((element) => {
|
203
|
+
element && observer.observe(element)
|
204
|
+
})
|
205
|
+
}
|
206
|
+
|
207
|
+
createIntersectionObserver()
|
208
|
+
}
|
209
|
+
|
210
|
+
export const backToTopHandle = () => {
|
211
|
+
pageScroll(0)
|
212
|
+
}
|
213
|
+
|
214
|
+
export const goToBottomHandle = () => {
|
215
|
+
pageScroll(parseInt(String(Container.changeOrGetHeight())))
|
216
|
+
}
|
217
|
+
|
218
|
+
export const goToCommentHandle = () => {
|
219
|
+
pageScroll($dom('#comments'))
|
220
|
+
}
|
221
|
+
|
222
|
+
export const menuActive = () => {
|
223
|
+
$dom.each('.menu .item:not(.title)', (element) => {
|
224
|
+
const target = <HTMLAnchorElement> element.child('a[href]')
|
225
|
+
const parentItem = element.parentNode.parentNode
|
226
|
+
if (!target) return
|
227
|
+
const isSamePath = target.pathname === location.pathname || target.pathname === location.pathname.replace('index.html', '')
|
228
|
+
const isSubPath = !CONFIG.root.startsWith(target.pathname) && location.pathname.startsWith(target.pathname)
|
229
|
+
const active = target.hostname === location.hostname && (isSamePath || isSubPath)
|
230
|
+
element.toggleClass('active', active)
|
231
|
+
if (element.parentNode.child('.active') && parentItem.hasClass('dropdown')) {
|
232
|
+
parentItem.removeClass('active').addClass('expand')
|
233
|
+
} else {
|
234
|
+
parentItem.removeClass('expand')
|
235
|
+
}
|
236
|
+
})
|
237
|
+
}
|