BirkhoffLee commited on
Commit
4f8826f
·
unverified ·
1 Parent(s): 50428e9

feat: 增加了 CI

Browse files
Files changed (2) hide show
  1. .cnb.yml +28 -0
  2. app/static/index.html +212 -31
.cnb.yml CHANGED
@@ -16,3 +16,31 @@ $:
16
  stages:
17
  - name: vscode go
18
  type: vscode:go
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
16
  stages:
17
  - name: vscode go
18
  type: vscode:go
19
+
20
+ main:
21
+ push:
22
+ - runner:
23
+ cpus: 1
24
+ imports:
25
+ - https://cnb.cool/maikebuke/Tools/Huggingface/AccessToken/-/blob/main/key.yml
26
+ env:
27
+ HF_SPACE_URL: "https://huggingface.co/spaces/ServiceX/Sublink"
28
+ stages:
29
+ - name: Force Push To Huggingface Spaces
30
+ script: |
31
+ # 从 HF_SPACE_URL 提取 owner/repo 路径用于构造带认证的 git remote
32
+ HF_REPO_PATH=$(echo "$HF_SPACE_URL" | sed 's|https://huggingface.co/spaces/||')
33
+ HF_REMOTE="https://user:${HF_TOKEN_FULL}@huggingface.co/spaces/${HF_REPO_PATH}"
34
+
35
+ # 删除 CI 文件,避免推送到目标仓库
36
+ rm -f .cnb.yml
37
+
38
+ git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
39
+ git config user.name "github-actions[bot]"
40
+
41
+ # 将删除操作提交(基于当前 HEAD)
42
+ git add -A
43
+ git diff --cached --quiet || git commit -m "ci: remove CI config before sync"
44
+
45
+ # 强制推送到 Huggingface Space
46
+ git push "$HF_REMOTE" HEAD:main --force
app/static/index.html CHANGED
@@ -7,40 +7,106 @@
7
  <style>
8
  *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
10
  body {
11
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
12
- background: #0f1117;
13
  color: #e2e8f0;
14
  min-height: 100vh;
15
  display: flex;
16
  align-items: flex-start;
17
  justify-content: center;
18
  padding: 2rem 1rem;
 
 
 
 
 
 
 
 
 
 
19
  }
20
 
21
  .container {
22
  width: 100%;
23
  max-width: 680px;
 
 
24
  }
25
 
26
  h1 {
27
- font-size: 1.5rem;
28
- font-weight: 600;
29
  margin-bottom: 0.25rem;
30
- color: #f8fafc;
 
 
 
 
 
 
 
 
 
31
  }
32
 
33
  .subtitle {
34
- font-size: 0.875rem;
35
- color: #64748b;
36
  margin-bottom: 2rem;
 
 
 
37
  }
38
 
 
39
  .card {
40
- background: #1e2130;
41
- border: 1px solid #2d3348;
42
  border-radius: 12px;
43
  padding: 1.5rem;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
44
  }
45
 
46
  .field {
@@ -54,24 +120,25 @@
54
  color: #94a3b8;
55
  margin-bottom: 0.4rem;
56
  text-transform: uppercase;
57
- letter-spacing: 0.04em;
58
  }
59
 
60
  textarea, select, input[type="text"] {
61
  width: 100%;
62
- background: #131620;
63
  border: 1px solid #2d3348;
64
  border-radius: 8px;
65
  color: #e2e8f0;
66
  font-size: 0.9rem;
67
  padding: 0.625rem 0.75rem;
68
  outline: none;
69
- transition: border-color 0.15s;
70
  font-family: inherit;
71
  }
72
 
73
  textarea:focus, select:focus, input[type="text"]:focus {
74
- border-color: #6366f1;
 
75
  }
76
 
77
  textarea {
@@ -88,7 +155,7 @@
88
  padding-right: 2rem;
89
  }
90
 
91
- select option { background: #1e2130; }
92
 
93
  /* 高级选项折叠 */
94
  .advanced-toggle {
@@ -103,9 +170,11 @@
103
  border: none;
104
  background: none;
105
  padding: 0;
 
 
106
  }
107
 
108
- .advanced-toggle:hover { color: #94a3b8; }
109
 
110
  .toggle-icon {
111
  display: inline-block;
@@ -130,18 +199,25 @@
130
  display: flex;
131
  align-items: center;
132
  gap: 0.375rem;
133
- background: #131620;
134
  border: 1px solid #2d3348;
135
  border-radius: 6px;
136
  padding: 0.3rem 0.6rem;
137
  cursor: pointer;
138
  font-size: 0.8125rem;
139
  color: #94a3b8;
140
- transition: border-color 0.15s, color 0.15s;
141
  }
142
 
143
  .bool-item:hover { border-color: #6366f1; color: #e2e8f0; }
144
 
 
 
 
 
 
 
 
145
  .bool-item input[type="checkbox"] {
146
  width: auto;
147
  accent-color: #6366f1;
@@ -166,27 +242,46 @@
166
  font-size: 0.9rem;
167
  font-weight: 500;
168
  cursor: pointer;
169
- transition: opacity 0.15s, background 0.15s;
170
  font-family: inherit;
 
 
171
  }
172
 
173
- .btn:hover { opacity: 0.85; }
174
  .btn:active { opacity: 0.7; }
175
 
176
  .btn-primary {
177
- background: #6366f1;
178
  color: #fff;
179
  padding: 0.65rem 1.5rem;
180
  width: 100%;
 
 
 
 
 
 
 
 
 
 
 
 
181
  }
182
 
 
 
 
183
  .btn-sm {
184
  background: #2d3348;
185
  color: #e2e8f0;
186
  padding: 0.4rem 0.85rem;
187
  font-size: 0.8rem;
 
188
  }
189
 
 
 
190
  /* 结果区域 */
191
  #result-section {
192
  margin-top: 1.25rem;
@@ -195,14 +290,18 @@
195
 
196
  #result-section.show { display: block; }
197
 
 
198
  .result-box {
199
- background: #131620;
200
  border: 1px solid #2d3348;
 
201
  border-radius: 8px;
202
  padding: 0.75rem 1rem;
203
  word-break: break-all;
204
  font-size: 0.8375rem;
205
- color: #a5b4fc;
 
 
206
  line-height: 1.5;
207
  margin-bottom: 0.75rem;
208
  }
@@ -226,19 +325,25 @@
226
 
227
  #error-msg.show { display: block; }
228
 
229
- /* Toast */
230
  #toast {
231
  position: fixed;
232
  bottom: 1.5rem;
233
- right: 1.5rem;
234
- background: #22c55e;
235
- color: #fff;
 
 
236
  padding: 0.5rem 1rem;
237
  border-radius: 8px;
238
  font-size: 0.875rem;
 
 
 
239
  opacity: 0;
240
  transition: opacity 0.3s;
241
  pointer-events: none;
 
242
  }
243
 
244
  #toast.show { opacity: 1; }
@@ -247,11 +352,12 @@
247
  #preview-section { margin-top: 0.75rem; display: none; }
248
  #preview-section.show { display: block; }
249
  #preview-content {
250
- background: #0a0c10;
251
  border: 1px solid #2d3348;
 
252
  border-radius: 8px;
253
  padding: 0.75rem 1rem;
254
- font-family: monospace;
255
  font-size: 0.75rem;
256
  color: #94a3b8;
257
  max-height: 400px;
@@ -263,9 +369,12 @@
263
  </style>
264
  </head>
265
  <body>
 
 
 
266
  <div class="container">
267
- <h1>Sublink</h1>
268
- <p class="subtitle">订阅转换工具</p>
269
 
270
  <div class="card">
271
  <!-- 订阅链接 -->
@@ -367,9 +476,82 @@
367
  </div>
368
  </div>
369
 
370
- <div id="toast">已复制</div>
371
 
372
  <script>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
373
  // 高级选项折叠/展开
374
  const advancedToggle = document.getElementById('advanced-toggle');
375
  const advancedSection = document.getElementById('advanced-section');
@@ -444,7 +626,6 @@ document.getElementById('gen-btn').addEventListener('click', async () => {
444
  };
445
 
446
  hideError();
447
- // 重置预览区
448
  hidePreview();
449
 
450
  try {
 
7
  <style>
8
  *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
9
 
10
+ /* 自定义滚动条 */
11
+ ::-webkit-scrollbar { width: 4px; height: 4px; }
12
+ ::-webkit-scrollbar-track { background: #060914; }
13
+ ::-webkit-scrollbar-thumb { background: #00d4ff; border-radius: 2px; }
14
+
15
+ /* CSS 自定义属性用于旋转边框动画 */
16
+ @property --angle {
17
+ syntax: '<angle>';
18
+ initial-value: 0deg;
19
+ inherits: false;
20
+ }
21
+
22
+ @keyframes spin-border {
23
+ to { --angle: 360deg; }
24
+ }
25
+
26
+ /* 标题光标闪烁 */
27
+ @keyframes blink {
28
+ 0%, 100% { opacity: 1; }
29
+ 50% { opacity: 0; }
30
+ }
31
+
32
+ /* 扫描线按钮效果 */
33
+ @keyframes scan-line {
34
+ 0% { left: -100%; }
35
+ 100% { left: 150%; }
36
+ }
37
+
38
  body {
39
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
40
+ background: #060914;
41
  color: #e2e8f0;
42
  min-height: 100vh;
43
  display: flex;
44
  align-items: flex-start;
45
  justify-content: center;
46
  padding: 2rem 1rem;
47
+ position: relative;
48
+ }
49
+
50
+ /* 背景 canvas 全屏 */
51
+ #bg-canvas {
52
+ position: fixed;
53
+ top: 0; left: 0;
54
+ width: 100%; height: 100%;
55
+ z-index: 0;
56
+ pointer-events: none;
57
  }
58
 
59
  .container {
60
  width: 100%;
61
  max-width: 680px;
62
+ position: relative;
63
+ z-index: 1;
64
  }
65
 
66
  h1 {
67
+ font-size: 1.6rem;
68
+ font-weight: 700;
69
  margin-bottom: 0.25rem;
70
+ color: #00d4ff;
71
+ font-family: 'Courier New', Courier, monospace;
72
+ letter-spacing: 0.15em;
73
+ text-shadow: 0 0 20px #00d4ff, 0 0 40px rgba(0, 212, 255, 0.3);
74
+ }
75
+
76
+ .cursor {
77
+ display: inline-block;
78
+ animation: blink 1s step-end infinite;
79
+ color: #00d4ff;
80
  }
81
 
82
  .subtitle {
83
+ font-size: 0.75rem;
84
+ color: #00d4ff;
85
  margin-bottom: 2rem;
86
+ letter-spacing: 0.25em;
87
+ text-transform: uppercase;
88
+ opacity: 0.6;
89
  }
90
 
91
+ /* Card 旋转渐变边框 */
92
  .card {
93
+ background: rgba(10, 14, 28, 0.9);
 
94
  border-radius: 12px;
95
  padding: 1.5rem;
96
+ position: relative;
97
+ z-index: 0;
98
+ overflow: hidden;
99
+ backdrop-filter: blur(12px);
100
+ }
101
+
102
+ .card::before {
103
+ content: '';
104
+ position: absolute;
105
+ inset: -1px;
106
+ border-radius: 13px;
107
+ background: conic-gradient(from var(--angle), #6366f1, #00d4ff, #6366f1);
108
+ animation: spin-border 4s linear infinite;
109
+ z-index: -1;
110
  }
111
 
112
  .field {
 
120
  color: #94a3b8;
121
  margin-bottom: 0.4rem;
122
  text-transform: uppercase;
123
+ letter-spacing: 0.08em;
124
  }
125
 
126
  textarea, select, input[type="text"] {
127
  width: 100%;
128
+ background: rgba(5, 8, 18, 0.8);
129
  border: 1px solid #2d3348;
130
  border-radius: 8px;
131
  color: #e2e8f0;
132
  font-size: 0.9rem;
133
  padding: 0.625rem 0.75rem;
134
  outline: none;
135
+ transition: border-color 0.2s, box-shadow 0.2s;
136
  font-family: inherit;
137
  }
138
 
139
  textarea:focus, select:focus, input[type="text"]:focus {
140
+ border-color: #00d4ff;
141
+ box-shadow: 0 0 0 2px rgba(0, 212, 255, 0.15), 0 0 12px rgba(0, 212, 255, 0.2);
142
  }
143
 
144
  textarea {
 
155
  padding-right: 2rem;
156
  }
157
 
158
+ select option { background: #0a0e1c; }
159
 
160
  /* 高级选项折叠 */
161
  .advanced-toggle {
 
170
  border: none;
171
  background: none;
172
  padding: 0;
173
+ letter-spacing: 0.08em;
174
+ transition: color 0.2s;
175
  }
176
 
177
+ .advanced-toggle:hover { color: #00d4ff; }
178
 
179
  .toggle-icon {
180
  display: inline-block;
 
199
  display: flex;
200
  align-items: center;
201
  gap: 0.375rem;
202
+ background: rgba(5, 8, 18, 0.8);
203
  border: 1px solid #2d3348;
204
  border-radius: 6px;
205
  padding: 0.3rem 0.6rem;
206
  cursor: pointer;
207
  font-size: 0.8125rem;
208
  color: #94a3b8;
209
+ transition: border-color 0.15s, color 0.15s, box-shadow 0.15s;
210
  }
211
 
212
  .bool-item:hover { border-color: #6366f1; color: #e2e8f0; }
213
 
214
+ /* checked 态发光 */
215
+ .bool-item:has(input:checked) {
216
+ border-color: #6366f1;
217
+ color: #a5b4fc;
218
+ box-shadow: 0 0 6px rgba(99, 102, 241, 0.3);
219
+ }
220
+
221
  .bool-item input[type="checkbox"] {
222
  width: auto;
223
  accent-color: #6366f1;
 
242
  font-size: 0.9rem;
243
  font-weight: 500;
244
  cursor: pointer;
245
+ transition: opacity 0.15s, box-shadow 0.2s;
246
  font-family: inherit;
247
+ position: relative;
248
+ overflow: hidden;
249
  }
250
 
 
251
  .btn:active { opacity: 0.7; }
252
 
253
  .btn-primary {
254
+ background: linear-gradient(90deg, #6366f1, #00d4ff);
255
  color: #fff;
256
  padding: 0.65rem 1.5rem;
257
  width: 100%;
258
+ box-shadow: 0 0 20px rgba(99, 102, 241, 0.4);
259
+ letter-spacing: 0.05em;
260
+ }
261
+
262
+ /* 扫描光效 */
263
+ .btn-primary::after {
264
+ content: '';
265
+ position: absolute;
266
+ top: 0; left: -100%;
267
+ width: 60%; height: 100%;
268
+ background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.15), transparent);
269
+ transition: left 0.4s ease;
270
  }
271
 
272
+ .btn-primary:hover::after { left: 150%; }
273
+ .btn-primary:hover { box-shadow: 0 0 30px rgba(0, 212, 255, 0.5); }
274
+
275
  .btn-sm {
276
  background: #2d3348;
277
  color: #e2e8f0;
278
  padding: 0.4rem 0.85rem;
279
  font-size: 0.8rem;
280
+ transition: background 0.15s, color 0.15s;
281
  }
282
 
283
+ .btn-sm:hover { background: #3d4460; color: #00d4ff; }
284
+
285
  /* 结果区域 */
286
  #result-section {
287
  margin-top: 1.25rem;
 
290
 
291
  #result-section.show { display: block; }
292
 
293
+ /* 终端风格结果框 */
294
  .result-box {
295
+ background: rgba(5, 8, 18, 0.9);
296
  border: 1px solid #2d3348;
297
+ border-left: 2px solid #00d4ff;
298
  border-radius: 8px;
299
  padding: 0.75rem 1rem;
300
  word-break: break-all;
301
  font-size: 0.8375rem;
302
+ font-family: 'Courier New', Courier, monospace;
303
+ color: #00d4ff;
304
+ text-shadow: 0 0 8px rgba(0, 212, 255, 0.4);
305
  line-height: 1.5;
306
  margin-bottom: 0.75rem;
307
  }
 
325
 
326
  #error-msg.show { display: block; }
327
 
328
+ /* Toast:左下角,玻璃风格 */
329
  #toast {
330
  position: fixed;
331
  bottom: 1.5rem;
332
+ left: 1.5rem;
333
+ background: rgba(6, 9, 20, 0.9);
334
+ backdrop-filter: blur(12px);
335
+ border: 1px solid #00d4ff;
336
+ color: #00d4ff;
337
  padding: 0.5rem 1rem;
338
  border-radius: 8px;
339
  font-size: 0.875rem;
340
+ font-family: 'Courier New', monospace;
341
+ letter-spacing: 0.05em;
342
+ box-shadow: 0 0 16px rgba(0, 212, 255, 0.3);
343
  opacity: 0;
344
  transition: opacity 0.3s;
345
  pointer-events: none;
346
+ z-index: 100;
347
  }
348
 
349
  #toast.show { opacity: 1; }
 
352
  #preview-section { margin-top: 0.75rem; display: none; }
353
  #preview-section.show { display: block; }
354
  #preview-content {
355
+ background: rgba(5, 8, 18, 0.95);
356
  border: 1px solid #2d3348;
357
+ border-left: 2px solid #00d4ff;
358
  border-radius: 8px;
359
  padding: 0.75rem 1rem;
360
+ font-family: 'Courier New', Courier, monospace;
361
  font-size: 0.75rem;
362
  color: #94a3b8;
363
  max-height: 400px;
 
369
  </style>
370
  </head>
371
  <body>
372
+ <!-- 背景粒子网络 canvas -->
373
+ <canvas id="bg-canvas"></canvas>
374
+
375
  <div class="container">
376
+ <h1>SUBLINK<span class="cursor">_</span></h1>
377
+ <p class="subtitle">Subscription Converter</p>
378
 
379
  <div class="card">
380
  <!-- 订阅链接 -->
 
476
  </div>
477
  </div>
478
 
479
+ <div id="toast">[ COPIED ]</div>
480
 
481
  <script>
482
+ // 背景粒子网络动画
483
+ (function() {
484
+ const canvas = document.getElementById('bg-canvas');
485
+ const ctx = canvas.getContext('2d');
486
+ const PARTICLE_COUNT = 60;
487
+ const CONNECT_DIST = 120;
488
+ const COLOR = '0, 212, 255';
489
+
490
+ let particles = [];
491
+
492
+ function resize() {
493
+ canvas.width = window.innerWidth;
494
+ canvas.height = window.innerHeight;
495
+ }
496
+
497
+ function initParticles() {
498
+ particles = [];
499
+ for (let i = 0; i < PARTICLE_COUNT; i++) {
500
+ particles.push({
501
+ x: Math.random() * canvas.width,
502
+ y: Math.random() * canvas.height,
503
+ vx: (Math.random() - 0.5) * 0.4,
504
+ vy: (Math.random() - 0.5) * 0.4,
505
+ r: Math.random() * 1.5 + 0.5,
506
+ });
507
+ }
508
+ }
509
+
510
+ function draw() {
511
+ ctx.clearRect(0, 0, canvas.width, canvas.height);
512
+
513
+ // 更新粒子位置
514
+ particles.forEach(p => {
515
+ p.x += p.vx;
516
+ p.y += p.vy;
517
+ // 边界反弹
518
+ if (p.x < 0 || p.x > canvas.width) p.vx *= -1;
519
+ if (p.y < 0 || p.y > canvas.height) p.vy *= -1;
520
+
521
+ // 绘制粒子点
522
+ ctx.beginPath();
523
+ ctx.arc(p.x, p.y, p.r, 0, Math.PI * 2);
524
+ ctx.fillStyle = `rgba(${COLOR}, 0.5)`;
525
+ ctx.fill();
526
+ });
527
+
528
+ // 绘制连线
529
+ for (let i = 0; i < particles.length; i++) {
530
+ for (let j = i + 1; j < particles.length; j++) {
531
+ const dx = particles[i].x - particles[j].x;
532
+ const dy = particles[i].y - particles[j].y;
533
+ const dist = Math.sqrt(dx * dx + dy * dy);
534
+ if (dist < CONNECT_DIST) {
535
+ const alpha = (1 - dist / CONNECT_DIST) * 0.4;
536
+ ctx.beginPath();
537
+ ctx.moveTo(particles[i].x, particles[i].y);
538
+ ctx.lineTo(particles[j].x, particles[j].y);
539
+ ctx.strokeStyle = `rgba(${COLOR}, ${alpha})`;
540
+ ctx.lineWidth = 0.5;
541
+ ctx.stroke();
542
+ }
543
+ }
544
+ }
545
+
546
+ requestAnimationFrame(draw);
547
+ }
548
+
549
+ resize();
550
+ initParticles();
551
+ draw();
552
+ window.addEventListener('resize', () => { resize(); initParticles(); });
553
+ })();
554
+
555
  // 高级选项折叠/展开
556
  const advancedToggle = document.getElementById('advanced-toggle');
557
  const advancedSection = document.getElementById('advanced-section');
 
626
  };
627
 
628
  hideError();
 
629
  hidePreview();
630
 
631
  try {