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,110 @@
1
+ import anime from 'theme-shokax-anime'
2
+ import { siteNavHeight } from '../globals/globalVars'
3
+ import type { AnimeOptions } from 'theme-shokax-anime/dist/types'
4
+ import {getTop, setDisplay} from './proto'
5
+
6
+ /**
7
+ * 参数 动画效果
8
+ * 0 元素逐渐消失
9
+ * 1 元素逐渐出现
10
+ * bounceUpIn 元素从下方弹跳出现
11
+ * shrinkIn 元素从放大到正常大小出现
12
+ * slideRightIn 元素从右侧滑入
13
+ * slideRightOut 元素向右侧滑出
14
+ * TODO 函数功能过于复杂,需要拆分
15
+ */
16
+ export const transition = (target: HTMLElement, type: number|string|Function, complete?: Function, begin?: Function): void => {
17
+ let animation:Partial<AnimeOptions>
18
+ let display = 'none'
19
+ switch (type) {
20
+ case 0:
21
+ animation = { opacity: [1, 0] }
22
+ break
23
+ case 1:
24
+ animation = { opacity: [0, 1] }
25
+ display = 'block'
26
+ break
27
+ case 'bounceUpIn':
28
+ animation = {
29
+ begin (anim) {
30
+ setDisplay(target, 'block')
31
+ },
32
+ translateY: [
33
+ { value: -60, duration: 200 },
34
+ { value: 10, duration: 200 },
35
+ { value: -5, duration: 200 },
36
+ { value: 0, duration: 200 }
37
+ ],
38
+ opacity: [0, 1]
39
+ }
40
+ display = 'block'
41
+ break
42
+ case 'shrinkIn':
43
+ animation = {
44
+ begin (anim) {
45
+ setDisplay(target, 'block')
46
+ },
47
+ scale: [
48
+ { value: 1.1, duration: 300 },
49
+ { value: 1, duration: 200 }
50
+ ],
51
+ opacity: 1
52
+ }
53
+ display = 'block'
54
+ break
55
+ case 'slideRightIn':
56
+ animation = {
57
+ begin (anim) {
58
+ setDisplay(target, 'block')
59
+ },
60
+ translateX: ['100%', '0%'],
61
+ opacity: [0, 1]
62
+ }
63
+ display = 'block'
64
+ break
65
+ case 'slideRightOut':
66
+ animation = {
67
+ translateX: ['0%', '100%'],
68
+ opacity: [1, 0]
69
+ }
70
+ break
71
+ default:
72
+ // @ts-ignore
73
+ animation = type
74
+ // @ts-ignore
75
+ display = type.display
76
+ break
77
+ }
78
+ anime(Object.assign({
79
+ targets: target,
80
+ duration: 200,
81
+ easing: 'linear',
82
+ begin () {
83
+ begin && begin()
84
+ },
85
+ complete () {
86
+ setDisplay(target, display)
87
+ complete && complete()
88
+ }
89
+ }, animation)).play()
90
+ }
91
+
92
+ export const pageScroll = (target: HTMLElement|number, offset?: number, complete?: Function) => {
93
+ // target: 滚动到的目标元素或坐标(number)
94
+ // offset: 可选的偏移量
95
+ // complete: 可选的回调函数,在动画完成时调用
96
+ anime({
97
+ // 动画目标
98
+ targets: typeof offset === 'number' && typeof target !== 'number' ? target.parentNode : document.scrollingElement,
99
+ // 动画持续时间
100
+ duration: 500,
101
+ // 动画缓动函数
102
+ easing: 'easeInOutQuad',
103
+ // 如果 offset 存在,则滚动到 offset,如果 target 是数字,则滚动到 target,如果 target 是 DOM 元素,则滚动到下述表达式
104
+ scrollTop: offset || (typeof target === 'number' ? target : (target ? getTop(target) + document.documentElement.scrollTop - siteNavHeight : 0)),
105
+ // 完成回调函数
106
+ complete () {
107
+ complete && complete()
108
+ }
109
+ }).play()
110
+ }
@@ -0,0 +1,126 @@
1
+ /*
2
+ 对注释的说明: 部分注释为openai-chatgpt生成的注释,可能存在描述或语义的问题
3
+ */
4
+ interface AudioItem {
5
+ title: string;
6
+ list: string[];
7
+ }
8
+
9
+ declare interface EventTarget {
10
+ createChild(tag: string, obj: Object, positon?: string): HTMLElement;
11
+ wrapObject(obj: Object): void;
12
+ changeOrGetHeight(h: number | string): void;
13
+ changeOrGetHeight(): number;
14
+ changeOrGetWidth(w: number | string): void;
15
+ changeOrGetWidth(): number;
16
+ getTop(): number;
17
+ left(): number;
18
+ insertAfter(element: HTMLElement): void;
19
+ display(d: string): EventTarget;
20
+ display():string
21
+ child(selector: string): HTMLElement;
22
+ find(selector: string): NodeListOf<HTMLElement>;
23
+ _class(type: string, className: string, display?: boolean): void;
24
+ addClass(className: string): EventTarget;
25
+ removeClass(className: string): EventTarget;
26
+ toggleClass(className: string, display?: boolean): EventTarget;
27
+ hasClass(className: string): boolean;
28
+ }
29
+
30
+ type walineMeta = 'nick'|'mail'|'link'
31
+
32
+ declare const LOCAL: {
33
+ path: string;
34
+ ignores: Array<(uri:string)=>boolean>;
35
+ audio: string[];
36
+ search: {
37
+ placeholder: string,
38
+ empty: string,
39
+ stats: string
40
+ };
41
+ quiz: {
42
+ choice: string,
43
+ multiple: string,
44
+ true_false: string,
45
+ essay: string,
46
+ gap_fill: string,
47
+ mistake: string
48
+ };
49
+ nocopy: boolean;
50
+ copyright: string;
51
+ outime: boolean
52
+ template: string
53
+ favicon: {
54
+ hide: string
55
+ show: string
56
+ }
57
+ }
58
+ interface configType {
59
+ hostname: string;
60
+ fireworks: any;
61
+ audio: AudioItem[];
62
+ version: number
63
+ root: string
64
+ statics: string
65
+ outime: {
66
+ enable: boolean
67
+ days: number
68
+ }
69
+ favicon: {
70
+ normal: string,
71
+ hidden: string
72
+ }
73
+ darkmode: boolean
74
+ auto_dark: {
75
+ enable: boolean
76
+ start: number
77
+ end: number
78
+ }
79
+ auto_scroll: boolean
80
+ loader: {
81
+ start: boolean
82
+ switch: boolean
83
+ }
84
+ js: {
85
+ chart: string
86
+ copy_tex: string
87
+ fancybox: string
88
+ echarts: string
89
+ }
90
+ css: {
91
+ valine: string
92
+ katex: string
93
+ mermaid: string
94
+ fancybox: string
95
+ }
96
+ search: any,
97
+ waline: {
98
+ serverURL: string
99
+ lang: string
100
+ locale: object
101
+ emoji: boolean
102
+ meta: walineMeta[]
103
+ requiredMeta: walineMeta[]
104
+ wordLimit: number
105
+ pageSize: number
106
+ pageview: boolean
107
+ }
108
+ walinePageView: boolean
109
+ quicklink: {
110
+ ignores: any
111
+ timeout: number
112
+ priority: boolean
113
+ }
114
+ playerAPI: string
115
+ }
116
+ // esbuild 静态常量
117
+ declare const __shokax_player__:boolean
118
+ declare const __shokax_fireworks__:boolean
119
+ declare const __shokax_search__:boolean
120
+ declare const __shokax_VL__:boolean
121
+ declare const __shokax_outime__:boolean
122
+ declare const __shokax_tabs__: boolean
123
+ declare const __shokax_quiz__: boolean
124
+ declare const __shokax_fancybox__: boolean
125
+ declare const __shokax_waline__:boolean
126
+ declare const shokax_CONFIG:configType
@@ -0,0 +1,26 @@
1
+ const getDocHeight = () => $dom('main > .inner').offsetHeight
2
+ /**
3
+ * 获取一个dom选择器对应的元素
4
+ */
5
+ const $dom = (selector: string, element: Document = document): HTMLElement => {
6
+ // 在测试环境中这能优化0.01-0.02ms左右
7
+ if (selector[0] === '#') {
8
+ return <HTMLElement> element.getElementById(selector.substring(1))
9
+ }
10
+ return <HTMLElement> element.querySelector(selector)
11
+ }
12
+
13
+ /**
14
+ * 获取具有此选择器的所有dom节点
15
+ */
16
+ $dom.all = (selector: string, element: Document = document): NodeListOf<HTMLElement> => {
17
+ return element.querySelectorAll(selector)
18
+ }
19
+ /**
20
+ * 获取具有此选择器的所有dom节点,并依次执行callback函数
21
+ */
22
+ $dom.each = (selector: string, callback: (value: HTMLElement, key: number, parent: NodeListOf<Element>) => void, element?: Document): void => {
23
+ $dom.all(selector, element).forEach(callback)
24
+ }
25
+
26
+ export { $dom, getDocHeight }
@@ -0,0 +1,43 @@
1
+ import { getScript } from './scriptPjax'
2
+ import { CONFIG } from '../globals/globalVars'
3
+ import { createChild } from './proto'
4
+
5
+ /**
6
+ * 用途是根据不同的资源名称和类型生成相应的资源 URL。
7
+ */
8
+ const assetUrl = (asset: string, type: string): string => {
9
+ const str = CONFIG[asset][type]
10
+ if (str.includes('http')) {
11
+ return str
12
+ }
13
+ if (str.includes('gh') || str.includes('combine')) {
14
+ return `https://cdn.jsdelivr.net/${str}`
15
+ }
16
+ if (str.includes('npm')) {
17
+ return `https://cdn.jsdelivr.net/${str}`
18
+ }
19
+ return `/${str}`
20
+ }
21
+
22
+ export const vendorJs = (type: string, callback?: Function, condition?: string) => {
23
+ if (LOCAL[type]) {
24
+ getScript(assetUrl('js', type), callback || function () {
25
+ window[type] = true
26
+ }, condition || window[type])
27
+ }
28
+ }
29
+
30
+ export const vendorCss = (type: string, condition?: string): void => {
31
+ if (window['css' + type]) {
32
+ return
33
+ }
34
+
35
+ if (LOCAL[type]) {
36
+ createChild(document.head, 'link', {
37
+ rel: 'stylesheet',
38
+ href: assetUrl('css', type)
39
+ })
40
+
41
+ window['css' + type] = true
42
+ }
43
+ }
@@ -0,0 +1,141 @@
1
+ import { $dom } from './dom'
2
+
3
+ export const insertAfter = function (el: HTMLElement, element: HTMLElement): void {
4
+ const parent = el.parentNode
5
+ if (parent.lastChild === el) {
6
+ parent.appendChild(element)
7
+ } else {
8
+ parent.insertBefore(element, el.nextSibling)
9
+ }
10
+ }
11
+
12
+ /**
13
+ * 创建一个子节点并放置
14
+ */
15
+ export const createChild = function (parent: HTMLElement, tag: string, obj: object, positon?: string): HTMLElement {
16
+ const child = document.createElement(tag)
17
+ Object.assign(child, obj)
18
+ switch (positon) {
19
+ case 'after':
20
+ insertAfter(parent, child)
21
+ break
22
+ case 'replace':
23
+ parent.innerHTML = ''
24
+ parent.appendChild(child)
25
+ break
26
+ default:
27
+ parent.appendChild(child)
28
+ }
29
+ return child
30
+ }
31
+
32
+ /**
33
+ * 此方法使用`<div>`包装一个 DOM 元素
34
+ * @param parent
35
+ * @param obj 需要被包装的对象
36
+ */
37
+ export const wrapObject = function (parent: HTMLElement, obj: any): void {
38
+ const box = document.createElement('div')
39
+ Object.assign(box, obj)
40
+ parent.insertBefore(box, obj)
41
+ parent.removeChild(obj)
42
+ box.appendChild(obj)
43
+ }
44
+
45
+ export const getHeight = function (el: HTMLElement): number {
46
+ return el.getBoundingClientRect().height
47
+ }
48
+
49
+ export const setWidth = function (el: HTMLElement, w: number|string): void {
50
+ el.style.width = typeof w === 'number' ? w + 'rem' : w
51
+ }
52
+
53
+ export const getWidth = function (el: HTMLElement): number {
54
+ return el.getBoundingClientRect().width
55
+ }
56
+
57
+ export const getTop = function (el: HTMLElement): number {
58
+ return el.getBoundingClientRect().top
59
+ }
60
+
61
+ export const getLeft = function (el: HTMLElement): number {
62
+ return el.getBoundingClientRect().left
63
+ }
64
+
65
+ export const getDisplay = function (el: HTMLElement): string {
66
+ return el.style.display
67
+ }
68
+
69
+ export const setDisplay = function (el: HTMLElement, d: string): HTMLElement {
70
+ el.style.display = d
71
+ return el
72
+ }
73
+
74
+ // TODO 未完成迁移
75
+ export const child = function (el: HTMLElement, selector: string): HTMLElement {
76
+ return $dom(selector, (el as unknown as Document))
77
+ }
78
+ export default function initProto () {
79
+ Object.assign(HTMLElement.prototype, {
80
+ /**
81
+ * 找到此节点第一个符合selector选择器的子节点
82
+ */
83
+ child (selector: string): HTMLElement {
84
+ return $dom(selector, this)
85
+ },
86
+ /**
87
+ * 找到此节点所有符合selector选择器的子节点
88
+ */
89
+ find (selector: string): NodeListOf<HTMLElement> {
90
+ return $dom.all(selector, this)
91
+ },
92
+ /**
93
+ * 这个方法接受三个参数:
94
+ * type 表示操作类型('add'、'remove'、'toggle'),
95
+ * className 是一个或多个要操作的类名,
96
+ * display 是一个可选的布尔值,用于在执行切换操作时指定类名是否应显示或隐藏。
97
+ * 该方法会根据操作类型执行相应的类名操作。
98
+ */
99
+ _class (type: string, className: string, display?: boolean): void {
100
+ const classNames = className.indexOf(' ') ? className.split(' ') : [className]
101
+ classNames.forEach((name) => {
102
+ if (type === 'toggle') {
103
+ this.classList.toggle(name, display)
104
+ } else {
105
+ this.classList[type](name)
106
+ }
107
+ })
108
+ },
109
+ /**
110
+ * 这个方法是对 _class 方法的封装,调用时会将操作类型设为 'add',然后执行添加类名的操作。
111
+ * 最后,它返回当前的 EventTarget,通常是 DOM 元素本身,以支持链式调用。
112
+ */
113
+ addClass (className: string): EventTarget {
114
+ this._class('add', className)
115
+ return this
116
+ },
117
+ /**
118
+ * 这个方法是对 _class 方法的封装,调用时会将操作类型设为 'remove',然后执行移除类名的操作。
119
+ * 最后,它返回当前的 EventTarget,通常是 DOM 元素本身,以支持链式调用。
120
+ */
121
+ removeClass (className: string): EventTarget {
122
+ this._class('remove', className)
123
+ return this
124
+ },
125
+ /**
126
+ * 这个方法是对 _class 方法的封装,调用时会将操作类型设为 'toggle',然后执行切换类名的操作。
127
+ * 如果提供了 display 参数,它将根据布尔值决定是否显示或隐藏类名。
128
+ * 最后,它返回当前的 EventTarget,通常是 DOM 元素本身,以支持链式调用。
129
+ */
130
+ toggleClass (className: string, display?: boolean): EventTarget {
131
+ this._class('toggle', className, display)
132
+ return this
133
+ },
134
+ /**
135
+ * 这个方法返回一个布尔值,表示元素是否包含指定的类名。
136
+ */
137
+ hasClass (className: string): boolean {
138
+ return this.classList.contains(className)
139
+ }
140
+ })
141
+ }
@@ -0,0 +1,72 @@
1
+ // rocket-loader & Auto minify(cloudflare) 补丁
2
+ // cloudflare 的上述功能会导致DOMContentLoaded事件无法触发,此补丁会将DOMContentLoaded重定向为load事件
3
+ export function cloudflareInit () {
4
+ let inCloudFlare = true
5
+ window.addEventListener('DOMContentLoaded', function () {
6
+ inCloudFlare = false
7
+ })
8
+
9
+ if (document.readyState === 'loading') {
10
+ window.addEventListener('load', function () {
11
+ if (inCloudFlare) {
12
+ window.dispatchEvent(new Event('DOMContentLoaded'))
13
+ console.log('%c ☁️cloudflare patch ' + '%c running(rocket & minify)', 'color: white; background: #ff8c00; padding: 5px 3px;', 'padding: 4px;border:1px solid #ff8c00')
14
+ }
15
+ })
16
+ }
17
+ }
18
+
19
+ export const getScript = (url: string, callback?: Function, condition?: string): void => {
20
+ // url: 脚本文件的URL地址
21
+ // callback: 当脚本加载完成时要执行的回调函数
22
+ // condition: 可选的条件参数,如果存在,则执行callback
23
+ if (condition) {
24
+ // 如果条件存在,则执行回调函数
25
+ callback()
26
+ } else {
27
+ let script = document.createElement('script')
28
+
29
+ // @ts-ignore
30
+ script.onload = function (_, isAbort: boolean) {
31
+ // _: 事件对象
32
+ // isAbort: 是否中止
33
+ // @ts-ignore
34
+ if (isAbort || !script.readyState) {
35
+ console.log('abort!')
36
+ script.onload = null
37
+ script = undefined
38
+ if (!isAbort && callback) setTimeout(callback, 0)
39
+ }
40
+ }
41
+ script.src = url
42
+ document.head.appendChild(script)
43
+ }
44
+ }
45
+
46
+ export const pjaxScript = (element: HTMLScriptElement) => {
47
+ const { text, parentNode, id, className, type, src, dataset } = element
48
+ const code = text || element.textContent || element.innerHTML || ''
49
+ parentNode.removeChild(element)
50
+ const script = document.createElement('script')
51
+ if (id) {
52
+ script.id = id
53
+ }
54
+ if (className) {
55
+ script.className = className
56
+ }
57
+ if (type) {
58
+ script.type = type
59
+ }
60
+ if (src) {
61
+ // Force synchronous loading of peripheral JS.
62
+ script.src = src
63
+ script.async = false
64
+ }
65
+ if (dataset.pjax !== undefined) {
66
+ script.dataset.pjax = ''
67
+ }
68
+ if (code !== '') {
69
+ script.appendChild(document.createTextNode(code))
70
+ }
71
+ parentNode.appendChild(script)
72
+ }
@@ -0,0 +1,12 @@
1
+ // Html5LocalStorage的一个API
2
+ export const $storage = {
3
+ set (key: string, value: string): void {
4
+ localStorage.setItem(key, value)
5
+ },
6
+ get (key: string): string {
7
+ return localStorage.getItem(key)
8
+ },
9
+ del (key: string): void {
10
+ localStorage.removeItem(key)
11
+ }
12
+ }
@@ -0,0 +1,50 @@
1
+ import { $storage } from './storage'
2
+ import { transition } from './anime'
3
+ import { $dom } from './dom'
4
+ import { BODY } from '../globals/globalVars'
5
+ import { changeTheme } from '../globals/themeColor'
6
+ import { child, createChild, setDisplay } from './proto'
7
+ export function initVue () {
8
+ function changeThemeByBtn () {
9
+ let c: { (): void; (): void; (): void }
10
+ const btn = child($dom('.theme'), '.ic')
11
+
12
+ const neko = createChild(BODY, 'div', {
13
+ id: 'neko',
14
+ innerHTML: '<div class="planet"><div class="sun"></div><div class="moon"></div></div><div class="body"><div class="face"><section class="eyes left"><span class="pupil"></span></section><section class="eyes right"><span class="pupil"></span></section><span class="nose"></span></div></div>'
15
+ })
16
+
17
+ const hideNeko = () => {
18
+ transition(neko, {
19
+ // @ts-ignore
20
+ delay: 2500,
21
+ opacity: 0
22
+ }, () => {
23
+ BODY.removeChild(neko)
24
+ })
25
+ }
26
+
27
+ if (btn.hasClass('i-sun')) {
28
+ c = () => {
29
+ neko.addClass('dark')
30
+ changeTheme('dark')
31
+ $storage.set('theme', 'dark')
32
+ hideNeko()
33
+ }
34
+ } else {
35
+ neko.addClass('dark')
36
+ c = () => {
37
+ neko.removeClass('dark')
38
+ changeTheme()
39
+ $storage.set('theme', 'light')
40
+ hideNeko()
41
+ }
42
+ }
43
+ transition(neko, 1, () => {
44
+ setTimeout(c, 210)
45
+ }, () => {
46
+ setDisplay(neko, 'block')
47
+ })
48
+ }
49
+ child($dom('#rightNav'), '.theme .ic').addEventListener('click', changeThemeByBtn)
50
+ }
@@ -0,0 +1,42 @@
1
+ import { $dom } from '../library/dom'
2
+
3
+ export const cardActive = () => {
4
+ if (!$dom('.index.wrap')) { return }
5
+ const io = new IntersectionObserver((entries) => {
6
+ entries.forEach((article) => {
7
+ if (article.target.hasClass('show')) {
8
+ io.unobserve(article.target)
9
+ } else {
10
+ if (article.isIntersecting || article.intersectionRatio > 0) {
11
+ article.target.addClass('show')
12
+ io.unobserve(article.target)
13
+ }
14
+ }
15
+ })
16
+ }, {
17
+ root: null,
18
+ threshold: [0.3]
19
+ })
20
+
21
+ $dom.each('.index.wrap article.item, .index.wrap section.item', (article) => {
22
+ io.observe(article)
23
+ })
24
+
25
+ $dom('.index.wrap .item:first-child').addClass('show')
26
+
27
+ $dom.each('.cards .item', (element) => {
28
+ ['mouseenter', 'touchstart'].forEach((item) => {
29
+ element.addEventListener(item, () => {
30
+ if ($dom('.cards .item.active')) {
31
+ $dom('.cards .item.active').removeClass('active')
32
+ }
33
+ element.addClass('active')
34
+ }, { passive: true })
35
+ });
36
+ ['mouseleave'].forEach((item) => {
37
+ element.addEventListener(item, () => {
38
+ element.removeClass('active')
39
+ }, { passive: true })
40
+ })
41
+ })
42
+ }
@@ -0,0 +1,71 @@
1
+ import { $dom } from '../library/dom'
2
+ import { vendorCss, vendorJs } from '../library/loadFile'
3
+ import { insertAfter } from '../library/proto'
4
+
5
+ export const postFancybox = (p:string) => {
6
+ if ($dom(p + ' .md img')) {
7
+ vendorCss('fancybox')
8
+ vendorCss('justifiedGallery')
9
+ vendorJs('fancybox', () => {
10
+ const q = jQuery.noConflict()
11
+
12
+ $dom.each(p + ' p.gallery', (element) => {
13
+ const box = document.createElement('div')
14
+ box.className = 'gallery'
15
+ box.setAttribute('data-height', String(element.getAttribute('data-height') || 220))
16
+
17
+ box.innerHTML = element.innerHTML.replace(/<br>/g, '')
18
+
19
+ element.parentNode.insertBefore(box, element)
20
+ element.remove()
21
+ })
22
+
23
+ $dom.each(p + ' .md img:not(.emoji):not(.vemoji)', (element) => {
24
+ const $image = q(element)
25
+ const imageLink = $image.attr('data-src') || $image.attr('src') // 替换
26
+ const $imageWrapLink = $image.wrap('<a class="fancybox" href="' + imageLink + '" itemscope itemtype="https://schema.org/ImageObject" itemprop="url"></a>').parent('a')
27
+ let info; let captionClass = 'image-info'
28
+ if (!$image.is('a img')) {
29
+ $image.data('safe-src', imageLink)
30
+ if (!$image.is('.gallery img')) {
31
+ $imageWrapLink.attr('data-fancybox', 'default').attr('rel', 'default')
32
+ } else {
33
+ captionClass = 'jg-caption'
34
+ }
35
+ }
36
+ if ((info = element.getAttribute('title'))) {
37
+ $imageWrapLink.attr('data-caption', info)
38
+ const para = document.createElement('span')
39
+ const txt = document.createTextNode(info)
40
+ para.appendChild(txt)
41
+ para.addClass(captionClass)
42
+ insertAfter(element, para)
43
+ }
44
+ })
45
+
46
+ $dom.each(p + ' div.gallery', (el, i) => {
47
+ // @ts-ignore
48
+ q(el).justifiedGallery({
49
+ rowHeight: q(el).data('height') || 120,
50
+ rel: 'gallery-' + i
51
+ }).on('jg.complete', function () {
52
+ q(this).find('a').each((k, ele) => {
53
+ ele.setAttribute('data-fancybox', 'gallery-' + i)
54
+ })
55
+ })
56
+ })
57
+
58
+ q.fancybox.defaults.hash = false
59
+ q(p + ' .fancybox').fancybox({
60
+ loop: true,
61
+ // @ts-ignore
62
+ helpers: {
63
+ overlay: {
64
+ locked: false
65
+ }
66
+ }
67
+ })
68
+ // @ts-ignore
69
+ }, window.jQuery)
70
+ }
71
+ }