hexo-theme-shokax 0.3.13 → 0.4.0-alpha.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (62) hide show
  1. package/_config.yml +16 -9
  2. package/layout/_mixin/comment.pug +4 -4
  3. package/layout/_partials/footer.pug +1 -1
  4. package/layout/_partials/head/head.pug +7 -1
  5. package/layout/_partials/header.pug +1 -1
  6. package/layout/_partials/layout.pug +0 -10
  7. package/layout/_partials/post/footer.pug +1 -2
  8. package/package.json +10 -5
  9. package/scripts/generaters/archive.js +1 -1
  10. package/scripts/generaters/script.js +64 -42
  11. package/scripts/helpers/asset.js +1 -1
  12. package/scripts/helpers/list_categories.js +0 -4
  13. package/scripts/plugin/lib/injects.js +1 -1
  14. package/source/js/_app/components/comments.ts +33 -0
  15. package/source/js/_app/components/sidebar.ts +239 -0
  16. package/source/js/_app/globals/globalVars.ts +99 -0
  17. package/source/js/_app/globals/handles.ts +123 -0
  18. package/source/js/_app/globals/themeColor.ts +64 -0
  19. package/source/js/_app/globals/thirdparty.ts +63 -0
  20. package/source/js/_app/globals/tools.ts +75 -0
  21. package/source/js/_app/library/anime.ts +110 -0
  22. package/source/js/_app/library/declare.d.ts +126 -0
  23. package/source/js/_app/library/dom.ts +26 -0
  24. package/source/js/_app/library/loadFile.ts +43 -0
  25. package/source/js/_app/library/proto.ts +141 -0
  26. package/source/js/_app/library/scriptPjax.ts +72 -0
  27. package/source/js/_app/library/storage.ts +12 -0
  28. package/source/js/_app/library/vue.ts +50 -0
  29. package/source/js/_app/page/common.ts +42 -0
  30. package/source/js/_app/page/fancybox.ts +71 -0
  31. package/source/js/_app/page/post.ts +266 -0
  32. package/source/js/_app/page/search.ts +135 -0
  33. package/source/js/_app/page/tab.ts +60 -0
  34. package/source/js/_app/pjax/domInit.ts +96 -0
  35. package/source/js/_app/pjax/refresh.ts +78 -0
  36. package/source/js/_app/pjax/siteInit.ts +72 -0
  37. package/source/js/_app/player.ts +799 -0
  38. package/source/assets/beian.webp +0 -0
  39. package/source/js/_app/components/sidebar.js +0 -209
  40. package/source/js/_app/fireworks.js +0 -10
  41. package/source/js/_app/globals/globalVars.js +0 -80
  42. package/source/js/_app/globals/handles.js +0 -98
  43. package/source/js/_app/globals/themeColor.js +0 -62
  44. package/source/js/_app/globals/thirdparty.js +0 -62
  45. package/source/js/_app/globals/tools.js +0 -66
  46. package/source/js/_app/library/anime.js +0 -106
  47. package/source/js/_app/library/dom.js +0 -34
  48. package/source/js/_app/library/loadFile.js +0 -36
  49. package/source/js/_app/library/proto.js +0 -163
  50. package/source/js/_app/library/scriptPjax.js +0 -70
  51. package/source/js/_app/library/storage.js +0 -12
  52. package/source/js/_app/library/vue.js +0 -53
  53. package/source/js/_app/page/comment.js +0 -23
  54. package/source/js/_app/page/common.js +0 -41
  55. package/source/js/_app/page/fancybox.js +0 -65
  56. package/source/js/_app/page/post.js +0 -244
  57. package/source/js/_app/page/search.js +0 -118
  58. package/source/js/_app/page/tab.js +0 -53
  59. package/source/js/_app/pjax/domInit.js +0 -76
  60. package/source/js/_app/pjax/refresh.js +0 -52
  61. package/source/js/_app/pjax/siteInit.js +0 -51
  62. package/source/js/_app/player.js +0 -771
@@ -0,0 +1,239 @@
1
+ /* 边栏分区 */
2
+
3
+ import { CONFIG, 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
+ import initProto, { child, getHeight, setDisplay } from '../library/proto'
8
+
9
+ initProto()
10
+ export const sideBarToggleHandle = (event:Event, force?:number) => {
11
+ if (sideBar.hasClass('on')) {
12
+ sideBar.removeClass('on')
13
+ menuToggle.removeClass('close')
14
+ if (force) {
15
+ // @ts-ignore
16
+ // noinspection JSConstantReassignment
17
+ sideBar.style = ''
18
+ } else {
19
+ transition(sideBar, 'slideRightOut')
20
+ }
21
+ } else {
22
+ if (force) {
23
+ // @ts-ignore
24
+ // noinspection JSConstantReassignment
25
+ sideBar.style = ''
26
+ } else {
27
+ transition(sideBar, 'slideRightIn', () => {
28
+ sideBar.addClass('on')
29
+ menuToggle.addClass('close')
30
+ })
31
+ }
32
+ }
33
+ }
34
+
35
+ export const sideBarTab = () => {
36
+ const sideBarInner = child(sideBar, '.inner')
37
+
38
+ if (sideBar.child('.tab')) {
39
+ sideBarInner.removeChild(sideBar.child('.tab'))
40
+ }
41
+
42
+ const list = document.createElement('ul'); let active = 'active'
43
+ list.className = 'tab';
44
+
45
+ ['contents', 'related', 'overview'].forEach((item) => {
46
+ const element = sideBar.child('.panel.' + item)
47
+
48
+ if (element.innerHTML.trim().length < 1) {
49
+ if (item === 'contents') {
50
+ setDisplay(showContents, 'none')
51
+ }
52
+ return
53
+ }
54
+
55
+ if (item === 'contents') {
56
+ setDisplay(showContents, '')
57
+ }
58
+
59
+ const tab = document.createElement('li')
60
+ const span = document.createElement('span')
61
+ const text = document.createTextNode(element.getAttribute('data-title'))
62
+ span.appendChild(text)
63
+ tab.appendChild(span)
64
+ tab.addClass(item + ' item')
65
+
66
+ if (active) {
67
+ element.addClass(active)
68
+ tab.addClass(active)
69
+ } else {
70
+ element.removeClass('active')
71
+ }
72
+ tab.addEventListener('click', (event) => {
73
+ const target = event.currentTarget as HTMLElement
74
+ if (target.hasClass('active')) return
75
+
76
+ sideBar.find('.tab .item').forEach((element) => {
77
+ element.removeClass('active')
78
+ })
79
+
80
+ sideBar.find('.panel').forEach((element) => {
81
+ element.removeClass('active')
82
+ })
83
+
84
+ sideBar.child('.panel.' + target.className.replace(' item', '')).addClass('active')
85
+
86
+ target.addClass('active')
87
+ })
88
+
89
+ list.appendChild(tab)
90
+ active = ''
91
+ })
92
+
93
+ if (list.childNodes.length > 1) {
94
+ sideBarInner.insertBefore(list, sideBarInner.childNodes[0])
95
+ sideBar.child('.panels').style.paddingTop = ''
96
+ } else {
97
+ sideBar.child('.panels').style.paddingTop = '.625rem'
98
+ }
99
+ }
100
+
101
+ export const sidebarTOC = () => {
102
+ const activateNavByIndex = (index:number): void => {
103
+ const target = navItems[index]
104
+
105
+ if (!target) return
106
+
107
+ if (target.hasClass('current')) {
108
+ return
109
+ }
110
+
111
+ $dom.each('.toc .active', (element) => {
112
+ element && element.removeClass('active current')
113
+ })
114
+
115
+ sections.forEach((element) => {
116
+ element && element.removeClass('active')
117
+ })
118
+
119
+ target.addClass('active current')
120
+ sections[index] && sections[index].addClass('active')
121
+
122
+ let parent = <Element> target.parentNode
123
+
124
+ while (!parent.matches('.contents')) {
125
+ if (parent.matches('li')) {
126
+ parent.addClass('active')
127
+ const t = $dom(parent.child('a.toc-link').getAttribute('href'))
128
+ if (t) {
129
+ t.addClass('active')
130
+ }
131
+ }
132
+ parent = <Element> parent.parentNode
133
+ }
134
+ // Scrolling to center active TOC element if TOC content is taller than viewport.
135
+ if (getComputedStyle(sideBar).display !== 'none' && tocElement.hasClass('active')) {
136
+ pageScroll(tocElement, target.offsetTop - (tocElement.offsetHeight / 4))
137
+ }
138
+ }
139
+ const navItems = $dom.all('.contents li')
140
+
141
+ if (navItems.length < 1) {
142
+ return
143
+ }
144
+
145
+ let sections = [...navItems]
146
+ let activeLock = null
147
+
148
+ sections = sections.map((element, index) => {
149
+ const link = element.child('a.toc-link')
150
+ const anchor = $dom(decodeURI(link.getAttribute('href')))
151
+ if (!anchor) return null
152
+ const alink = anchor.child('a.anchor')
153
+
154
+ const anchorScroll = (event:MouseEvent) => {
155
+ event.preventDefault()
156
+ const target = $dom(decodeURI((event.currentTarget as HTMLElement).getAttribute('href')))
157
+
158
+ activeLock = index
159
+ pageScroll(target, null, () => {
160
+ activateNavByIndex(index)
161
+ activeLock = null
162
+ })
163
+ }
164
+
165
+ // TOC item animation navigate.
166
+ link.addEventListener('click', anchorScroll)
167
+ alink && alink.addEventListener('click', (event) => {
168
+ anchorScroll(event)
169
+ clipBoard(CONFIG.hostname + '/' + LOCAL.path + (event.currentTarget as HTMLElement).getAttribute('href'))
170
+ })
171
+ return anchor
172
+ })
173
+
174
+ const tocElement = sideBar.child('.contents.panel')
175
+
176
+ const findIndex = (entries: IntersectionObserverEntry[]) => {
177
+ let index = 0
178
+ let entry = entries[index]
179
+
180
+ if (entry.boundingClientRect.top > 0) {
181
+ index = sections.indexOf(entry.target as HTMLElement)
182
+ return index === 0 ? 0 : index - 1
183
+ }
184
+ for (; index < entries.length; index++) {
185
+ if (entries[index].boundingClientRect.top <= 0) {
186
+ entry = entries[index]
187
+ } else {
188
+ return sections.indexOf(entry.target as HTMLElement)
189
+ }
190
+ }
191
+ return sections.indexOf(entry.target as HTMLElement)
192
+ }
193
+
194
+ const createIntersectionObserver = () => {
195
+ const observer = new IntersectionObserver((entries) => {
196
+ const index = findIndex(entries) + (diffY < 0 ? 1 : 0)
197
+ if (activeLock === null) {
198
+ activateNavByIndex(index)
199
+ }
200
+ }, {
201
+ rootMargin: '0px 0px -100% 0px', threshold: 0
202
+ })
203
+
204
+ sections.forEach((element) => {
205
+ element && observer.observe(element)
206
+ })
207
+ }
208
+
209
+ createIntersectionObserver()
210
+ }
211
+
212
+ export const backToTopHandle = () => {
213
+ pageScroll(0)
214
+ }
215
+
216
+ export const goToBottomHandle = () => {
217
+ pageScroll(parseInt(String(getHeight(Container))))
218
+ }
219
+
220
+ export const goToCommentHandle = () => {
221
+ pageScroll($dom('#comments'))
222
+ }
223
+
224
+ export const menuActive = () => {
225
+ $dom.each('.menu .item:not(.title)', (element) => {
226
+ const target = <HTMLAnchorElement> element.child('a[href]')
227
+ const parentItem = element.parentNode.parentNode
228
+ if (!target) return
229
+ const isSamePath = target.pathname === location.pathname || target.pathname === location.pathname.replace('index.html', '')
230
+ const isSubPath = !CONFIG.root.startsWith(target.pathname) && location.pathname.startsWith(target.pathname)
231
+ const active = target.hostname === location.hostname && (isSamePath || isSubPath)
232
+ element.toggleClass('active', active)
233
+ if (element.parentNode.child('.active') && parentItem.hasClass('dropdown')) {
234
+ parentItem.removeClass('active').addClass('expand')
235
+ } else {
236
+ parentItem.removeClass('expand')
237
+ }
238
+ })
239
+ }
@@ -0,0 +1,99 @@
1
+ import { $dom } from '../library/dom'
2
+ import Pjax from 'theme-shokax-pjax'
3
+ import initProto from '../library/proto'
4
+
5
+ export const CONFIG = shokax_CONFIG
6
+ initProto()
7
+ export const statics = CONFIG.statics.indexOf('//') > 0 ? CONFIG.statics : CONFIG.root
8
+ export const scrollAction: { x: number, y: number } = { x: 0, y: 0 }
9
+ export let diffY = 0
10
+ export let originTitle: string, titleTime: NodeJS.Timeout
11
+ export const BODY = document.getElementsByTagName('body')[0]
12
+ export const HTML = document.documentElement
13
+ export const Container = $dom('#container')
14
+ export const loadCat = $dom('#loading')
15
+ export const siteNav = $dom('#nav')
16
+ export const siteHeader = $dom('#header')
17
+ export const menuToggle = siteNav.child('.toggle')
18
+ export const quickBtn = $dom('#quick')
19
+ export const sideBar = $dom('#sidebar')
20
+ export const siteBrand = $dom('#brand')
21
+ export let toolBtn = $dom('#tool')
22
+ export let toolPlayer
23
+ export let backToTop: HTMLElement
24
+ export let goToComment
25
+ export let showContents
26
+ export let siteSearch = $dom('#search')
27
+ export let siteNavHeight: number, headerHightInner: number, headerHight: number
28
+ export let oWinHeight = window.innerHeight
29
+ export let oWinWidth = window.innerWidth
30
+ export let LOCAL_HASH = 0
31
+ export let LOCAL_URL = window.location.href
32
+ export let pjax:Pjax
33
+
34
+ export function setSiteNavHeight (value:number):void {
35
+ siteNavHeight = value
36
+ }
37
+ export function setHeaderHightInner (value:number):void {
38
+ headerHightInner = value
39
+ }
40
+
41
+ export function setHeaderHight (value:number):void {
42
+ headerHight = value
43
+ }
44
+
45
+ export function setOWinHeight (value:number):void {
46
+ oWinHeight = value
47
+ }
48
+
49
+ export function setOWinWidth (value:number):void {
50
+ oWinWidth = value
51
+ }
52
+
53
+ export function setDiffY (value:number):void {
54
+ diffY = value
55
+ }
56
+
57
+ export function setTitleTime (value:NodeJS.Timeout):void {
58
+ titleTime = value
59
+ }
60
+
61
+ export function setLocalHash (value:number):void {
62
+ LOCAL_HASH = value
63
+ }
64
+
65
+ export function setLocalUrl (value:string):void {
66
+ LOCAL_URL = value
67
+ }
68
+
69
+ export function setPjax (value:Pjax):void {
70
+ pjax = value
71
+ }
72
+
73
+ export function setOriginTitle (value:string):void {
74
+ originTitle = value
75
+ }
76
+
77
+ export function setToolPlayer (value:any):void {
78
+ toolPlayer = value
79
+ }
80
+
81
+ export function setBackToTop (value:HTMLElement):void {
82
+ backToTop = value
83
+ }
84
+
85
+ export function setGoToComment (value:any):void {
86
+ goToComment = value
87
+ }
88
+
89
+ export function setShowContents (value:any):void {
90
+ showContents = value
91
+ }
92
+
93
+ export function setToolBtn (value:HTMLElement):void {
94
+ toolBtn = value
95
+ }
96
+
97
+ export function setSiteSearch (value:HTMLElement):void {
98
+ siteSearch = value
99
+ }
@@ -0,0 +1,123 @@
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, CONFIG
22
+ } from './globalVars'
23
+ import { changeMetaTheme } from './themeColor'
24
+ import { Loader } from './thirdparty'
25
+ import {getHeight, setWidth} from '../library/proto'
26
+
27
+ export const resizeHandle = () => {
28
+ // 获取 siteNav 的高度
29
+ setSiteNavHeight(getHeight(siteNav))
30
+ // 获取 siteHeader 的高度
31
+ setHeaderHightInner(getHeight(siteHeader))
32
+ // 获取 #waves 的高度
33
+ setHeaderHight(headerHightInner + getHeight($dom('#waves')))
34
+
35
+ // 判断窗口宽度是否改变
36
+ if (oWinWidth !== window.innerWidth) {
37
+ sideBarToggleHandle(null, 1)
38
+ }
39
+
40
+ // 记录窗口高度和宽度
41
+ setOWinHeight(window.innerHeight)
42
+ setOWinWidth(window.innerWidth)
43
+ }
44
+
45
+ export const scrollHandle = () => {
46
+ // 获取窗口高度
47
+ const winHeight = window.innerHeight
48
+ // 获取文档高度
49
+ const docHeight = getDocHeight()
50
+ // 计算可见内容高度
51
+ const contentVisibilityHeight = docHeight > winHeight ? docHeight - winHeight : document.body.scrollHeight - winHeight
52
+ // 判断页面是否滚动超过 headerHightInner
53
+ const SHOW = window.scrollY > headerHightInner
54
+ // 判断页面是否开始滚动
55
+ const startScroll = window.scrollY > 0
56
+
57
+ // 根据条件修改 meta theme
58
+ if (SHOW) {
59
+ changeMetaTheme('#FFF')
60
+ } else {
61
+ changeMetaTheme('#222')
62
+ }
63
+
64
+ // 控制导航栏的显示隐藏
65
+ siteNav.toggleClass('show', SHOW)
66
+ // 控制网站 logo 的显示隐藏
67
+ toolBtn.toggleClass('affix', startScroll)
68
+ // 控制侧边栏的显示隐藏,当滚动高度大于 headerHight 且窗口宽度大于 991px 时显示
69
+ siteBrand.toggleClass('affix', startScroll)
70
+ sideBar.toggleClass('affix', window.scrollY > headerHight && document.body.offsetWidth > 991)
71
+ // 初始化滚动时导航栏的显示方向
72
+ if (typeof scrollAction.y === 'undefined') {
73
+ scrollAction.y = window.scrollY
74
+ }
75
+ setDiffY(scrollAction.y - window.scrollY)
76
+
77
+ // 控制滑动时导航栏显示
78
+ if (diffY < 0) {
79
+ siteNav.removeClass('up')
80
+ siteNav.toggleClass('down', SHOW)
81
+ } else if (diffY > 0) {
82
+ siteNav.removeClass('down')
83
+ siteNav.toggleClass('up', SHOW)
84
+ } else { /* empty */ }
85
+ scrollAction.y = window.scrollY
86
+ // 计算滚动百分比
87
+ const scrollPercent = Math.round(Math.min(100 * window.scrollY / contentVisibilityHeight, 100)) + '%'
88
+ // 更新回到顶部按钮的文字
89
+ if (backToTop.child('span').innerText !== scrollPercent) {
90
+ backToTop.child('span').innerText = scrollPercent
91
+ }
92
+ // 更新百分比进度条的宽度
93
+ if ($dom('#sidebar').hasClass('affix') || $dom('#sidebar').hasClass('on')) {
94
+ setWidth($dom('.percent'), scrollPercent)
95
+ }
96
+ }
97
+
98
+ // 可见度监听(离开页面和返回时更改document的title)
99
+ export const visibilityListener = () => {
100
+ const iconNode = $dom('[rel="icon"]')
101
+ document.addEventListener('visibilitychange', () => {
102
+ switch (document.visibilityState) {
103
+ case 'hidden':
104
+ iconNode.setAttribute('href', statics + CONFIG.favicon.hidden)
105
+ document.title = LOCAL.favicon.hide
106
+ if (CONFIG.loader.switch) {
107
+ Loader.show()
108
+ }
109
+ clearTimeout(titleTime)
110
+ break
111
+ case 'visible':
112
+ iconNode.setAttribute('href', statics + CONFIG.favicon.normal)
113
+ document.title = LOCAL.favicon.show
114
+ if (CONFIG.loader.switch) {
115
+ Loader.hide(1000)
116
+ }
117
+ setTitleTime(setTimeout(() => {
118
+ document.title = originTitle
119
+ }, 2000))
120
+ break
121
+ }
122
+ })
123
+ }
@@ -0,0 +1,64 @@
1
+ import { $storage } from '../library/storage'
2
+ import { $dom } from '../library/dom'
3
+ import { CONFIG, 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 { CONFIG, 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,75 @@
1
+ import { pageScroll } from '../library/anime'
2
+ import { $dom } from '../library/dom'
3
+ import { $storage } from '../library/storage'
4
+ import { BODY, CONFIG, LOCAL_HASH, LOCAL_URL, scrollAction, setLocalHash } from './globalVars'
5
+ import { createChild } from '../library/proto'
6
+
7
+ // 显示提示(现阶段用于版权及复制结果提示)
8
+ export const showtip = (msg: string): void | never => {
9
+ if (!msg) {
10
+ return
11
+ }
12
+
13
+ const tipbox = createChild(BODY, 'div', {
14
+ innerHTML: msg,
15
+ className: 'tip'
16
+ })
17
+
18
+ setTimeout(() => {
19
+ tipbox.addClass('hide')
20
+ setTimeout(() => {
21
+ BODY.removeChild(tipbox)
22
+ }, 300)
23
+ }, 3000)
24
+ }
25
+
26
+ export const pagePosition = () => {
27
+ // 判断配置项是否开启了自动记录滚动位置
28
+ if (CONFIG.auto_scroll) {
29
+ // 将当前页面的滚动位置存入本地缓存
30
+ $storage.set(LOCAL_URL, String(scrollAction.y))
31
+ }
32
+ }
33
+
34
+ export const positionInit = (comment?: boolean) => {
35
+ // 获取页面锚点
36
+ const anchor = window.location.hash
37
+
38
+ let target = null
39
+ if (LOCAL_HASH) {
40
+ $storage.del(LOCAL_URL)
41
+ return
42
+ }
43
+
44
+ if (anchor) {
45
+ target = $dom(decodeURI(anchor))
46
+ } else {
47
+ target = CONFIG.auto_scroll ? parseInt($storage.get(LOCAL_URL)) : 0
48
+ }
49
+
50
+ if (target) {
51
+ pageScroll(target)
52
+ setLocalHash(1)
53
+ }
54
+
55
+ if (comment && anchor && !LOCAL_HASH) {
56
+ pageScroll(target)
57
+ setLocalHash(1)
58
+ }
59
+ }
60
+
61
+ /*
62
+ 基于clipboard API的复制功能,仅在https环境下有效
63
+ */
64
+ export const clipBoard = (str: string, callback?: (result:boolean) => void) => {
65
+ if (navigator.clipboard && window.isSecureContext) {
66
+ navigator.clipboard.writeText(str).then(() => {
67
+ callback && callback(true)
68
+ }, () => {
69
+ callback && callback(false)
70
+ })
71
+ } else {
72
+ console.error('Too old browser, clipborad API not supported.')
73
+ callback && callback(false)
74
+ }
75
+ }