前言

转载自:安知鱼butterfly重装日记

效果预览

ps:打赏会有投币特效和┗|`O′|┛ 嗷~~的一声~

步骤

1. 修改[Blogroot]\themes\butterfly\languages\zh-CN.yml

1
2
3
4
5
6
7
8
9
10
date_suffix:
just: 刚刚
min: 分钟前
hour: 小时前
day: 天前
month: 个月前

- donate: 打赏
+ donate: 不给糖果就捣蛋
share: 分享

2. 修改[Blogroot]\themes\butterfly\layout\includes\post\reward.pug,整体替换为以下内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
link(rel='stylesheet' href=url_for(theme.CDN.option.coin_css) media="defer" onload="this.media='all'")
.post-reward
button.tip-button.reward-button
span.tip-button__text= _p('donate')
.coin-wrapper
.coin
.coin__middle
.coin__back
.coin__front
.reward-main
ul.reward-all
each item in theme.reward.QR_code
- var clickTo = (item.itemlist||item).link ? (item.itemlist||item).link : (item.itemlist||item).img
li.reward-item
a(href=clickTo target='_blank')
img.post-qr-code-img(src=url_for((item.itemlist||item).img) alt=(item.itemlist||item).text)
.post-qr-code-desc=(item.itemlist||item).text
if theme.reward.coinAudio
- var coinAudio = theme.reward.coinAudio ? url_for(theme.reward.coinAudio) : 'https://cdn.cbd.int/akilar-candyassets@1.0.36/audio/coin.mp3'
audio#coinAudio(src=coinAudio)
script(defer src=url_for(theme.CDN.option.coin_js))

3. 新建[Blogroot]source\css\coin\coin.css

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
.tip-button {
border: 0;
border-radius: 0.25rem;
cursor: pointer;
font-size: 20px;
font-weight: 600;
height: 2.6rem;
margin-bottom: -4rem;
outline: 0;
position: relative;
top: 0;
transform-origin: 0% 100%;
transition: transform 50ms ease-in-out;
width: auto;
-webkit-tap-highlight-color: transparent;
}
.tip-button:active {
transform: rotate(4deg);
}
.tip-button.clicked {
animation: 150ms ease-in-out 1 shake;
pointer-events: none;
}
.tip-button.clicked .tip-button__text {
opacity: 0;
transition: opacity 100ms linear 200ms;
}
.tip-button.clicked::before {
height: 0.5rem;
width: 60%;
background: $button-hover-color;
}
.tip-button.clicked .coin {
transition: margin-bottom 1s linear 200ms;
margin-bottom: 0;
}
.tip-button.shrink-landing::before {
transition: width 200ms ease-in;
width: 0;
}
.tip-button.coin-landed::after {
opacity: 1;
transform: scale(1);
transform-origin: 50% 100%;
}
.tip-button.coin-landed .coin-wrapper {
background: radial-gradient(circle at 35% 97%, rgba(3, 16, 50, 0.4) 0.04rem, transparent 0.04rem), radial-gradient(
circle at 45% 92%,
rgba(3, 16, 50, 0.4) 0.04rem,
transparent 0.02rem
), radial-gradient(circle at 55% 98%, rgba(3, 16, 50, 0.4) 0.04rem, transparent 0.04rem), radial-gradient(circle at
65% 96%, rgba(3, 16, 50, 0.4) 0.06rem, transparent 0.06rem);
background-position: center bottom;
background-size: 100%;
bottom: -1rem;
opacity: 0;
transform: scale(2) translateY(-10px);
}
.tip-button__text {
color: #fff;
margin-right: 1.8rem;
opacity: 1;
position: relative;
transition: opacity 100ms linear 500ms;
z-index: 3;
}
.tip-button::before {
border-radius: 0.25rem;
bottom: 0;
content: "";
display: block;
height: 100%;
left: 50%;
position: absolute;
transform: translateX(-50%);
transition: height 250ms ease-in-out 400ms, width 250ms ease-in-out 300ms;
width: 100%;
z-index: 2;
}
.tip-button::after {
bottom: -1rem;
color: white;
content: "ヾ(≧O≦)〃嗷~"; /*点击后显示的内容*/
height: 110%;
left: 0;
opacity: 0;
position: absolute;
pointer-events: none;
text-align: center;
transform: scale(0);
transform-origin: 50% 20%;
transition: transform 200ms cubic-bezier(0, 0, 0.35, 1.43);
width: 100%;
z-index: 1;
}

.coin-wrapper {
background: none;
bottom: 0;
height: 18rem;
left: 0;
opacity: 1;
overflow: hidden;
pointer-events: none;
position: absolute;
transform: none;
transform-origin: 50% 100%;
transition: opacity 200ms linear 100ms, transform 300ms ease-out;
width: 100%;
}

.coin {
--front-y-multiplier: 0;
--back-y-multiplier: 0;
--coin-y-multiplier: 0;
--coin-x-multiplier: 0;
--coin-scale-multiplier: 0;
--coin-rotation-multiplier: 0;
--shine-opacity-multiplier: 0.4;
--shine-bg-multiplier: 50%;
bottom: calc(var(--coin-y-multiplier) * 1rem - 3.5rem);
height: 3.5rem;
margin-bottom: 3.05rem;
position: absolute;
right: calc(var(--coin-x-multiplier) * 34% + 16%);
transform: translateX(50%) scale(calc(0.4 + var(--coin-scale-multiplier))) rotate(calc(var(
--coin-rotation-multiplier
) * -1deg));
transition: opacity 100ms linear 200ms;
width: 3.5rem;
z-index: 3;
}
.coin__front,
.coin__middle,
.coin__back,
.coin::before,
.coin__front::after,
.coin__back::after {
border-radius: 50%;
box-sizing: border-box;
height: 100%;
left: 0;
position: absolute;
width: 100%;
z-index: 3;
}
.coin__front {
background: radial-gradient(circle at 50% 50%, transparent 50%, rgba(115, 124, 153, 0.4) 54%, #c2cadf 54%),
linear-gradient(210deg, #8590b3 32%, transparent 32%), linear-gradient(150deg, #8590b3 32%, transparent 32%),
linear-gradient(to right, #8590b3 22%, transparent 22%, transparent 78%, #8590b3 78%), linear-gradient(
to bottom,
#fcfaf9 44%,
transparent 44%,
transparent 65%,
#fcfaf9 65%,
#fcfaf9 71%,
#8590b3 71%
), linear-gradient(to right, transparent 28%, #fcfaf9 28%, #fcfaf9 34%, #8590b3 34%, #8590b3 40%, #fcfaf9 40%, #fcfaf9
47%, #8590b3 47%, #8590b3 53%, #fcfaf9 53%, #fcfaf9 60%, #8590b3 60%, #8590b3 66%, #fcfaf9 66%, #fcfaf9 72%, transparent
72%);
background-color: #8590b3;
background-size: 100% 100%;
transform: translateY(calc(var(--front-y-multiplier) * 0.3181818182rem / 2)) scaleY(var(--front-scale-multiplier));
}
.coin__front::after {
background: rgba(0, 0, 0, 0.2);
content: "";
opacity: var(--front-y-multiplier);
}
.coin__middle {
background: #737c99;
transform: translateY(calc(var(--middle-y-multiplier) * 0.3181818182rem / 2)) scaleY(var(--middle-scale-multiplier));
}
.coin__back {
background: radial-gradient(circle at 50% 50%, transparent 50%, rgba(115, 124, 153, 0.4) 54%, #c2cadf 54%),
radial-gradient(circle at 50% 40%, #fcfaf9 23%, transparent 23%), radial-gradient(circle at 50% 100%, #fcfaf9 35%, transparent
35%);
background-color: #8590b3;
background-size: 100% 100%;
transform: translateY(calc(var(--back-y-multiplier) * 0.3181818182rem / 2)) scaleY(var(--back-scale-multiplier));
}
.coin__back::after {
background: rgba(0, 0, 0, 0.2);
content: "";
opacity: var(--back-y-multiplier);
}
.coin::before {
background: radial-gradient(circle at 25% 65%, transparent 50%, rgba(255, 255, 255, 0.9) 90%), linear-gradient(55deg, transparent
calc(var(--shine-bg-multiplier) + 0%), #e9f4ff calc(var(--shine-bg-multiplier) + 0%), transparent calc(var(
--shine-bg-multiplier
) + 50%));
content: "";
opacity: var(--shine-opacity-multiplier);
transform: translateY(calc(var(--middle-y-multiplier) * 0.3181818182rem / -2)) scaleY(var(--middle-scale-multiplier))
rotate(calc(var(--coin-rotation-multiplier) * 1deg));
z-index: 10;
}
.coin::after {
background: #737c99;
content: "";
height: 0.3181818182rem;
left: 0;
position: absolute;
top: 50%;
transform: translateY(-50%);
width: 100%;
z-index: 2;
}

@keyframes shake {
0% {
transform: rotate(4deg);
}
66% {
transform: rotate(-4deg);
}
100% {
transform: rotate();
}
}

4. 新建[Blogroot]\source\js\coin\coin.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
var tipButtons = document.querySelectorAll(".tip-button");

function coinAudio() {
var coinAudio = document.getElementById("coinAudio");
if (coinAudio) {
coinAudio.play(); //有音频时播放
}
}
// Loop through all buttons (allows for multiple buttons on page)
tipButtons.forEach(button => {
var coin = button.querySelector(".coin");

// The larger the number, the slower the animation
coin.maxMoveLoopCount = 90;

button.addEventListener("click", () => {
if (/Android|webOS|BlackBerry/i.test(navigator.userAgent)) return true; //媒体选择
if (button.clicked) return;
button.classList.add("clicked");

// Wait to start flipping th coin because of the button tilt animation
setTimeout(() => {
// Randomize the flipping speeds just for fun
coin.sideRotationCount = Math.floor(Math.random() * 5) * 90;
coin.maxFlipAngle = (Math.floor(Math.random() * 4) + 3) * Math.PI;
button.clicked = true;
flipCoin();
coinAudio();
}, 50);
});

var flipCoin = () => {
coin.moveLoopCount = 0;
flipCoinLoop();
};

var resetCoin = () => {
coin.style.setProperty("--coin-x-multiplier", 0);
coin.style.setProperty("--coin-scale-multiplier", 0);
coin.style.setProperty("--coin-rotation-multiplier", 0);
coin.style.setProperty("--shine-opacity-multiplier", 0.4);
coin.style.setProperty("--shine-bg-multiplier", "50%");
coin.style.setProperty("opacity", 1);
// Delay to give the reset animation some time before you can click again
setTimeout(() => {
button.clicked = false;
}, 300);
};

var flipCoinLoop = () => {
coin.moveLoopCount++;
var percentageCompleted = coin.moveLoopCount / coin.maxMoveLoopCount;
coin.angle = -coin.maxFlipAngle * Math.pow(percentageCompleted - 1, 2) + coin.maxFlipAngle;

// Calculate the scale and position of the coin moving through the air
coin.style.setProperty("--coin-y-multiplier", -11 * Math.pow(percentageCompleted * 2 - 1, 4) + 11);
coin.style.setProperty("--coin-x-multiplier", percentageCompleted);
coin.style.setProperty("--coin-scale-multiplier", percentageCompleted * 0.6);
coin.style.setProperty("--coin-rotation-multiplier", percentageCompleted * coin.sideRotationCount);

// Calculate the scale and position values for the different coin faces
// The math uses sin/cos wave functions to similate the circular motion of 3D spin
coin.style.setProperty("--front-scale-multiplier", Math.max(Math.cos(coin.angle), 0));
coin.style.setProperty("--front-y-multiplier", Math.sin(coin.angle));

coin.style.setProperty("--middle-scale-multiplier", Math.abs(Math.cos(coin.angle), 0));
coin.style.setProperty("--middle-y-multiplier", Math.cos((coin.angle + Math.PI / 2) % Math.PI));

coin.style.setProperty("--back-scale-multiplier", Math.max(Math.cos(coin.angle - Math.PI), 0));
coin.style.setProperty("--back-y-multiplier", Math.sin(coin.angle - Math.PI));

coin.style.setProperty("--shine-opacity-multiplier", 4 * Math.sin((coin.angle + Math.PI / 2) % Math.PI) - 3.2);
coin.style.setProperty("--shine-bg-multiplier", -40 * (Math.cos((coin.angle + Math.PI / 2) % Math.PI) - 0.5) + "%");

// Repeat animation loop
if (coin.moveLoopCount < coin.maxMoveLoopCount) {
if (coin.moveLoopCount === coin.maxMoveLoopCount - 6) button.classList.add("shrink-landing");
window.requestAnimationFrame(flipCoinLoop);
} else {
button.classList.add("coin-landed");
coin.style.setProperty("opacity", 0);
setTimeout(() => {
button.classList.remove("clicked", "shrink-landing", "coin-landed");
setTimeout(() => {
resetCoin();
}, 300);
}, 1500);
}
};
});

5. 修改_config.butterfly.yml,添加音频文件配置项,添加 CDN 配置项:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
  # Sponsor/reward
reward:
enable: true
+ coinAudio: https://cdn.cbd.int/akilar-candyassets@1.0.36/audio/aowu.m4a
QR_code:
- img: https://npm.elemecdn.com/anzhiyu-blog@1.1.6/img/post/common/qrcode-weichat.png
link:
text: wechat
- img: https://npm.elemecdn.com/anzhiyu-blog@1.1.6/img/post/common/qrcode-alipay.png
link:
text: alipay
CDN:
# main
main_css: /css/index.css
jquery: https://cdn.cbd.int/jquery@latest/dist/jquery.min.js
main: /js/main.js
utils:/js/utils.js
option:
+ # 打赏按钮投币效果
+ coin_js: /js/coin/coin.js
+ coin_css: /css/coin/coin.css

6. 修改[Blogroot]\themes\butterfly\source\css\_layout\reward.styl,整体替换为以下内容

注意:如果打赏图片有两张的话,请将下列代码中的.reward-main模块中的width改为200%

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
.post-reward
position: relative
margin-top: 4rem
width: 100%
text-align: center

.reward-button
display: inline-block
padding: .2rem 1.2rem
background: var(--btn-bg)
color: var(--btn-color)
cursor: pointer
transition: all .4s

&:hover
box-shadow: inset 15em 0 0 0 var(--btn-hover-color)

.reward-main
display: block

.reward-main
position: absolute
bottom: 40px
left: -25%
z-index: 100
display: none
padding: 0 0 15px
width: 150%

.reward-all
display: inline-block
margin: 0
padding: 1rem .5rem
border-radius: 4px
background: var(--reward-pop)

&:before
position: absolute
bottom: -10px
left: 0
width: 100%
height: 20px
content: ''

&:after
position: absolute
right: 0
bottom: 2px
left: 0
margin: 0 auto
width: 0
height: 0
border-top: 13px solid var(--reward-pop)
border-right: 13px solid transparent
border-left: 13px solid transparent
content: ''

.reward-item
display: inline-block
padding: 0 8px
list-style-type: none
vertical-align: top

img
width: 130px
height: 130px

.post-qr-code-desc
padding-top: .4rem
width: 130px
color: $reward-pop-up-color

7. hexo三连