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

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.
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
+ }