@anglefeint/astro-theme 0.1.18 → 0.1.20
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.
- package/README.md +21 -1
- package/package.json +1 -1
- package/src/scripts/blogpost/hero-canvas.js +58 -29
- package/src/styles/about/background.css +57 -0
- package/src/styles/about/base.css +58 -0
- package/src/styles/about/keyboard.css +112 -0
- package/src/styles/about/modals.css +159 -0
- package/src/styles/about/panel.css +337 -0
- package/src/styles/about/responsive.css +1 -0
- package/src/styles/about/sidebar.css +39 -0
- package/src/styles/about-page.css +8 -756
- package/src/styles/ai/background.css +1 -0
- package/src/styles/ai/base.css +249 -0
- package/src/styles/ai/controls.css +396 -0
- package/src/styles/ai/hero.css +1 -0
- package/src/styles/ai/prose.css +269 -0
- package/src/styles/ai/related.css +106 -0
- package/src/styles/ai/responsive.css +49 -0
- package/src/styles/blog-post.css +9 -7
- package/src/styles/theme-ai.css +8 -1062
- package/src/styles/theme-cyber.css +1 -0
package/README.md
CHANGED
|
@@ -59,4 +59,24 @@ In the starter/site project, map these aliases to `src/config/*` and `src/i18n/*
|
|
|
59
59
|
- `anglefeint-new-post`
|
|
60
60
|
- `anglefeint-new-page`
|
|
61
61
|
|
|
62
|
-
|
|
62
|
+
Examples:
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
# create one post slug in all default locales
|
|
66
|
+
anglefeint-new-post my-first-post
|
|
67
|
+
|
|
68
|
+
# create post only for selected locales
|
|
69
|
+
anglefeint-new-post my-first-post --locales en,ja
|
|
70
|
+
|
|
71
|
+
# or via environment variable
|
|
72
|
+
ANGLEFEINT_LOCALES=en,ja anglefeint-new-post my-first-post
|
|
73
|
+
|
|
74
|
+
# create a custom page with theme variant
|
|
75
|
+
anglefeint-new-page projects --theme base
|
|
76
|
+
anglefeint-new-page projects --theme ai
|
|
77
|
+
anglefeint-new-page projects --theme cyber
|
|
78
|
+
anglefeint-new-page projects --theme hacker
|
|
79
|
+
anglefeint-new-page projects --theme matrix
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Starter projects can invoke these directly (or wrap them in npm scripts). For most users, `#starter` is the recommended installation path.
|
package/package.json
CHANGED
|
@@ -4,13 +4,17 @@ export function initHeroCanvas(prefersReducedMotion) {
|
|
|
4
4
|
|
|
5
5
|
var canvas = shell.querySelector('.hero-canvas');
|
|
6
6
|
var wrap = shell.querySelector('.hero-canvas-wrap');
|
|
7
|
-
|
|
7
|
+
var heroStack = shell.querySelector('.hero-stack');
|
|
8
|
+
if (!canvas || !wrap || !heroStack) return;
|
|
9
|
+
var ctx = canvas.getContext('2d');
|
|
10
|
+
if (!ctx) return;
|
|
8
11
|
|
|
9
12
|
var src = canvas.getAttribute('data-hero-src');
|
|
10
13
|
if (!src) return;
|
|
11
14
|
|
|
12
15
|
var heroStart = 0;
|
|
13
16
|
var heroRaf = 0;
|
|
17
|
+
var resizeTimer = 0;
|
|
14
18
|
var baseCanvas = document.createElement('canvas');
|
|
15
19
|
var baseCtx = baseCanvas.getContext('2d');
|
|
16
20
|
var pixelCanvas = document.createElement('canvas');
|
|
@@ -19,14 +23,17 @@ export function initHeroCanvas(prefersReducedMotion) {
|
|
|
19
23
|
var noiseCtx = noiseCanvas.getContext('2d');
|
|
20
24
|
var edgeCanvas = document.createElement('canvas');
|
|
21
25
|
var edgeCtx = edgeCanvas.getContext('2d');
|
|
26
|
+
var edgeWorkCanvas = document.createElement('canvas');
|
|
27
|
+
var edgeWorkCtx = edgeWorkCanvas.getContext('2d');
|
|
22
28
|
var edgeReady = false;
|
|
29
|
+
var frameCount = 0;
|
|
23
30
|
|
|
24
31
|
var EDGE_PHASE = 1.8;
|
|
25
32
|
var REVEAL_PHASE = 2.5;
|
|
26
33
|
var INTRO_END = EDGE_PHASE + REVEAL_PHASE;
|
|
27
34
|
|
|
28
35
|
function sizeCanvas() {
|
|
29
|
-
var rect =
|
|
36
|
+
var rect = heroStack.getBoundingClientRect();
|
|
30
37
|
var dpr = Math.min(window.devicePixelRatio || 1, 2);
|
|
31
38
|
canvas.width = Math.max(2, Math.round(rect.width * dpr));
|
|
32
39
|
canvas.height = Math.max(2, Math.round(rect.height * dpr));
|
|
@@ -55,28 +62,44 @@ export function initHeroCanvas(prefersReducedMotion) {
|
|
|
55
62
|
baseCanvas.width = w;
|
|
56
63
|
baseCanvas.height = h;
|
|
57
64
|
drawBase(baseCtx, img, w, h);
|
|
58
|
-
|
|
65
|
+
var workW = Math.max(2, Math.round(w * 0.5));
|
|
66
|
+
var workH = Math.max(2, Math.round(h * 0.5));
|
|
67
|
+
edgeWorkCanvas.width = workW;
|
|
68
|
+
edgeWorkCanvas.height = workH;
|
|
69
|
+
drawBase(edgeWorkCtx, img, workW, workH);
|
|
59
70
|
|
|
60
|
-
var srcImage =
|
|
71
|
+
var srcImage = edgeWorkCtx.getImageData(0, 0, workW, workH);
|
|
61
72
|
var d = srcImage.data;
|
|
62
|
-
var out =
|
|
73
|
+
var out = edgeWorkCtx.createImageData(workW, workH);
|
|
63
74
|
var od = out.data;
|
|
75
|
+
var rowStride = workW * 4;
|
|
64
76
|
|
|
65
|
-
for (var y = 1; y <
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
var i =
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
77
|
+
for (var y = 1; y < workH - 1; y++) {
|
|
78
|
+
var row = y * rowStride;
|
|
79
|
+
var rowAbove = row - rowStride;
|
|
80
|
+
var rowBelow = row + rowStride;
|
|
81
|
+
for (var x = 1; x < workW - 1; x++) {
|
|
82
|
+
var i = row + x * 4;
|
|
83
|
+
var iLeft = i - 4;
|
|
84
|
+
var iRight = i + 4;
|
|
85
|
+
var iAbove = rowAbove + x * 4;
|
|
86
|
+
var iAboveLeft = iAbove - 4;
|
|
87
|
+
var iAboveRight = iAbove + 4;
|
|
88
|
+
var iBelow = rowBelow + x * 4;
|
|
89
|
+
var iBelowLeft = iBelow - 4;
|
|
90
|
+
var iBelowRight = iBelow + 4;
|
|
91
|
+
|
|
92
|
+
var lumAboveLeft = d[iAboveLeft] * 0.299 + d[iAboveLeft + 1] * 0.587 + d[iAboveLeft + 2] * 0.114;
|
|
93
|
+
var lumAbove = d[iAbove] * 0.299 + d[iAbove + 1] * 0.587 + d[iAbove + 2] * 0.114;
|
|
94
|
+
var lumAboveRight = d[iAboveRight] * 0.299 + d[iAboveRight + 1] * 0.587 + d[iAboveRight + 2] * 0.114;
|
|
95
|
+
var lumLeft = d[iLeft] * 0.299 + d[iLeft + 1] * 0.587 + d[iLeft + 2] * 0.114;
|
|
96
|
+
var lumRight = d[iRight] * 0.299 + d[iRight + 1] * 0.587 + d[iRight + 2] * 0.114;
|
|
97
|
+
var lumBelowLeft = d[iBelowLeft] * 0.299 + d[iBelowLeft + 1] * 0.587 + d[iBelowLeft + 2] * 0.114;
|
|
98
|
+
var lumBelow = d[iBelow] * 0.299 + d[iBelow + 1] * 0.587 + d[iBelow + 2] * 0.114;
|
|
99
|
+
var lumBelowRight = d[iBelowRight] * 0.299 + d[iBelowRight + 1] * 0.587 + d[iBelowRight + 2] * 0.114;
|
|
75
100
|
|
|
76
|
-
var gx = -
|
|
77
|
-
|
|
78
|
-
var gy = -luma(x - 1, y - 1) - 2 * luma(x, y - 1) - luma(x + 1, y - 1)
|
|
79
|
-
+ luma(x - 1, y + 1) + 2 * luma(x, y + 1) + luma(x + 1, y + 1);
|
|
101
|
+
var gx = -lumAboveLeft - 2 * lumLeft - lumBelowLeft + lumAboveRight + 2 * lumRight + lumBelowRight;
|
|
102
|
+
var gy = -lumAboveLeft - 2 * lumAbove - lumAboveRight + lumBelowLeft + 2 * lumBelow + lumBelowRight;
|
|
80
103
|
var mag = Math.min(255, Math.sqrt(gx * gx + gy * gy));
|
|
81
104
|
|
|
82
105
|
od[i] = Math.min(255, mag * 0.4);
|
|
@@ -86,15 +109,18 @@ export function initHeroCanvas(prefersReducedMotion) {
|
|
|
86
109
|
}
|
|
87
110
|
}
|
|
88
111
|
|
|
89
|
-
|
|
112
|
+
edgeWorkCtx.putImageData(out, 0, 0);
|
|
113
|
+
edgeCtx.clearRect(0, 0, w, h);
|
|
114
|
+
edgeCtx.imageSmoothingEnabled = true;
|
|
115
|
+
edgeCtx.drawImage(edgeWorkCanvas, 0, 0, workW, workH, 0, 0, w, h);
|
|
90
116
|
edgeReady = true;
|
|
91
117
|
}
|
|
92
118
|
|
|
93
119
|
function heroRender(t) {
|
|
94
120
|
if (!heroStart) heroStart = t;
|
|
95
121
|
var elapsed = (t - heroStart) * 0.001;
|
|
96
|
-
|
|
97
|
-
if (!
|
|
122
|
+
frameCount++;
|
|
123
|
+
if (!canvas.img) {
|
|
98
124
|
heroRaf = requestAnimationFrame(heroRender);
|
|
99
125
|
return;
|
|
100
126
|
}
|
|
@@ -161,7 +187,7 @@ export function initHeroCanvas(prefersReducedMotion) {
|
|
|
161
187
|
ctx.fillStyle = barGrad;
|
|
162
188
|
ctx.fillRect(0, scanPos - 30, w, 60);
|
|
163
189
|
|
|
164
|
-
if (Math.random() < 0.08) {
|
|
190
|
+
if ((frameCount % 2) === 0 && Math.random() < 0.08) {
|
|
165
191
|
var glitchY = Math.random() * h;
|
|
166
192
|
var glitchH = 2 + Math.random() * 12;
|
|
167
193
|
var shiftX = (Math.random() - 0.5) * 12;
|
|
@@ -171,14 +197,14 @@ export function initHeroCanvas(prefersReducedMotion) {
|
|
|
171
197
|
ctx.restore();
|
|
172
198
|
}
|
|
173
199
|
|
|
174
|
-
if (elapsed >= 6 && Math.random() < 0.025) {
|
|
200
|
+
if ((frameCount % 3) === 0 && elapsed >= 6 && Math.random() < 0.025) {
|
|
175
201
|
var dropoutY = Math.floor(Math.random() * h);
|
|
176
202
|
var dropoutH = 2 + Math.floor(Math.random() * 2);
|
|
177
203
|
ctx.fillStyle = 'rgba(0, 0, 0, 0.85)';
|
|
178
204
|
ctx.fillRect(0, dropoutY, w, dropoutH);
|
|
179
205
|
}
|
|
180
206
|
|
|
181
|
-
if (Math.random() < 0.03) {
|
|
207
|
+
if ((frameCount % 3) === 0 && Math.random() < 0.03) {
|
|
182
208
|
var burstY = Math.random() * h * 0.8;
|
|
183
209
|
var burstH = 4 + Math.random() * 20;
|
|
184
210
|
if (noiseCanvas.width !== w) {
|
|
@@ -221,8 +247,7 @@ export function initHeroCanvas(prefersReducedMotion) {
|
|
|
221
247
|
buildEdge(img);
|
|
222
248
|
wrap.classList.add('ready');
|
|
223
249
|
if (prefersReducedMotion) {
|
|
224
|
-
|
|
225
|
-
if (staticCtx) staticCtx.drawImage(baseCanvas, 0, 0);
|
|
250
|
+
ctx.drawImage(baseCanvas, 0, 0);
|
|
226
251
|
return;
|
|
227
252
|
}
|
|
228
253
|
heroRaf = requestAnimationFrame(heroRender);
|
|
@@ -230,10 +255,13 @@ export function initHeroCanvas(prefersReducedMotion) {
|
|
|
230
255
|
img.src = new URL(src, window.location.href).href;
|
|
231
256
|
|
|
232
257
|
window.addEventListener('resize', function() {
|
|
233
|
-
if (canvas.img)
|
|
258
|
+
if (!canvas.img) return;
|
|
259
|
+
if (resizeTimer) clearTimeout(resizeTimer);
|
|
260
|
+
resizeTimer = setTimeout(function() {
|
|
261
|
+
resizeTimer = 0;
|
|
234
262
|
sizeCanvas();
|
|
235
263
|
buildEdge(canvas.img);
|
|
236
|
-
}
|
|
264
|
+
}, 180);
|
|
237
265
|
}, { passive: true });
|
|
238
266
|
|
|
239
267
|
function onHeroVisibilityChange() {
|
|
@@ -248,6 +276,7 @@ export function initHeroCanvas(prefersReducedMotion) {
|
|
|
248
276
|
|
|
249
277
|
document.addEventListener('visibilitychange', onHeroVisibilityChange);
|
|
250
278
|
window.addEventListener('beforeunload', function() {
|
|
279
|
+
if (resizeTimer) clearTimeout(resizeTimer);
|
|
251
280
|
cancelAnimationFrame(heroRaf);
|
|
252
281
|
}, { once: true });
|
|
253
282
|
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/* About background layer: terminal backdrop and scan/flicker ambience. */
|
|
2
|
+
/* ── terminal background ── */
|
|
3
|
+
.hacker-bg {
|
|
4
|
+
position: fixed;
|
|
5
|
+
inset: 0;
|
|
6
|
+
z-index: 0;
|
|
7
|
+
overflow: hidden;
|
|
8
|
+
pointer-events: none;
|
|
9
|
+
}
|
|
10
|
+
.hacker-bg-canvas {
|
|
11
|
+
position: absolute;
|
|
12
|
+
inset: 0;
|
|
13
|
+
width: 100%;
|
|
14
|
+
height: 100%;
|
|
15
|
+
}
|
|
16
|
+
.hacker-scanlines {
|
|
17
|
+
position: absolute;
|
|
18
|
+
inset: 0;
|
|
19
|
+
/* 浅色扫描线:在深色背景上可见,全屏 CRT 感 */
|
|
20
|
+
background: repeating-linear-gradient(
|
|
21
|
+
180deg,
|
|
22
|
+
transparent 0px,
|
|
23
|
+
transparent 2px,
|
|
24
|
+
rgba(255, 255, 255, 0.03) 2px,
|
|
25
|
+
rgba(255, 255, 255, 0.03) 3px
|
|
26
|
+
);
|
|
27
|
+
pointer-events: none;
|
|
28
|
+
}
|
|
29
|
+
.hacker-vignette {
|
|
30
|
+
position: absolute;
|
|
31
|
+
inset: 0;
|
|
32
|
+
background: radial-gradient(
|
|
33
|
+
ellipse at center,
|
|
34
|
+
transparent 50%,
|
|
35
|
+
rgba(0, 0, 0, 0.5) 80%,
|
|
36
|
+
rgba(0, 0, 0, 0.85) 100%
|
|
37
|
+
);
|
|
38
|
+
pointer-events: none;
|
|
39
|
+
}
|
|
40
|
+
.hacker-flicker {
|
|
41
|
+
position: absolute;
|
|
42
|
+
inset: 0;
|
|
43
|
+
background: transparent;
|
|
44
|
+
animation: hacker-flicker-anim 0.08s infinite;
|
|
45
|
+
pointer-events: none;
|
|
46
|
+
}
|
|
47
|
+
@keyframes hacker-flicker-anim {
|
|
48
|
+
0% { background: rgba(255, 255, 255, 0.012); }
|
|
49
|
+
50% { background: transparent; }
|
|
50
|
+
100% { background: rgba(255, 255, 255, 0.005); }
|
|
51
|
+
}
|
|
52
|
+
.hacker-glow {
|
|
53
|
+
position: absolute;
|
|
54
|
+
inset: 0;
|
|
55
|
+
box-shadow: inset 0 0 120px rgba(255, 255, 255, 0.03);
|
|
56
|
+
pointer-events: none;
|
|
57
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/* About base layer: hacker-page chrome variables and shell baselines. */
|
|
2
|
+
body.hacker-page {
|
|
3
|
+
background: #000 !important;
|
|
4
|
+
background-image: none !important;
|
|
5
|
+
color: rgba(255, 255, 255, 0.88);
|
|
6
|
+
min-height: 100vh;
|
|
7
|
+
scrollbar-width: thin;
|
|
8
|
+
scrollbar-color: rgba(255, 255, 255, 0.25) transparent;
|
|
9
|
+
/* header: Anonymous 黑白灰 + 黄点缀 */
|
|
10
|
+
--chrome-bg: rgba(0, 0, 0, 0.42);
|
|
11
|
+
--chrome-border: rgba(255, 255, 255, 0.2);
|
|
12
|
+
--chrome-link: rgba(255, 255, 255, 0.9);
|
|
13
|
+
--chrome-link-hover: rgba(0, 255, 100, 0.95);
|
|
14
|
+
--chrome-active: rgba(255, 255, 255, 0.5);
|
|
15
|
+
--chrome-text-muted: rgba(255, 255, 255, 0.5);
|
|
16
|
+
}
|
|
17
|
+
body.hacker-page::-webkit-scrollbar { width: 6px; }
|
|
18
|
+
body.hacker-page::-webkit-scrollbar-track { background: transparent; }
|
|
19
|
+
body.hacker-page::-webkit-scrollbar-thumb {
|
|
20
|
+
background: rgba(255, 255, 255, 0.22);
|
|
21
|
+
border-radius: 3px;
|
|
22
|
+
}
|
|
23
|
+
/* fixed header + content offset (mirrors ai-page in global.css) */
|
|
24
|
+
body.hacker-page header {
|
|
25
|
+
position: fixed;
|
|
26
|
+
top: 0;
|
|
27
|
+
left: 0;
|
|
28
|
+
right: 0;
|
|
29
|
+
z-index: 100;
|
|
30
|
+
backdrop-filter: blur(3px);
|
|
31
|
+
-webkit-backdrop-filter: blur(3px);
|
|
32
|
+
}
|
|
33
|
+
body.hacker-page .hacker-content {
|
|
34
|
+
padding-top: calc(3em + 56px);
|
|
35
|
+
}
|
|
36
|
+
body.hacker-page .hacker-content,
|
|
37
|
+
body.hacker-page footer {
|
|
38
|
+
position: relative;
|
|
39
|
+
z-index: 10;
|
|
40
|
+
}
|
|
41
|
+
/* footer: Anonymous 灰白 */
|
|
42
|
+
body.hacker-page footer {
|
|
43
|
+
--chrome-bg: rgba(0, 0, 0, 0.85);
|
|
44
|
+
--chrome-border: rgba(255, 255, 255, 0.15);
|
|
45
|
+
border-top-color: rgba(255, 255, 255, 0.15) !important;
|
|
46
|
+
color: rgba(255, 255, 255, 0.55);
|
|
47
|
+
}
|
|
48
|
+
body.hacker-page footer a {
|
|
49
|
+
color: rgba(255, 255, 255, 0.7) !important;
|
|
50
|
+
}
|
|
51
|
+
body.hacker-page footer a:hover {
|
|
52
|
+
color: rgba(0, 255, 100, 0.9) !important;
|
|
53
|
+
}
|
|
54
|
+
@media (max-width: 720px) {
|
|
55
|
+
body.hacker-page .hacker-content {
|
|
56
|
+
padding-top: calc(1em + 56px);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/* About keyboard layer: virtual keyboard and helper interaction visuals. */
|
|
2
|
+
/* Help: 虚拟键盘 */
|
|
3
|
+
.hacker-vkeyboard {
|
|
4
|
+
display: flex;
|
|
5
|
+
flex-direction: column;
|
|
6
|
+
gap: 4px;
|
|
7
|
+
font-size: 0.7rem;
|
|
8
|
+
}
|
|
9
|
+
.hacker-vkeyboard-row {
|
|
10
|
+
display: flex;
|
|
11
|
+
justify-content: center;
|
|
12
|
+
gap: 3px;
|
|
13
|
+
}
|
|
14
|
+
.hacker-vkey {
|
|
15
|
+
min-width: 24px;
|
|
16
|
+
height: 28px;
|
|
17
|
+
padding: 0 6px;
|
|
18
|
+
display: inline-flex;
|
|
19
|
+
align-items: center;
|
|
20
|
+
justify-content: center;
|
|
21
|
+
background: rgba(255, 255, 255, 0.08);
|
|
22
|
+
border: 1px solid rgba(255, 255, 255, 0.2);
|
|
23
|
+
border-radius: 4px;
|
|
24
|
+
color: rgba(255, 255, 255, 0.9);
|
|
25
|
+
font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
|
|
26
|
+
cursor: pointer;
|
|
27
|
+
transition: all 0.1s ease;
|
|
28
|
+
user-select: none;
|
|
29
|
+
}
|
|
30
|
+
.hacker-vkey:hover {
|
|
31
|
+
background: rgba(255, 255, 255, 0.15);
|
|
32
|
+
border-color: rgba(255, 255, 255, 0.35);
|
|
33
|
+
}
|
|
34
|
+
.hacker-vkey.highlight {
|
|
35
|
+
background: rgba(0, 255, 100, 0.35);
|
|
36
|
+
border-color: rgba(0, 255, 100, 0.7);
|
|
37
|
+
box-shadow: 0 0 12px rgba(0, 255, 100, 0.3);
|
|
38
|
+
}
|
|
39
|
+
.hacker-vkey.wide { min-width: 36px; }
|
|
40
|
+
.hacker-vkey.backspace { min-width: 72px; }
|
|
41
|
+
.hacker-vkey.space { min-width: 120px; }
|
|
42
|
+
.hacker-vkey.acc { background: rgba(255, 140, 0, 0.25); border-color: rgba(255, 140, 0, 0.5); }
|
|
43
|
+
.hacker-vkey.acc:hover { background: rgba(255, 140, 0, 0.35); }
|
|
44
|
+
.hacker-vkeyboard-wrap {
|
|
45
|
+
display: flex;
|
|
46
|
+
flex-wrap: wrap;
|
|
47
|
+
gap: 2rem;
|
|
48
|
+
align-items: stretch;
|
|
49
|
+
}
|
|
50
|
+
.hacker-vkeyboard-main {
|
|
51
|
+
flex: 1;
|
|
52
|
+
min-width: 0;
|
|
53
|
+
}
|
|
54
|
+
.hacker-vkeyboard-side {
|
|
55
|
+
display: flex;
|
|
56
|
+
flex-direction: column;
|
|
57
|
+
gap: 6px;
|
|
58
|
+
flex-shrink: 0;
|
|
59
|
+
min-width: 140px;
|
|
60
|
+
}
|
|
61
|
+
.hacker-vkeyboard-side-block {
|
|
62
|
+
display: flex;
|
|
63
|
+
flex-direction: column;
|
|
64
|
+
gap: 4px;
|
|
65
|
+
margin-bottom: 4px;
|
|
66
|
+
}
|
|
67
|
+
.hacker-vkeyboard-side-row {
|
|
68
|
+
display: flex;
|
|
69
|
+
gap: 3px;
|
|
70
|
+
}
|
|
71
|
+
.hacker-vkeyboard-side-block .hacker-vkey {
|
|
72
|
+
flex: 1;
|
|
73
|
+
min-width: 0;
|
|
74
|
+
}
|
|
75
|
+
.hacker-vkey.nav-home { background: rgba(66, 133, 244, 0.3); border-color: rgba(66, 133, 244, 0.5); }
|
|
76
|
+
.hacker-vkey.nav-home:hover { background: rgba(66, 133, 244, 0.4); }
|
|
77
|
+
.hacker-vkey.nav-end { background: rgba(234, 67, 53, 0.25); border-color: rgba(234, 67, 53, 0.5); }
|
|
78
|
+
.hacker-vkey.nav-end:hover { background: rgba(234, 67, 53, 0.35); }
|
|
79
|
+
.hacker-vkeyboard-arrows-wrap {
|
|
80
|
+
display: flex;
|
|
81
|
+
flex-direction: column;
|
|
82
|
+
align-items: center;
|
|
83
|
+
margin-top: 6px;
|
|
84
|
+
}
|
|
85
|
+
.hacker-vkeyboard-arrows {
|
|
86
|
+
display: grid;
|
|
87
|
+
grid-template: ". u ." 1fr "l d r" 1fr / 1fr 1fr 1fr;
|
|
88
|
+
gap: 2px;
|
|
89
|
+
height: 56px;
|
|
90
|
+
}
|
|
91
|
+
.hacker-vkeyboard-arrows .arr-u { grid-area: u; }
|
|
92
|
+
.hacker-vkeyboard-arrows .arr-l { grid-area: l; }
|
|
93
|
+
.hacker-vkeyboard-arrows .arr-r { grid-area: r; }
|
|
94
|
+
.hacker-vkeyboard-arrows .arr-d { grid-area: d; }
|
|
95
|
+
.hacker-vkeyboard-arrows .hacker-vkey { width: 50px; height: 22px; font-size: 0.65rem; padding: 0; }
|
|
96
|
+
.hacker-vkeyboard-stats {
|
|
97
|
+
width: 100%;
|
|
98
|
+
margin-top: 0.2rem;
|
|
99
|
+
font-size: 0.75em;
|
|
100
|
+
color: rgba(255, 255, 255, 0.6);
|
|
101
|
+
}
|
|
102
|
+
.hacker-vkeyboard-stats-label {
|
|
103
|
+
font-size: 0.65rem;
|
|
104
|
+
color: rgba(255, 255, 255, 0.5);
|
|
105
|
+
letter-spacing: 0.1em;
|
|
106
|
+
}
|
|
107
|
+
.hacker-modal-body.hacker-modal-keyboard {
|
|
108
|
+
overflow: visible;
|
|
109
|
+
}
|
|
110
|
+
@media (max-width: 900px) {
|
|
111
|
+
.hacker-sidebar { display: none; }
|
|
112
|
+
}
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
/* About modal layer: dialog shells and script explorer surfaces. */
|
|
2
|
+
/* ── 弹窗 (Anonymous 窗口) ── */
|
|
3
|
+
.hacker-modal-overlay {
|
|
4
|
+
position: fixed;
|
|
5
|
+
inset: 0;
|
|
6
|
+
z-index: 200;
|
|
7
|
+
background: rgba(0, 0, 0, 0.7);
|
|
8
|
+
backdrop-filter: blur(4px);
|
|
9
|
+
display: none;
|
|
10
|
+
align-items: center;
|
|
11
|
+
justify-content: center;
|
|
12
|
+
padding: 2rem;
|
|
13
|
+
}
|
|
14
|
+
.hacker-modal-overlay.open {
|
|
15
|
+
display: flex;
|
|
16
|
+
}
|
|
17
|
+
.hacker-modal {
|
|
18
|
+
width: min(420px, 100%);
|
|
19
|
+
max-height: 80vh;
|
|
20
|
+
}
|
|
21
|
+
.hacker-modal.hacker-modal-wide {
|
|
22
|
+
width: min(900px, calc(100vw - 2rem));
|
|
23
|
+
overflow: visible;
|
|
24
|
+
}
|
|
25
|
+
.hacker-modal-header {
|
|
26
|
+
display: flex;
|
|
27
|
+
align-items: center;
|
|
28
|
+
gap: 0.5rem;
|
|
29
|
+
padding: 0.5rem 0.9rem;
|
|
30
|
+
background: #fff;
|
|
31
|
+
border-bottom: 1px solid rgba(0, 0, 0, 0.15);
|
|
32
|
+
}
|
|
33
|
+
.hacker-modal-dots {
|
|
34
|
+
display: flex;
|
|
35
|
+
gap: 6px;
|
|
36
|
+
}
|
|
37
|
+
.hacker-modal-dots span {
|
|
38
|
+
width: 10px;
|
|
39
|
+
height: 10px;
|
|
40
|
+
border-radius: 50%;
|
|
41
|
+
}
|
|
42
|
+
.hacker-modal-dots span:nth-child(1) { background: #ff5f57; }
|
|
43
|
+
.hacker-modal-dots span:nth-child(2) { background: #febc2e; }
|
|
44
|
+
.hacker-modal-dots span:nth-child(3) { background: #28c840; }
|
|
45
|
+
.hacker-modal-title {
|
|
46
|
+
font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
|
|
47
|
+
font-size: 0.75em;
|
|
48
|
+
color: #000;
|
|
49
|
+
font-weight: 600;
|
|
50
|
+
letter-spacing: 0.1em;
|
|
51
|
+
text-transform: uppercase;
|
|
52
|
+
}
|
|
53
|
+
.hacker-modal-close {
|
|
54
|
+
margin-left: auto;
|
|
55
|
+
width: 66px;
|
|
56
|
+
height: 66px;
|
|
57
|
+
border: none;
|
|
58
|
+
background: rgba(0, 0, 0, 0.06);
|
|
59
|
+
color: #000;
|
|
60
|
+
display: flex;
|
|
61
|
+
align-items: center;
|
|
62
|
+
justify-content: center;
|
|
63
|
+
cursor: pointer;
|
|
64
|
+
opacity: 0.9;
|
|
65
|
+
border-radius: 10px;
|
|
66
|
+
}
|
|
67
|
+
.hacker-modal-close .hacker-modal-close-icon {
|
|
68
|
+
flex-shrink: 0;
|
|
69
|
+
}
|
|
70
|
+
.hacker-modal-close:hover {
|
|
71
|
+
opacity: 1;
|
|
72
|
+
background: rgba(0, 0, 0, 0.14);
|
|
73
|
+
}
|
|
74
|
+
.hacker-modal-body {
|
|
75
|
+
padding: 1rem 0.9rem 1.2rem;
|
|
76
|
+
color: rgba(255, 255, 255, 0.88);
|
|
77
|
+
font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
|
|
78
|
+
font-size: 0.82rem;
|
|
79
|
+
line-height: 1.6;
|
|
80
|
+
max-height: 60vh;
|
|
81
|
+
overflow-y: auto;
|
|
82
|
+
}
|
|
83
|
+
.hacker-modal-body pre {
|
|
84
|
+
margin: 0;
|
|
85
|
+
white-space: pre-wrap;
|
|
86
|
+
word-break: break-word;
|
|
87
|
+
}
|
|
88
|
+
/* DL Data: Downloading 进度条 (Anonymous 风格) */
|
|
89
|
+
.hacker-modal-body.hacker-modal-download .modal-subtitle {
|
|
90
|
+
font-size: 0.9em;
|
|
91
|
+
color: rgba(255, 255, 255, 0.7);
|
|
92
|
+
margin-bottom: 1rem;
|
|
93
|
+
}
|
|
94
|
+
.hacker-modal-progress {
|
|
95
|
+
display: flex;
|
|
96
|
+
gap: 2px;
|
|
97
|
+
flex-wrap: wrap;
|
|
98
|
+
margin-top: 0.5rem;
|
|
99
|
+
}
|
|
100
|
+
.hacker-modal-progress span {
|
|
101
|
+
width: 10px;
|
|
102
|
+
height: 12px;
|
|
103
|
+
background: rgba(255, 255, 255, 0.2);
|
|
104
|
+
transition: background 0.12s ease;
|
|
105
|
+
}
|
|
106
|
+
.hacker-modal-progress span.filled {
|
|
107
|
+
background: rgba(255, 255, 255, 0.6);
|
|
108
|
+
}
|
|
109
|
+
/* All Scripts: 文件夹网格 */
|
|
110
|
+
.hacker-modal-scripts {
|
|
111
|
+
padding: 0.5rem 0;
|
|
112
|
+
}
|
|
113
|
+
.hacker-modal-scripts-path {
|
|
114
|
+
font-size: 0.9em;
|
|
115
|
+
color: rgba(255, 255, 255, 0.9);
|
|
116
|
+
letter-spacing: 0.05em;
|
|
117
|
+
margin-bottom: 1rem;
|
|
118
|
+
border-bottom: 1px solid rgba(255, 255, 255, 0.15);
|
|
119
|
+
padding-bottom: 0.5rem;
|
|
120
|
+
}
|
|
121
|
+
.hacker-modal-scripts-grid {
|
|
122
|
+
display: grid;
|
|
123
|
+
grid-template-columns: repeat(5, 1fr);
|
|
124
|
+
gap: 1rem;
|
|
125
|
+
}
|
|
126
|
+
.hacker-script-folder {
|
|
127
|
+
display: flex;
|
|
128
|
+
flex-direction: column;
|
|
129
|
+
align-items: center;
|
|
130
|
+
gap: 0.5rem;
|
|
131
|
+
padding: 0.6rem 0.4rem;
|
|
132
|
+
background: rgba(255, 255, 255, 0.05);
|
|
133
|
+
border: 1px solid rgba(255, 255, 255, 0.12);
|
|
134
|
+
border-radius: 6px;
|
|
135
|
+
color: rgba(255, 255, 255, 0.9);
|
|
136
|
+
text-decoration: none;
|
|
137
|
+
transition: all 0.15s ease;
|
|
138
|
+
}
|
|
139
|
+
.hacker-script-folder:hover {
|
|
140
|
+
background: rgba(255, 255, 255, 0.12);
|
|
141
|
+
border-color: rgba(0, 255, 100, 0.4);
|
|
142
|
+
box-shadow: 0 0 12px rgba(0, 255, 100, 0.15);
|
|
143
|
+
}
|
|
144
|
+
.hacker-script-folder-icon {
|
|
145
|
+
width: 32px;
|
|
146
|
+
height: 28px;
|
|
147
|
+
color: rgba(255, 255, 255, 0.7);
|
|
148
|
+
}
|
|
149
|
+
.hacker-script-folder-label {
|
|
150
|
+
font-size: 0.72rem;
|
|
151
|
+
text-align: center;
|
|
152
|
+
word-break: break-word;
|
|
153
|
+
line-height: 1.3;
|
|
154
|
+
}
|
|
155
|
+
@media (max-width: 600px) {
|
|
156
|
+
.hacker-modal-scripts-grid {
|
|
157
|
+
grid-template-columns: repeat(3, 1fr);
|
|
158
|
+
}
|
|
159
|
+
}
|