hexo-theme-shokax 0.3.12 → 0.4.0-alpha.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (103) hide show
  1. package/README.md +10 -3
  2. package/README_en.MD +13 -5
  3. package/_config.yml +19 -16
  4. package/layout/_mixin/comment.pug +4 -4
  5. package/layout/_mixin/segment.pug +1 -1
  6. package/layout/_partials/head/head.pug +0 -1
  7. package/layout/_partials/post/post.pug +1 -1
  8. package/layout/_partials/post/reward.pug +1 -1
  9. package/layout/_partials/sidebar/overview.pug +1 -1
  10. package/package.json +11 -11
  11. package/scripts/filters/locals.d.ts +1 -0
  12. package/scripts/filters/locals.ts +59 -0
  13. package/scripts/filters/post.d.ts +0 -0
  14. package/scripts/filters/post.js +1 -1
  15. package/scripts/filters/post.ts +6 -0
  16. package/scripts/generaters/archive.d.ts +1 -0
  17. package/scripts/generaters/archive.ts +144 -0
  18. package/scripts/generaters/config.d.ts +1 -0
  19. package/scripts/generaters/config.ts +52 -0
  20. package/scripts/generaters/images.d.ts +1 -0
  21. package/scripts/generaters/images.ts +26 -0
  22. package/scripts/generaters/index.d.ts +1 -0
  23. package/scripts/generaters/index.ts +110 -0
  24. package/scripts/generaters/pages.d.ts +0 -0
  25. package/scripts/generaters/pages.ts +16 -0
  26. package/scripts/generaters/script.d.ts +1 -0
  27. package/scripts/generaters/script.js +25 -6
  28. package/scripts/generaters/script.ts +110 -0
  29. package/scripts/helpers/asset.d.ts +1 -0
  30. package/scripts/helpers/asset.ts +158 -0
  31. package/scripts/helpers/engine.d.ts +1 -0
  32. package/scripts/helpers/engine.ts +171 -0
  33. package/scripts/helpers/list_categories.d.ts +1 -0
  34. package/scripts/helpers/list_categories.ts +104 -0
  35. package/scripts/helpers/summary_ai.d.ts +1 -0
  36. package/scripts/helpers/summary_ai.js +1 -1
  37. package/scripts/helpers/summary_ai.ts +100 -0
  38. package/scripts/helpers/symbols_count_time.d.ts +1 -0
  39. package/scripts/helpers/symbols_count_time.ts +76 -0
  40. package/scripts/plugin/check.d.ts +1 -0
  41. package/scripts/plugin/check.ts +35 -0
  42. package/scripts/plugin/index.d.ts +6 -0
  43. package/scripts/plugin/index.ts +52 -0
  44. package/scripts/plugin/lib/injects-point.d.ts +5 -0
  45. package/scripts/plugin/lib/injects-point.ts +20 -0
  46. package/scripts/plugin/lib/injects.d.ts +2 -0
  47. package/scripts/plugin/lib/injects.ts +101 -0
  48. package/scripts/tags/links.d.ts +1 -0
  49. package/scripts/tags/links.ts +75 -0
  50. package/scripts/tags/media.d.ts +1 -0
  51. package/scripts/tags/media.ts +19 -0
  52. package/source/css/_common/components/tags/tabs.styl +3 -1
  53. package/source/css/_common/scaffolding/base.styl +6 -6
  54. package/source/css/_iconfont.styl +4 -0
  55. package/source/js/_app/components/sidebar.ts +237 -0
  56. package/source/js/_app/globals/globalVars.ts +98 -0
  57. package/source/js/_app/globals/handles.ts +122 -0
  58. package/source/js/_app/globals/themeColor.ts +64 -0
  59. package/source/js/_app/globals/thirdparty.ts +63 -0
  60. package/source/js/_app/globals/tools.ts +74 -0
  61. package/source/js/_app/library/anime.ts +109 -0
  62. package/source/js/_app/library/declare.d.ts +117 -0
  63. package/source/js/_app/library/dom.ts +26 -0
  64. package/source/js/_app/library/libtype.d.ts +4 -0
  65. package/source/js/_app/library/loadFile.ts +41 -0
  66. package/source/js/_app/library/proto.ts +143 -0
  67. package/source/js/_app/library/scriptPjax.ts +72 -0
  68. package/source/js/_app/library/storage.ts +12 -0
  69. package/source/js/_app/library/vue.ts +60 -0
  70. package/source/js/_app/page/common.ts +42 -0
  71. package/source/js/_app/page/fancybox.ts +70 -0
  72. package/source/js/_app/page/post.ts +265 -0
  73. package/source/js/_app/page/search.ts +129 -0
  74. package/source/js/_app/page/tab.ts +59 -0
  75. package/source/js/_app/pjax/domInit.ts +95 -0
  76. package/source/js/_app/pjax/refresh.ts +75 -0
  77. package/source/js/_app/pjax/siteInit.ts +67 -0
  78. package/source/js/_app/player.ts +798 -0
  79. package/source/css/twikoo.css +0 -2002
  80. package/source/js/_app/components/sidebar.js +0 -210
  81. package/source/js/_app/fireworks.js +0 -10
  82. package/source/js/_app/globals/globalVars.js +0 -80
  83. package/source/js/_app/globals/handles.js +0 -138
  84. package/source/js/_app/globals/themeColor.js +0 -62
  85. package/source/js/_app/globals/thirdparty.js +0 -71
  86. package/source/js/_app/globals/tools.js +0 -92
  87. package/source/js/_app/library/anime.js +0 -109
  88. package/source/js/_app/library/dom.js +0 -34
  89. package/source/js/_app/library/loadFile.js +0 -36
  90. package/source/js/_app/library/proto.js +0 -163
  91. package/source/js/_app/library/scriptPjax.js +0 -70
  92. package/source/js/_app/library/storage.js +0 -12
  93. package/source/js/_app/library/vue.js +0 -53
  94. package/source/js/_app/page/comment.js +0 -23
  95. package/source/js/_app/page/common.js +0 -41
  96. package/source/js/_app/page/fancybox.js +0 -65
  97. package/source/js/_app/page/post.js +0 -244
  98. package/source/js/_app/page/search.js +0 -118
  99. package/source/js/_app/page/tab.js +0 -53
  100. package/source/js/_app/pjax/domInit.js +0 -76
  101. package/source/js/_app/pjax/refresh.js +0 -53
  102. package/source/js/_app/pjax/siteInit.js +0 -49
  103. package/source/js/_app/player.js +0 -774
@@ -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
+ }
@@ -0,0 +1,98 @@
1
+ import { $dom } from '../library/dom'
2
+ import Pjax from 'theme-shokax-pjax'
3
+ import initProto from '../library/proto'
4
+
5
+ initProto()
6
+ export const statics = CONFIG.statics.indexOf('//') > 0 ? CONFIG.statics : CONFIG.root
7
+ export const scrollAction: { x: number, y: number } = { x: 0, y: 0 }
8
+ export let diffY = 0
9
+ export let originTitle: string, titleTime: NodeJS.Timeout
10
+ export const BODY = document.getElementsByTagName('body')[0]
11
+ export const HTML = document.documentElement
12
+ export const Container = $dom('#container')
13
+ export const loadCat = $dom('#loading')
14
+ export const siteNav = $dom('#nav')
15
+ export const siteHeader = $dom('#header')
16
+ export const menuToggle = siteNav.child('.toggle')
17
+ export const quickBtn = $dom('#quick')
18
+ export const sideBar = $dom('#sidebar')
19
+ export const siteBrand = $dom('#brand')
20
+ export let toolBtn = $dom('#tool')
21
+ export let toolPlayer
22
+ export let backToTop: HTMLElement
23
+ export let goToComment
24
+ export let showContents
25
+ export let siteSearch = $dom('#search')
26
+ export let siteNavHeight: number, headerHightInner: number, headerHight: number
27
+ export let oWinHeight = window.innerHeight
28
+ export let oWinWidth = window.innerWidth
29
+ export let LOCAL_HASH = 0
30
+ export let LOCAL_URL = window.location.href
31
+ export let pjax:Pjax
32
+
33
+ export function setSiteNavHeight (value:number):void {
34
+ siteNavHeight = value
35
+ }
36
+ export function setHeaderHightInner (value:number):void {
37
+ headerHightInner = value
38
+ }
39
+
40
+ export function setHeaderHight (value:number):void {
41
+ headerHight = value
42
+ }
43
+
44
+ export function setOWinHeight (value:number):void {
45
+ oWinHeight = value
46
+ }
47
+
48
+ export function setOWinWidth (value:number):void {
49
+ oWinWidth = value
50
+ }
51
+
52
+ export function setDiffY (value:number):void {
53
+ diffY = value
54
+ }
55
+
56
+ export function setTitleTime (value:NodeJS.Timeout):void {
57
+ titleTime = value
58
+ }
59
+
60
+ export function setLocalHash (value:number):void {
61
+ LOCAL_HASH = value
62
+ }
63
+
64
+ export function setLocalUrl (value:string):void {
65
+ LOCAL_URL = value
66
+ }
67
+
68
+ export function setPjax (value:Pjax):void {
69
+ pjax = value
70
+ }
71
+
72
+ export function setOriginTitle (value:string):void {
73
+ originTitle = value
74
+ }
75
+
76
+ export function setToolPlayer (value:any):void {
77
+ toolPlayer = value
78
+ }
79
+
80
+ export function setBackToTop (value:HTMLElement):void {
81
+ backToTop = value
82
+ }
83
+
84
+ export function setGoToComment (value:any):void {
85
+ goToComment = value
86
+ }
87
+
88
+ export function setShowContents (value:any):void {
89
+ showContents = value
90
+ }
91
+
92
+ export function setToolBtn (value:HTMLElement):void {
93
+ toolBtn = value
94
+ }
95
+
96
+ export function setSiteSearch (value:HTMLElement):void {
97
+ siteSearch = value
98
+ }
@@ -0,0 +1,122 @@
1
+ import { sideBarToggleHandle } from '../components/sidebar'
2
+ import { $dom, getDocHeight } from '../library/dom'
3
+ import {
4
+ backToTop,
5
+ diffY,
6
+ headerHight,
7
+ headerHightInner,
8
+ oWinWidth,
9
+ originTitle,
10
+ scrollAction,
11
+ sideBar,
12
+ siteBrand,
13
+ siteHeader,
14
+ siteNav,
15
+ statics,
16
+ titleTime,
17
+ toolBtn,
18
+ setSiteNavHeight,
19
+ setHeaderHightInner,
20
+ setHeaderHight,
21
+ setOWinHeight, setOWinWidth, setDiffY, setTitleTime
22
+ } from './globalVars'
23
+ import { changeMetaTheme } from './themeColor'
24
+ import { Loader } from './thirdparty'
25
+
26
+ export const resizeHandle = () => {
27
+ // 获取 siteNav 的高度
28
+ setSiteNavHeight(siteNav.changeOrGetHeight())
29
+ // 获取 siteHeader 的高度
30
+ setHeaderHightInner(siteHeader.changeOrGetHeight())
31
+ // 获取 #waves 的高度
32
+ setHeaderHight(headerHightInner + $dom('#waves').changeOrGetHeight())
33
+
34
+ // 判断窗口宽度是否改变
35
+ if (oWinWidth !== window.innerWidth) {
36
+ sideBarToggleHandle(null, 1)
37
+ }
38
+
39
+ // 记录窗口高度和宽度
40
+ setOWinHeight(window.innerHeight)
41
+ setOWinWidth(window.innerWidth)
42
+ }
43
+
44
+ export const scrollHandle = () => {
45
+ // 获取窗口高度
46
+ const winHeight = window.innerHeight
47
+ // 获取文档高度
48
+ const docHeight = getDocHeight()
49
+ // 计算可见内容高度
50
+ const contentVisibilityHeight = docHeight > winHeight ? docHeight - winHeight : document.body.scrollHeight - winHeight
51
+ // 判断页面是否滚动超过 headerHightInner
52
+ const SHOW = window.scrollY > headerHightInner
53
+ // 判断页面是否开始滚动
54
+ const startScroll = window.scrollY > 0
55
+
56
+ // 根据条件修改 meta theme
57
+ if (SHOW) {
58
+ changeMetaTheme('#FFF')
59
+ } else {
60
+ changeMetaTheme('#222')
61
+ }
62
+
63
+ // 控制导航栏的显示隐藏
64
+ siteNav.toggleClass('show', SHOW)
65
+ // 控制网站 logo 的显示隐藏
66
+ toolBtn.toggleClass('affix', startScroll)
67
+ // 控制侧边栏的显示隐藏,当滚动高度大于 headerHight 且窗口宽度大于 991px 时显示
68
+ siteBrand.toggleClass('affix', startScroll)
69
+ sideBar.toggleClass('affix', window.scrollY > headerHight && document.body.offsetWidth > 991)
70
+ // 初始化滚动时导航栏的显示方向
71
+ if (typeof scrollAction.y === 'undefined') {
72
+ scrollAction.y = window.scrollY
73
+ }
74
+ setDiffY(scrollAction.y - window.scrollY)
75
+
76
+ // 控制滑动时导航栏显示
77
+ if (diffY < 0) {
78
+ siteNav.removeClass('up')
79
+ siteNav.toggleClass('down', SHOW)
80
+ } else if (diffY > 0) {
81
+ siteNav.removeClass('down')
82
+ siteNav.toggleClass('up', SHOW)
83
+ } else { /* empty */ }
84
+ scrollAction.y = window.scrollY
85
+ // 计算滚动百分比
86
+ const scrollPercent = Math.round(Math.min(100 * window.scrollY / contentVisibilityHeight, 100)) + '%'
87
+ // 更新回到顶部按钮的文字
88
+ if (backToTop.child('span').innerText !== scrollPercent) {
89
+ backToTop.child('span').innerText = scrollPercent
90
+ }
91
+ // 更新百分比进度条的宽度
92
+ if ($dom('#sidebar').hasClass('affix') || $dom('#sidebar').hasClass('on')) {
93
+ $dom('.percent').changeOrGetWidth(scrollPercent)
94
+ }
95
+ }
96
+
97
+ // 可见度监听(离开页面和返回时更改document的title)
98
+ export const visibilityListener = () => {
99
+ const iconNode = $dom('[rel="icon"]')
100
+ document.addEventListener('visibilitychange', () => {
101
+ switch (document.visibilityState) {
102
+ case 'hidden':
103
+ iconNode.setAttribute('href', statics + CONFIG.favicon.hidden)
104
+ document.title = LOCAL.favicon.hide
105
+ if (CONFIG.loader.switch) {
106
+ Loader.show()
107
+ }
108
+ clearTimeout(titleTime)
109
+ break
110
+ case 'visible':
111
+ iconNode.setAttribute('href', statics + CONFIG.favicon.normal)
112
+ document.title = LOCAL.favicon.show
113
+ if (CONFIG.loader.switch) {
114
+ Loader.hide(1000)
115
+ }
116
+ setTitleTime(setTimeout(() => {
117
+ document.title = originTitle
118
+ }, 2000))
119
+ break
120
+ }
121
+ })
122
+ }
@@ -0,0 +1,64 @@
1
+ import { $storage } from '../library/storage'
2
+ import { $dom } from '../library/dom'
3
+ import { HTML } from './globalVars'
4
+
5
+ /**
6
+ * 更改日夜模式
7
+ */
8
+ export const changeTheme = (type?: string) => {
9
+ const btn = <HTMLElement>$dom('.theme .ic')
10
+ if (type === 'dark') {
11
+ HTML.setAttribute('data-theme', type)
12
+ btn.removeClass('i-sun')
13
+ btn.addClass('i-moon')
14
+ } else {
15
+ HTML.removeAttribute('data-theme')
16
+ btn.removeClass('i-moon')
17
+ btn.addClass('i-sun')
18
+ }
19
+ }
20
+
21
+ /**
22
+ * 自动调整黑夜白天
23
+ * 优先级: 手动选择>时间>跟随系统
24
+ */
25
+ export const autoDarkmode = () => {
26
+ if (CONFIG.auto_dark.enable) {
27
+ if (new Date().getHours() >= CONFIG.auto_dark.start || new Date().getHours() <= CONFIG.auto_dark.end) {
28
+ changeTheme('dark')
29
+ } else {
30
+ changeTheme()
31
+ }
32
+ }
33
+ }
34
+
35
+ /**
36
+ * 更改主题的meta
37
+ */
38
+ export const changeMetaTheme = (color: string): void => {
39
+ if (HTML.getAttribute('data-theme') === 'dark') {
40
+ color = '#222'
41
+ }
42
+
43
+ $dom('meta[name="theme-color"]').setAttribute('content', color)
44
+ }
45
+
46
+ // 记忆日夜模式切换和系统亮暗模式监听
47
+ export const themeColorListener = () => {
48
+ window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', (mediaQueryList) => {
49
+ if (mediaQueryList.matches) {
50
+ changeTheme('dark')
51
+ } else {
52
+ changeTheme()
53
+ }
54
+ })
55
+
56
+ const t = $storage.get('theme')
57
+ if (t) {
58
+ changeTheme(t)
59
+ } else {
60
+ if (CONFIG.darkmode) {
61
+ changeTheme('dark')
62
+ }
63
+ }
64
+ }
@@ -0,0 +1,63 @@
1
+ // 与第三方js的交互或第三方嵌入js
2
+
3
+ import { loadCat } from './globalVars'
4
+ import { transition } from '../library/anime'
5
+
6
+ // 加载动画
7
+ export const Loader = {
8
+ timer: undefined,
9
+ lock: false,
10
+ show () {
11
+ clearTimeout(this.timer)
12
+ document.body.removeClass('loaded')
13
+ loadCat.setAttribute('style', 'display:block')
14
+ Loader.lock = false
15
+ },
16
+ hide (sec?: number) {
17
+ if (!CONFIG.loader.start) {
18
+ sec = -1
19
+ }
20
+ this.timer = setTimeout(this.vanish, sec || 3000)
21
+ },
22
+ vanish (): void {
23
+ if (Loader.lock) {
24
+ return
25
+ }
26
+ if (CONFIG.loader.start) {
27
+ transition(loadCat, 0)
28
+ }
29
+ document.body.addClass('loaded')
30
+ Loader.lock = true
31
+ }
32
+ }
33
+
34
+ export const isOutime = (): void => {
35
+ let updateTime: Date
36
+ const times = document.getElementsByTagName('time')
37
+ if (times.length === 0) {
38
+ return
39
+ }
40
+ const posts = document.getElementsByClassName('body md')
41
+ if (posts.length === 0) {
42
+ return
43
+ }
44
+
45
+ const now = Date.now() // 当前时间戳
46
+ const pubTime = new Date(times[0].dateTime) // 文章发布时间戳
47
+ if (times.length === 1) {
48
+ updateTime = pubTime // 文章发布时间亦是最后更新时间
49
+ } else {
50
+ updateTime = new Date(times[1].dateTime) // 文章最后更新时间戳
51
+ }
52
+ // @ts-ignore
53
+ const interval = parseInt(String(now - updateTime)) // 时间差
54
+ const days = parseInt(String(CONFIG.outime.days)) || 30 // 设置时效,默认硬编码 30 天
55
+ // 最后一次更新时间超过 days 天(毫秒)
56
+ if (interval > (days * 86400000)) {
57
+ // @ts-ignore
58
+ const publish = parseInt(String((now - pubTime) / 86400000))
59
+ const updated = parseInt(String(interval / 86400000))
60
+ const template = LOCAL.template.replace('{{publish}}', String(publish)).replace('{{updated}}', String(updated))
61
+ posts[0].insertAdjacentHTML('afterbegin', template)
62
+ }
63
+ }
@@ -0,0 +1,74 @@
1
+ import { pageScroll } from '../library/anime'
2
+ import { $dom } from '../library/dom'
3
+ import { $storage } from '../library/storage'
4
+ import { BODY, LOCAL_HASH, LOCAL_URL, scrollAction, setLocalHash } from './globalVars'
5
+
6
+ // 显示提示(现阶段用于版权及复制结果提示)
7
+ export const showtip = (msg: string): void | never => {
8
+ if (!msg) {
9
+ return
10
+ }
11
+
12
+ const tipbox = BODY.createChild('div', {
13
+ innerHTML: msg,
14
+ className: 'tip'
15
+ })
16
+
17
+ setTimeout(() => {
18
+ tipbox.addClass('hide')
19
+ setTimeout(() => {
20
+ BODY.removeChild(tipbox)
21
+ }, 300)
22
+ }, 3000)
23
+ }
24
+
25
+ export const pagePosition = () => {
26
+ // 判断配置项是否开启了自动记录滚动位置
27
+ if (CONFIG.auto_scroll) {
28
+ // 将当前页面的滚动位置存入本地缓存
29
+ $storage.set(LOCAL_URL, String(scrollAction.y))
30
+ }
31
+ }
32
+
33
+ export const positionInit = (comment?: boolean) => {
34
+ // 获取页面锚点
35
+ const anchor = window.location.hash
36
+
37
+ let target = null
38
+ if (LOCAL_HASH) {
39
+ $storage.del(LOCAL_URL)
40
+ return
41
+ }
42
+
43
+ if (anchor) {
44
+ target = $dom(decodeURI(anchor))
45
+ } else {
46
+ target = CONFIG.auto_scroll ? parseInt($storage.get(LOCAL_URL)) : 0
47
+ }
48
+
49
+ if (target) {
50
+ pageScroll(target)
51
+ setLocalHash(1)
52
+ }
53
+
54
+ if (comment && anchor && !LOCAL_HASH) {
55
+ pageScroll(target)
56
+ setLocalHash(1)
57
+ }
58
+ }
59
+
60
+ /*
61
+ 基于clipboard API的复制功能,仅在https环境下有效
62
+ */
63
+ export const clipBoard = (str: string, callback?: (result:boolean) => void) => {
64
+ if (navigator.clipboard && window.isSecureContext) {
65
+ navigator.clipboard.writeText(str).then(() => {
66
+ callback && callback(true)
67
+ }, () => {
68
+ callback && callback(false)
69
+ })
70
+ } else {
71
+ console.error('Too old browser, clipborad API not supported.')
72
+ callback && callback(false)
73
+ }
74
+ }