tona-plugins 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. package/README.md +48 -0
  2. package/index.d.ts +32 -0
  3. package/package.json +51 -0
  4. package/src/constants/cdn.js +12 -0
  5. package/src/index.js +30 -0
  6. package/src/plugins/background/index.js +50 -0
  7. package/src/plugins/background/index.scss +0 -0
  8. package/src/plugins/barrage/index.js +104 -0
  9. package/src/plugins/barrage/index.scss +16 -0
  10. package/src/plugins/catalog/index.js +212 -0
  11. package/src/plugins/catalog/index.scss +0 -0
  12. package/src/plugins/charts/index.js +60 -0
  13. package/src/plugins/charts/index.scss +16 -0
  14. package/src/plugins/clickEffects/index.js +137 -0
  15. package/src/plugins/clickEffects/index.scss +0 -0
  16. package/src/plugins/codeCopy/index.js +94 -0
  17. package/src/plugins/codeCopy/index.scss +65 -0
  18. package/src/plugins/codeHighlight/index.js +35 -0
  19. package/src/plugins/codeHighlight/index.scss +216 -0
  20. package/src/plugins/codeHighlight/themes.js +60 -0
  21. package/src/plugins/codeLang/index.js +51 -0
  22. package/src/plugins/codeLang/index.scss +28 -0
  23. package/src/plugins/codeLinenumbers/index.js +33 -0
  24. package/src/plugins/codeLinenumbers/index.scss +61 -0
  25. package/src/plugins/codeTrafficLight/index.js +18 -0
  26. package/src/plugins/codeTrafficLight/index.scss +0 -0
  27. package/src/plugins/colorMode/index.js +81 -0
  28. package/src/plugins/colorMode/index.scss +0 -0
  29. package/src/plugins/commentsAvatars/index.js +85 -0
  30. package/src/plugins/commentsAvatars/index.scss +3 -0
  31. package/src/plugins/darkMode/index.js +115 -0
  32. package/src/plugins/darkMode/index.scss +67 -0
  33. package/src/plugins/donation/index.js +45 -0
  34. package/src/plugins/donation/index.scss +63 -0
  35. package/src/plugins/emoji/index.js +167 -0
  36. package/src/plugins/emoji/index.scss +155 -0
  37. package/src/plugins/footer/index.js +35 -0
  38. package/src/plugins/footer/index.scss +54 -0
  39. package/src/plugins/imagePreview/index.js +98 -0
  40. package/src/plugins/imagePreview/index.scss +51 -0
  41. package/src/plugins/license/index.js +62 -0
  42. package/src/plugins/license/index.scss +51 -0
  43. package/src/plugins/live2d/index.js +67 -0
  44. package/src/plugins/live2d/index.scss +0 -0
  45. package/src/plugins/live2d/live2d-models.js +21 -0
  46. package/src/plugins/lock/index.js +77 -0
  47. package/src/plugins/lock/index.scss +56 -0
  48. package/src/plugins/musicPlayer/index.js +81 -0
  49. package/src/plugins/musicPlayer/index.scss +68 -0
  50. package/src/plugins/notation/index.js +73 -0
  51. package/src/plugins/notation/index.scss +12 -0
  52. package/src/plugins/notice/index.js +17 -0
  53. package/src/plugins/notice/index.scss +46 -0
  54. package/src/plugins/postBottomImage/index.js +27 -0
  55. package/src/plugins/postBottomImage/index.scss +26 -0
  56. package/src/plugins/postMessage/index.js +89 -0
  57. package/src/plugins/postMessage/index.scss +81 -0
  58. package/src/plugins/postTopImage/index.js +28 -0
  59. package/src/plugins/postTopImage/index.scss +29 -0
  60. package/src/plugins/qrcode/index.js +42 -0
  61. package/src/plugins/qrcode/index.scss +10 -0
  62. package/src/plugins/signature/index.js +47 -0
  63. package/src/plugins/signature/index.scss +18 -0
  64. package/src/plugins/toast/index.js +49 -0
  65. package/src/plugins/tools/index.js +251 -0
  66. package/src/plugins/tools/index.scss +114 -0
  67. package/src/plugins/webTag/index.js +40 -0
  68. package/src/plugins/webTag/index.scss +0 -0
  69. package/src/utils/cnblog.js +282 -0
  70. package/src/utils/helpers.js +418 -0
  71. package/src/utils/shared.js +2 -0
@@ -0,0 +1,33 @@
1
+ // 构建代码行号
2
+ import { getCodeLangOptions } from 'tona-options'
3
+ import { isMd, isPostDetailsPage } from '../../utils/cnblog'
4
+
5
+ /**
6
+ * 构建代码行号
7
+ */
8
+ function buildLinenumbers() {
9
+ $('pre code').each(function () {
10
+ const linenumberContainer = $('<ul/>').addClass('awes-linenumber')
11
+ const lines = $(this).text().split('\n').length - 1
12
+
13
+ for (let i = 1; i <= lines; i++) {
14
+ linenumberContainer.append($('<li/>').text(i))
15
+ }
16
+
17
+ $(this).before(linenumberContainer)
18
+ })
19
+ }
20
+
21
+ export function codeLinenumbers(_, devOptions) {
22
+ const { enable } = getCodeLangOptions(devOptions)
23
+ if (!isPostDetailsPage) {
24
+ return
25
+ }
26
+ if (!enable) {
27
+ return
28
+ }
29
+ if (!isMd()) {
30
+ return
31
+ }
32
+ buildLinenumbers()
33
+ }
@@ -0,0 +1,61 @@
1
+ @use 'sass:map';
2
+
3
+ $lineNumbers: () !default;
4
+ $lineNumbers: map.merge(
5
+ (
6
+ color: #999999,
7
+ ),
8
+ $lineNumbers
9
+ );
10
+
11
+ $lineNumbersColor: map.get($lineNumbers, color);
12
+
13
+ /* 覆盖博客园bundle css*/
14
+ @media screen and (max-width: 767px) {
15
+ #cnblogs_post_body td {
16
+ white-space: pre;
17
+ }
18
+ }
19
+
20
+ @media screen and (max-width: 768px) {
21
+ .awes-linenumber {
22
+ display: none;
23
+ }
24
+ }
25
+
26
+ /* Markdown */
27
+ #cnblogs_post_body {
28
+ pre {
29
+ display: flex;
30
+ ul.awes-linenumber {
31
+ margin-top: 0;
32
+ }
33
+ .awes-linenumber {
34
+ margin: 0;
35
+ padding: 16px 16px 8px 16px;
36
+ li {
37
+ font-weight: normal;
38
+ color: $lineNumbersColor;
39
+ list-style: none;
40
+ text-align: right;
41
+ line-height: 1.5;
42
+ font-size: 15px;
43
+ }
44
+ }
45
+ }
46
+ }
47
+
48
+ /* 富文本 */
49
+ #cnblogs_post_body .cnblogs_code {
50
+ pre {
51
+ display: block;
52
+ span[style='color: #008080;'] {
53
+ padding: 2px 0;
54
+ border: none;
55
+ text-align: center;
56
+ color: $lineNumbersColor !important;
57
+ word-break: normal;
58
+ white-space: pre;
59
+ }
60
+ }
61
+ }
@@ -0,0 +1,18 @@
1
+ import { getCodeTrafficLightOptions } from 'tona-options'
2
+ import { isPostDetailsPage } from '../../utils/cnblog'
3
+ import { insertStyle } from '../../utils/helpers'
4
+
5
+ export function codeTrafficLight(_, devOptions) {
6
+ const { enable } = getCodeTrafficLightOptions(devOptions)
7
+
8
+ if (!enable) {
9
+ return
10
+ }
11
+ if (!isPostDetailsPage()) {
12
+ return
13
+ }
14
+
15
+ insertStyle(
16
+ "pre[class*='language-'].highlighter-prismjs,pre code.hljs{position:relative;padding:2.5em 1em 1em}pre[class*='language-'].highlighter-prismjs::before,pre code.hljs::before{content:'';position:absolute;top:10px;left:12px;width:12px;height:12px;background:#fe5f59;border-radius:50%;box-shadow:20px 0 #febb2c,40px 0 #29c73f;z-index:2;}",
17
+ )
18
+ }
File without changes
@@ -0,0 +1,81 @@
1
+ /**
2
+ * 设置皮肤色
3
+ * 需要皮肤使用相关 css 自定义属性
4
+ */
5
+ import { getThemeOptions } from 'tona-options'
6
+ import { randomColor } from '../../utils/helpers'
7
+
8
+ /**
9
+ * 将 16 进制颜色转成 rgb 或 rgba
10
+ * @param {string} hex
11
+ * @param {number} opacity
12
+ */
13
+ function hexToRgba(hex, opacity) {
14
+ if (!hex) {
15
+ return
16
+ }
17
+
18
+ // Check if already an RGB value
19
+ if (/^rgb\(/i.test(hex)) {
20
+ return hex
21
+ }
22
+
23
+ // Use explicit character ranges for better clarity
24
+ const hexReg = /^#(?:[0-9A-F]{3}|[0-9A-F]{6})$/i
25
+ if (!hexReg.test(hex)) {
26
+ return hex
27
+ }
28
+
29
+ // Remove the # and handle 3-digit hex shorthand
30
+ let hexValue = hex.slice(1)
31
+ if (hexValue.length === 3) {
32
+ hexValue = hexValue
33
+ .split('')
34
+ .map((char) => char + char)
35
+ .join('')
36
+ }
37
+
38
+ const red = Number.parseInt(hexValue.slice(0, 2), 16)
39
+ const green = Number.parseInt(hexValue.slice(2, 4), 16)
40
+ const blue = Number.parseInt(hexValue.slice(4, 6), 16)
41
+
42
+ if (opacity === undefined || opacity === null) {
43
+ return `rgb(${red},${green},${blue})`
44
+ }
45
+
46
+ return `rgba(${red},${green},${blue},${opacity})`
47
+ }
48
+
49
+ /**
50
+ * 获取皮肤色
51
+ * @param {*} color
52
+ */
53
+ function buildMainColor(color) {
54
+ const mainColor = color === 'random' ? randomColor('rgba') : color
55
+ return mainColor
56
+ }
57
+
58
+ /**
59
+ * 插入 css 变量
60
+ * @param {*} color
61
+ */
62
+ function insertStyle(color) {
63
+ const primary = buildMainColor(color)
64
+ const primary8 = hexToRgba(primary, 0.85)
65
+ const primary4 = hexToRgba(primary, 0.4)
66
+ const primary2 = hexToRgba(primary, 0.2)
67
+
68
+ $('head').append(
69
+ `<style class="themeColor">:root{
70
+ --themeColor: ${primary};
71
+ --theme-primary-8: ${primary8};
72
+ --theme-primary-4: ${primary4};
73
+ --theme-primary-2: ${primary2};
74
+ </style>`,
75
+ )
76
+ }
77
+
78
+ export function colorMode(_, devOptions) {
79
+ const { color } = getThemeOptions(devOptions)
80
+ insertStyle(color)
81
+ }
File without changes
@@ -0,0 +1,85 @@
1
+ import { getCurrentPage } from '../../utils/cnblog'
2
+ import { poll } from '../../utils/helpers'
3
+
4
+ /**
5
+ * 构建头像
6
+ */
7
+ function buildAvatars() {
8
+ if ($('.custom-comment-avatar').length) {
9
+ return
10
+ }
11
+ $('.feedbackItem').each(function () {
12
+ let avatar = $(this).children('.feedbackCon').children('span:last').html()
13
+
14
+ avatar = avatar
15
+ ? avatar.replace('http://', 'https://')
16
+ : 'https://pic.cnblogs.com/face/sample_face.gif'
17
+
18
+ const ele = `<div class='custom-comment-avatar'><img src="${avatar}" class='avatar' /></div>`
19
+ $(this).children('.feedbackCon').prepend(ele)
20
+ })
21
+ }
22
+
23
+ /**
24
+ * 调整支持反对按钮位置
25
+ */
26
+ function moveSupport() {
27
+ $('.comment_vote').each(function () {
28
+ $(this).appendTo($(this).parent().siblings('.feedbackListSubtitle'))
29
+ })
30
+ }
31
+
32
+ /**
33
+ * 作者回复靠右
34
+ */
35
+ function authorRight() {
36
+ $('.feedbackItem').each(function () {
37
+ const isAuthor = $(this).find('.louzhu').text() === '楼主'
38
+ if (isAuthor) {
39
+ $(this).addClass('custom-comments-author')
40
+ }
41
+ })
42
+ }
43
+
44
+ /**
45
+ * 组合
46
+ */
47
+ function build() {
48
+ buildAvatars()
49
+ moveSupport()
50
+ authorRight()
51
+ }
52
+
53
+ /**
54
+ * 监听 ajax
55
+ */
56
+ function listener() {
57
+ window.renderCommentsAvatars = build
58
+ $(document).ajaxComplete((_, __, option) => {
59
+ if (
60
+ option.url.includes('PostComment/Add') ||
61
+ option.url.includes('DeleteComment')
62
+ ) {
63
+ // eslint-disable-next-line new-cap
64
+ new window.blogCommentManager().renderComments(0)
65
+ }
66
+ })
67
+ $(document).ajaxComplete((_, __, option) => {
68
+ if (option.url.includes('GetComments')) {
69
+ window.renderCommentsAvatars()
70
+ window.buildEmojis()
71
+ window.imagebox()
72
+ }
73
+ })
74
+ poll(() => $('.feedbackItem').length, build)
75
+ }
76
+
77
+ export function commentsAvatars() {
78
+ if (getCurrentPage() !== 'post') {
79
+ return
80
+ }
81
+ if ($('.custom-comment-avatar').lenght) {
82
+ return
83
+ }
84
+ listener()
85
+ }
@@ -0,0 +1,3 @@
1
+ #tip_comment {
2
+ display: none;
3
+ }
@@ -0,0 +1,115 @@
1
+ import { getDarkModeOptions } from 'tona-options'
2
+
3
+ /**
4
+ * 覆盖自定义背景色
5
+ * @param {string} mode
6
+ */
7
+ // function setBackground(mode) {
8
+ // const {
9
+ // enable,
10
+ // value,
11
+ // type,
12
+ // } = window.opts.bodyBackground
13
+ // if (!enable) return
14
+
15
+ // if (mode === 'dark') {
16
+ // if (type !== 'color') return
17
+ // setTimeout(() => {
18
+ // $('body').css('background-color', '#333')
19
+ // }, 0)
20
+ // }
21
+
22
+ // if (mode === 'light') {
23
+ // if (type !== 'color') return
24
+ // $('body').css('background-color', `${value}`) // bodybgc设置
25
+ // }
26
+ // }
27
+
28
+ /**
29
+ * 切换代码块深色、浅色主题
30
+ * @param {string} mode 'dark' | 'light'
31
+ */
32
+ function setCodeTheme(mode) {
33
+ mode === 'dark'
34
+ ? window.highlighter.setTheme(window.darkModeCodeHighlightTheme)
35
+ : window.highlighter.setTheme(window.codeHighlightTheme)
36
+ }
37
+
38
+ /**
39
+ * 在暗色皮肤和亮色皮肤之间切换
40
+ * @param {string} mode 'dark' | 'light'
41
+ * @param {boolean} withTransition
42
+ */
43
+ function changeMode(mode, withTransition = true) {
44
+ setCodeTheme(mode)
45
+ $('html').attr('theme', mode)
46
+ localStorage.modeType = mode
47
+
48
+ const transitionClassName =
49
+ mode === 'dark' ? 'light-to-dark' : 'dark-to-light'
50
+
51
+ if (withTransition) {
52
+ $('body').addClass(transitionClassName)
53
+ }
54
+
55
+ setTimeout(() => $('body').removeClass(transitionClassName), 1200)
56
+ }
57
+
58
+ /**
59
+ * 初始化
60
+ * @param {string} darkDefault
61
+ * @param {boolean} autoDark
62
+ * @param {boolean} autoLight
63
+ */
64
+ function init(darkDefault, autoDark, autoLight) {
65
+ const hour = new Date().getHours()
66
+ const isNight = hour > 19 || hour <= 5
67
+ const storage = localStorage.modeType
68
+
69
+ const followStorage = () => {
70
+ if (storage) {
71
+ changeMode(storage, false)
72
+ return
73
+ }
74
+
75
+ if (!storage) {
76
+ window.matchMedia('(prefers-color-scheme: dark)').matches
77
+ ? changeMode('dark', false)
78
+ : changeMode('light', false)
79
+ }
80
+ }
81
+
82
+ if (!storage && darkDefault) {
83
+ changeMode('dark', false)
84
+ return
85
+ }
86
+
87
+ if (isNight) {
88
+ autoDark ? changeMode('dark', false) : followStorage()
89
+ }
90
+
91
+ if (!isNight) {
92
+ autoLight ? changeMode('light', false) : followStorage()
93
+ }
94
+ }
95
+
96
+ /**
97
+ * 处理皮肤切换按钮点击事件
98
+ */
99
+ function listenToggleButtonClick() {
100
+ $(document).on('click', '.mode-change', () => {
101
+ const isDark = $('html').attr('theme') === 'dark'
102
+ isDark ? changeMode('light') : changeMode('dark')
103
+ })
104
+ }
105
+
106
+ export function darkMode(_, devOptions) {
107
+ const { enable, darkDefault, autoDark, autoLight } =
108
+ getDarkModeOptions(devOptions)
109
+
110
+ if (!enable) {
111
+ return
112
+ }
113
+ init(darkDefault, autoDark, autoLight)
114
+ listenToggleButtonClick()
115
+ }
@@ -0,0 +1,67 @@
1
+ @use 'sass:map';
2
+
3
+ $mode: () !default;
4
+ $mode: map.merge(
5
+ (
6
+ bg-light: #fff,
7
+ bg-dark: #252528,
8
+ ),
9
+ $mode
10
+ );
11
+
12
+ $bg-light: map.get($mode, bg-light);
13
+ $bg-dark: map.get($mode, bg-dark);
14
+
15
+ .dark-to-light:after {
16
+ content: '';
17
+ width: 100vw;
18
+ height: 100vh;
19
+ position: fixed;
20
+ z-index: 99999;
21
+ left: 0;
22
+ top: 0;
23
+ margin-left: 0;
24
+ background-color: $bg-dark;
25
+ opacity: 0.7;
26
+ animation: toLight 0.6s linear 0s forwards;
27
+ pointer-events: none;
28
+ }
29
+
30
+ .light-to-dark:after {
31
+ content: '';
32
+ width: 100vw;
33
+ height: 100vh;
34
+ position: fixed;
35
+ z-index: 99999;
36
+ left: 0;
37
+ top: 0;
38
+ margin-left: 0;
39
+ background-color: $bg-light;
40
+ opacity: 0.7;
41
+ animation: toDark 0.6s linear 0s forwards;
42
+ pointer-events: none;
43
+ }
44
+
45
+ @keyframes toLight {
46
+ 0% {
47
+ background-color: $bg-dark;
48
+ opacity: 0.7;
49
+ }
50
+
51
+ 100% {
52
+ background-color: $bg-light;
53
+ opacity: 0;
54
+ }
55
+ }
56
+
57
+ @keyframes toDark {
58
+ 0% {
59
+ background-color: $bg-light;
60
+ opacity: 0.7;
61
+ }
62
+
63
+ 100% {
64
+ background-color: $bg-dark;
65
+ opacity: 0;
66
+ }
67
+ }
@@ -0,0 +1,45 @@
1
+ import { getDonationOptions } from 'tona-options'
2
+ import { getCurrentPage } from '../../utils/cnblog'
3
+ import { poll } from '../../utils/helpers'
4
+
5
+ /**
6
+ * 二维码展开收起操作
7
+ */
8
+ function qrcodeToggle() {
9
+ $('#custom-donation-btn').click(() => {
10
+ $('#custom-donation-qrcode').toggle('swing')
11
+ })
12
+ $('#custom-donation-qrcode div').click(function () {
13
+ $(this).parent().toggle('linear')
14
+ })
15
+ }
16
+
17
+ export function donation(_, devOptions) {
18
+ const { enable, qrcodes } = getDonationOptions(devOptions)
19
+
20
+ if (!enable) {
21
+ return
22
+ }
23
+ if (getCurrentPage() !== 'post') {
24
+ return
25
+ }
26
+ if (!qrcodes.length) {
27
+ return
28
+ }
29
+
30
+ poll(
31
+ () => $('#green_channel_favorite').length && $('#blog_post_info').length,
32
+ () => {
33
+ const btn = '<a id="custom-donation-btn">打赏</a>'
34
+ const qrcode = $('<div id="custom-donation-qrcode"></div>')
35
+
36
+ qrcodes.forEach((item) => {
37
+ qrcode.append(`<div style="background-image: url(${item})"></div>`)
38
+ })
39
+ $('#green_channel_favorite').after(btn)
40
+ $('#blog_post_info').before(qrcode)
41
+
42
+ qrcodeToggle()
43
+ },
44
+ )
45
+ }
@@ -0,0 +1,63 @@
1
+ @use 'sass:map';
2
+
3
+ $donation: () !default;
4
+
5
+ $donation: map.merge(
6
+ (
7
+ btnColors: #10ac84,
8
+ qrcodeBackground: #fff,
9
+ ),
10
+ $donation
11
+ ) !default;
12
+
13
+ $donationBtnColors: map.get($donation, btnColors);
14
+ $donationQrcodeBackground: map.get($donation, qrcodeBackground);
15
+
16
+ #custom-donation-btn {
17
+ background-color: $donationBtnColors !important;
18
+ padding: 4px 10px !important;
19
+ &:hover {
20
+ box-shadow: 0 0 5px #999;
21
+ transform: scale(1.1);
22
+ transform: translateY(-2px);
23
+ transition: all 0.2s;
24
+ }
25
+ }
26
+
27
+ #custom-donation-qrcode {
28
+ display: none;
29
+ position: relative;
30
+ cursor: pointer;
31
+ z-index: 999999999;
32
+ text-align: center;
33
+ & > div {
34
+ display: inline-block;
35
+ margin: 0 auto;
36
+ margin-right: 20px;
37
+ width: 180px;
38
+ height: 180px;
39
+ background-size: contain;
40
+ background-repeat: no-repeat;
41
+ border-radius: 5px;
42
+ background-color: $donationQrcodeBackground;
43
+ }
44
+ }
45
+
46
+ @media screen and (max-width: 767px) {
47
+ #blog_post_info_block #blog_post_info #green_channel {
48
+ justify-content: center;
49
+ }
50
+ #custom-donation-btn {
51
+ margin: 3px !important;
52
+ &:hover {
53
+ transform: none;
54
+ }
55
+ }
56
+ #custom-donation-qrcode {
57
+ & > div {
58
+ margin-right: 0;
59
+ width: 100%;
60
+ height: 320px;
61
+ }
62
+ }
63
+ }