block-proxy 0.1.11 → 0.1.13
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/.agents/skills/commit/skill.md +40 -0
- package/.claude/settings.local.json +29 -1
- package/.claude/skills/build-client/skill.md +24 -0
- package/.claude/skills/commit/skill.md +34 -26
- package/.claude/skills/release-client/skill.md +68 -0
- package/CLAUDE.md +109 -47
- package/Dockerfile +1 -1
- package/README.md +69 -60
- package/build/asset-manifest.json +6 -6
- package/build/index.html +1 -1
- package/build/static/css/main.3f317ce6.css +2 -0
- package/build/static/css/main.3f317ce6.css.map +1 -0
- package/build/static/js/{main.2247fb80.js → main.68f66be0.js} +3 -3
- package/build/static/js/main.68f66be0.js.map +1 -0
- package/client/app.py +312 -0
- package/client/build.sh +84 -0
- package/client/config.py +49 -0
- package/client/config_window.py +155 -0
- package/client/icons/app.icns +0 -0
- package/client/icons/app_example.png +0 -0
- package/client/icons/app_icon.png +0 -0
- package/client/icons/backup/app_example.png +0 -0
- package/client/icons/backup/christmas-sock_dark.png +0 -0
- package/client/icons/backup/christmas-sock_light.png +0 -0
- package/client/icons/backup/socks_on_G.png +0 -0
- package/client/icons/backup/socks_on_M.png +0 -0
- package/client/icons/christmas-sock_dark.png +0 -0
- package/client/icons/christmas-sock_light.png +0 -0
- package/client/icons/christmas-sock_light_bar.png +0 -0
- package/client/icons/socks_on_G.png +0 -0
- package/client/icons/socks_on_G_bar.png +0 -0
- package/client/icons/socks_on_M.png +0 -0
- package/client/icons/socks_on_M_bar.png +0 -0
- package/client/main.py +28 -0
- package/client/proxy_core.py +475 -0
- package/client/requirements.txt +3 -0
- package/client/scripts/download_xray.sh +30 -0
- package/client/setup.py +30 -0
- package/client/system_proxy.py +94 -0
- package/client/tests/__init__.py +0 -0
- package/client/tests/test_config.py +72 -0
- package/client/tests/test_system_proxy.py +69 -0
- package/client/watch-icons.js +31 -0
- package/config.json +82 -5
- package/docs/superpowers/plans/2026-05-27-blockproxyclient.md +1274 -0
- package/docs/superpowers/specs/2026-05-27-blockproxyclient-design.md +264 -0
- package/package.json +11 -5
- package/proxy/proxy.js +70 -18
- package/server/express.js +17 -1
- package/skills-lock.json +11 -0
- package/socks5/server.js +2 -2
- package/src/App.css +596 -276
- package/src/App.js +25 -22
- package/src/index.css +3 -4
- package/test/lib/mock-server.js +133 -0
- package/test/proxy-tests.js +708 -0
- package/test/run.js +330 -0
- package/build/static/css/main.8bfa3d5f.css +0 -2
- package/build/static/css/main.8bfa3d5f.css.map +0 -1
- package/build/static/js/main.2247fb80.js.map +0 -1
- package/hack-of-anyproxy/lib/requestHandler.js +0 -1060
- /package/build/static/js/{main.2247fb80.js.LICENSE.txt → main.68f66be0.js.LICENSE.txt} +0 -0
package/README.md
CHANGED
|
@@ -7,19 +7,16 @@
|
|
|
7
7
|
|
|
8
8
|
> **Block-Proxy**
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
Socks5/http 代理工具,支持 MITM 和二次开发
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
用在家庭网关,限制小朋友上网用。特性:
|
|
13
13
|
|
|
14
|
-
- HTTP 代理
|
|
15
|
-
-
|
|
16
|
-
-
|
|
17
|
-
-
|
|
18
|
-
- 指定拦截Mac地址
|
|
19
|
-
- 设定日期和时间段
|
|
20
|
-
- 顺便过滤广告
|
|
14
|
+
- HTTP 代理 + Socks5 over TLS 代理
|
|
15
|
+
- 域名拦截、url 正则、Mac 地址拦截
|
|
16
|
+
- 设定日期和时间段、顺便过滤广告
|
|
17
|
+
- 提供服务端和客户端
|
|
21
18
|
|
|
22
|
-
### 1
|
|
19
|
+
### 1)服务端使用方法
|
|
23
20
|
|
|
24
21
|
#### ① 方式一:快速部署
|
|
25
22
|
|
|
@@ -45,46 +42,13 @@ block-proxy -c rule.js
|
|
|
45
42
|
|
|
46
43
|
#### ② 方式二,Docker 部署(推荐)
|
|
47
44
|
|
|
48
|
-
1.
|
|
49
|
-
- Arm 架构 → <a href="http://yui.cool:7001/public/downloads/block-proxy/arm/block-proxy.tar" target=_blank>block-proxy-arm.tar</a>
|
|
50
|
-
- X86 架构 → <a href="http://yui.cool:7001/public/downloads/block-proxy/x86/block-proxy-x86.tar" target=_blank>block-proxy-x86.tar</a>
|
|
51
|
-
2. 导入:`docker load < block-proxy.tar`
|
|
52
|
-
3. 启动:参照下文 Docker 部署
|
|
45
|
+
1. 拉取镜像(自动匹配架构):
|
|
53
46
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
2. 客户端配置:http 代理直接在 iphone wifi 详情里手动配置,socks5 代理只支持 socks5 over TLS,用小火箭配置。配置信息参照[配置面板](http://localhost:8004)
|
|
58
|
-
|
|
59
|
-
### 3)开发和调试
|
|
60
|
-
|
|
61
|
-
代码 clone 下来后执行`pnpm i`,执行 `npm run dev` 运行本地服务。默认开启 5 个端口:
|
|
62
|
-
|
|
63
|
-
|端口 |说明 |可否关闭|
|
|
64
|
-
|:----:|:------:|:------:|
|
|
65
|
-
|3000 |调试端口(仅开发调试配置面板用)| 生产环境不启用|
|
|
66
|
-
|8001 |HTTP 代理端口 | 不可禁用 |
|
|
67
|
-
|8002 |Socks5(Over TLS)代理端口 | 可禁用 |
|
|
68
|
-
|8003 |AnyProxy 监控页面| 可禁用 |
|
|
69
|
-
|8004 |后台配置页端口 | 可禁用 |
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
### 4)Docker 构建说明
|
|
73
|
-
|
|
74
|
-
准备工作,构建 docker 包,先启动本地 Docker:
|
|
75
|
-
|
|
76
|
-
- 开发调试:`npm run dev`,开发调试用3000端口
|
|
77
|
-
- 生产启动:`npm run start`,生产环境使用
|
|
78
|
-
- 只启动代理:`npm run proxy`,不启动配置后台,只启动代理
|
|
79
|
-
- 后台构建:`npm run build`
|
|
80
|
-
- 本地打包:`npm run docker:build`
|
|
81
|
-
- 打arm包:`npm run docker:build_arm`
|
|
82
|
-
- 导出tar包到本地:`docker save -o block-proxy.tar block-proxy`
|
|
83
|
-
- 安装包到openwrt:`docker load < block-proxy.tar`
|
|
84
|
-
|
|
85
|
-
> 要是打包 docker 空间不够就执行 `docker system prune -a --volumes`
|
|
47
|
+
```
|
|
48
|
+
docker pull crpi-x1zji86f6jpcd7t1.cn-hangzhou.personal.cr.aliyuncs.com/lijing00333/block-proxy:latest
|
|
49
|
+
```
|
|
86
50
|
|
|
87
|
-
|
|
51
|
+
2. 启动:
|
|
88
52
|
|
|
89
53
|
```
|
|
90
54
|
docker run --init -d --restart=unless-stopped \
|
|
@@ -96,7 +60,7 @@ docker run --init -d --restart=unless-stopped \
|
|
|
96
60
|
--cpus="5" \
|
|
97
61
|
--memory 400m \
|
|
98
62
|
-v "$(pwd)/":/app/config \
|
|
99
|
-
--name block-proxy block-proxy
|
|
63
|
+
--name block-proxy crpi-x1zji86f6jpcd7t1.cn-hangzhou.personal.cr.aliyuncs.com/lijing00333/block-proxy:latest
|
|
100
64
|
```
|
|
101
65
|
|
|
102
66
|
其中挂载目录 `$(pws)/` 下的 `rule.js` 是需要额外挂载的配置文件,可留空。
|
|
@@ -110,16 +74,56 @@ docker run --init -d --restart=unless-stopped \
|
|
|
110
74
|
```
|
|
111
75
|
docker run --init -d --restart=unless-stopped --user=root \
|
|
112
76
|
-v "$(pwd)/":/app/config \
|
|
113
|
-
-e TZ=Asia/Shanghai -p 8001:8001 -p 8002:8002
|
|
114
|
-
--name block-proxy block-proxy
|
|
77
|
+
-e TZ=Asia/Shanghai -p 8001:8001 -p 8002:8002 \
|
|
78
|
+
--name block-proxy crpi-x1zji86f6jpcd7t1.cn-hangzhou.personal.cr.aliyuncs.com/lijing00333/block-proxy:latest
|
|
115
79
|
```
|
|
116
80
|
|
|
81
|
+
### 2)服务侧端口配置
|
|
82
|
+
|
|
83
|
+
1. 服务端配置:配置面板 <http://server-ip:8003>,关闭、启用配置面板:<http://server-ip:8001>
|
|
84
|
+
2. 客户端配置:http 代理直接在 iphone wifi 详情里手动配置,socks5 代理只支持 socks5 over TLS,用小火箭配置。配置信息参照[配置面板](http://localhost:8003)
|
|
117
85
|
|
|
118
|
-
###
|
|
86
|
+
### 3)服务侧代码的开发和调试
|
|
87
|
+
|
|
88
|
+
代码 clone 下来后执行`pnpm i`,执行 `npm run dev` 运行本地服务。默认开启 5 个端口:
|
|
89
|
+
|
|
90
|
+
|端口 |说明 |可否关闭|
|
|
91
|
+
|:----:|:------:|:------:|
|
|
92
|
+
|3000 |调试端口(仅开发调试配置面板用)| 生产环境不启用|
|
|
93
|
+
|8001 |HTTP 代理端口 | 不可禁用 |
|
|
94
|
+
|8002 |Socks5(Over TLS)代理端口 | 可禁用 |
|
|
95
|
+
|8003 |后台配置页端口 | 可禁用 |
|
|
96
|
+
|8004 |~~已废弃~~ | 原后台配置页,已迁移至 8003 |
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
### 4)Block-Proxy 的 Docker 构建说明
|
|
100
|
+
|
|
101
|
+
准备工作,构建 docker 包,先启动本地 Docker:
|
|
102
|
+
|
|
103
|
+
- 开发调试:`npm run dev`,开发调试用3000端口
|
|
104
|
+
- 生产启动:`npm run start`,生产环境使用
|
|
105
|
+
- 只启动代理:`npm run proxy`,不启动配置后台,只启动代理
|
|
106
|
+
- 后台构建:`npm run build`
|
|
107
|
+
- 本地构建 amd64:`npm run docker:build`
|
|
108
|
+
- 本地构建 arm64:`npm run docker:build:arm`
|
|
109
|
+
- 推送 amd64 + arm64 双架构到 ACR:`npm run docker:push`
|
|
110
|
+
- 仅推送 amd64:`npm run docker:push:amd64`
|
|
111
|
+
- 仅推送 arm64:`npm run docker:push:arm64`
|
|
112
|
+
|
|
113
|
+
> 首次使用 `docker:push` 前需要先 ACR 登录:
|
|
114
|
+
> ```
|
|
115
|
+
> docker login --username=hi50078584@aliyun.com crpi-x1zji86f6jpcd7t1.cn-hangzhou.personal.cr.aliyuncs.com
|
|
116
|
+
> ```
|
|
117
|
+
> 要是打包 docker 空间不够就执行 `docker system prune -a --volumes`
|
|
118
|
+
|
|
119
|
+
拷贝 tar 到 openwrt 后启动容器:参照上文 Docker部署。
|
|
120
|
+
|
|
121
|
+
### 5)客户端配置说明
|
|
119
122
|
|
|
120
123
|
#### ① 代理端口
|
|
121
124
|
|
|
122
|
-
|
|
125
|
+
- 8001:HTTP 代理
|
|
126
|
+
- 8002:socks5 over TLS
|
|
123
127
|
|
|
124
128
|
⚠️ Socks5 代理不支持对 Mac 地址的定向拦截,Mac 地址的拦截只对局域网内的 HTTP 代理绑定生效。建议局域网绑定 http 代理,公网绑定 Socks5 代理。
|
|
125
129
|
|
|
@@ -127,7 +131,7 @@ docker run --init -d --restart=unless-stopped --user=root \
|
|
|
127
131
|
|
|
128
132
|
#### ② 后台配置
|
|
129
133
|
|
|
130
|
-
访问路径:`http://proxy-ip:
|
|
134
|
+
访问路径:`http://proxy-ip:8003`
|
|
131
135
|
|
|
132
136
|
路由表间隔两小时刷新一次。如果新加入网的设备没生效,刷新一下路由表。添加限制条件后,点击重启代理按钮。
|
|
133
137
|
|
|
@@ -136,10 +140,10 @@ docker run --init -d --restart=unless-stopped --user=root \
|
|
|
136
140
|
|
|
137
141
|
#### ③ 设备配置
|
|
138
142
|
|
|
139
|
-
1.
|
|
140
|
-
2.
|
|
143
|
+
1. 证书设置:进入后台配置,扫码安装证书,在手机设置中安装该证书,同时配置完全信任:设置→通用→关于本机→证书信任设置→打开对AnyProxy的完全信任
|
|
144
|
+
2. 代理设置:iPhone/iPad 为例:设置 → 无线局域网 → 点击当前网络 → HTTP代理/配置代理,设置服务器和端口。
|
|
141
145
|
|
|
142
|
-
|
|
146
|
+
如果要通过 mac 地址拦截小朋友上网,小朋友的设备里把 Mac 固定下来:
|
|
143
147
|
|
|
144
148
|
<img width="350" alt="image" src="https://github.com/user-attachments/assets/f9bfab89-7194-4a72-b1ae-5cca27911bc9" />
|
|
145
149
|
|
|
@@ -155,14 +159,14 @@ ip6tables -I forwarding_rule -m mac --mac-source D2:9E:8D:1B:F1:4E -j REJECT
|
|
|
155
159
|
然后重启防火墙
|
|
156
160
|
|
|
157
161
|
|
|
158
|
-
### 6
|
|
162
|
+
### 6)关于 MITM
|
|
159
163
|
|
|
160
164
|
#### 应用条件:
|
|
161
165
|
|
|
162
166
|
1. MITM 基于 AnyProxy 的规则实现,客户端设备必须要安装 AnyProxy 的证书。
|
|
163
167
|
2. 服务需要根据 ip 反查 mac 地址,需要代理服务工作在对子网有扫描权限的节点,最好是部署在 openwrt 网关,可以`arp -a`看下是否可以扫描完全。
|
|
164
168
|
3. 服务会自动更新路由表,每 2 个小时更新一次,对于新入网的设备,最好在后台手动刷新并重启代理,以免拦截规则不能立即生效。
|
|
165
|
-
4. 所有规则都在 HTTP 代理中生效,Socks5 是指向 AnyProxy
|
|
169
|
+
4. 所有规则都在 HTTP 代理中生效,Socks5 on tls 是指向 AnyProxy 的反向代理,内网 Mac 地址的拦截只对直接绑定 HTTP 代理的情况生效。
|
|
166
170
|
|
|
167
171
|
#### Youtube 去广告
|
|
168
172
|
|
|
@@ -172,7 +176,6 @@ ip6tables -I forwarding_rule -m mac --mac-source D2:9E:8D:1B:F1:4E -j REJECT
|
|
|
172
176
|
- *youtube.com*:`^https?:\/\/s\.youtube\.com\/api\/stats\/qoe\?adcontext`
|
|
173
177
|
- *youtube.com*:`^https?:\/\/(www|s)\.youtube\.com\/api\/stats\/ads`
|
|
174
178
|
- *googlevideo.com*:`^https?:\/\/[\w-]+\.googlevideo\.com\/(?!(dclk_video_ads|videoplayback\?)).+&oad`
|
|
175
|
-
- <del>*youtubei.googleapis.com*:`\/youtubei\/v1\/notification_registration\/get_settings`</del>
|
|
176
179
|
|
|
177
180
|
另外两条规则在这里:<https://github.com/jayli/block-proxy/blob/main/proxy/mitm/rule.js>(手工添加上面四条规则就够了)
|
|
178
181
|
|
|
@@ -199,6 +202,12 @@ done!
|
|
|
199
202
|
>
|
|
200
203
|
><img width="300" alt="image" src="https://github.com/user-attachments/assets/0f46d6b4-00b1-44aa-9be7-fa23a09bb199" />
|
|
201
204
|
|
|
205
|
+
### 7)客户端软件
|
|
206
|
+
|
|
207
|
+
提供了客户端桌面端连接代理工具 SocksClient.app,支持 MacOS(M系列)。
|
|
208
|
+
|
|
209
|
+
下载地址:[GitHub Release](https://github.com/jayli/block-proxy/releases/latest)
|
|
210
|
+
|
|
202
211
|
### License
|
|
203
212
|
|
|
204
213
|
MIT
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"files": {
|
|
3
|
-
"main.css": "/static/css/main.
|
|
4
|
-
"main.js": "/static/js/main.
|
|
3
|
+
"main.css": "/static/css/main.3f317ce6.css",
|
|
4
|
+
"main.js": "/static/js/main.68f66be0.js",
|
|
5
5
|
"static/js/835.f7452062.chunk.js": "/static/js/835.f7452062.chunk.js",
|
|
6
6
|
"index.html": "/index.html",
|
|
7
|
-
"main.
|
|
8
|
-
"main.
|
|
7
|
+
"main.3f317ce6.css.map": "/static/css/main.3f317ce6.css.map",
|
|
8
|
+
"main.68f66be0.js.map": "/static/js/main.68f66be0.js.map",
|
|
9
9
|
"835.f7452062.chunk.js.map": "/static/js/835.f7452062.chunk.js.map"
|
|
10
10
|
},
|
|
11
11
|
"entrypoints": [
|
|
12
|
-
"static/css/main.
|
|
13
|
-
"static/js/main.
|
|
12
|
+
"static/css/main.3f317ce6.css",
|
|
13
|
+
"static/js/main.68f66be0.js"
|
|
14
14
|
]
|
|
15
15
|
}
|
package/build/index.html
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="icon" href="/favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><meta name="description" content="Web site created using create-react-app"/><link rel="apple-touch-icon" href="/logo192.png"/><link rel="manifest" href="/manifest.json"/><title>React App</title><script defer="defer" src="/static/js/main.
|
|
1
|
+
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="icon" href="/favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><meta name="description" content="Web site created using create-react-app"/><link rel="apple-touch-icon" href="/logo192.png"/><link rel="manifest" href="/manifest.json"/><title>React App</title><script defer="defer" src="/static/js/main.68f66be0.js"></script><link href="/static/css/main.3f317ce6.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
body{background:#f8fafc}code{font-family:source-code-pro,Menlo,Monaco,Consolas,Courier New,monospace}:root{--primary:#4f46e5;--primary-hover:#4338ca;--primary-light:#eef2ff;--success:#059669;--success-hover:#047857;--danger:#dc2626;--danger-hover:#b91c1c;--warning:#d97706;--warning-hover:#b45309;--info:#0284c7;--info-hover:#0369a1;--gray-50:#f9fafb;--gray-100:#f3f4f6;--gray-200:#e5e7eb;--gray-300:#d1d5db;--gray-400:#9ca3af;--gray-500:#6b7280;--gray-600:#4b5563;--gray-700:#374151;--gray-800:#1f2937;--gray-900:#111827;--radius:8px;--radius-sm:6px;--radius-xs:4px;--shadow-sm:0 1px 2px #0000000d;--shadow:0 1px 3px #0000001a,0 1px 2px #0000000f;--shadow-md:0 4px 6px -1px #0000001a,0 2px 4px -2px #0000001a;--shadow-lg:0 10px 15px -3px #0000001a,0 4px 6px -4px #0000001a;--transition:150ms cubic-bezier(0.4,0,0.2,1)}*{box-sizing:border-box}body{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif;margin:0}.App{background:linear-gradient(135deg,#f0f4ff,#f8fafc 30%,#f0fdf4 70%,#fefce8);min-height:100vh;padding:24px 16px 48px}.config-container{margin:0 auto;max-width:960px;position:relative}.config-container h1{color:#1f2937;color:var(--gray-800);font-size:26px;font-weight:700;letter-spacing:-.02em;margin:0 0 28px;text-align:center}.config-section{background:#fff;border:1px solid #f3f4f6;border:1px solid var(--gray-100);border-radius:12px;box-shadow:0 1px 3px #0000001a,0 1px 2px #0000000f;box-shadow:var(--shadow);margin-bottom:20px;padding:24px 28px;transition:box-shadow .15s cubic-bezier(.4,0,.2,1);transition:box-shadow var(--transition)}.config-section:hover{box-shadow:0 4px 6px -1px #0000001a,0 2px 4px -2px #0000001a;box-shadow:var(--shadow-md)}.config-section h2{align-items:center;border-bottom:2px solid #f3f4f6;border-bottom:2px solid var(--gray-100);color:#1f2937;color:var(--gray-800);display:flex;font-size:16px;font-weight:600;gap:8px;margin:0 0 18px;padding-bottom:12px}.config-section h2:before{background:#4f46e5;background:var(--primary);border-radius:2px;content:"";display:inline-block;height:18px;width:4px}.config-section h3{color:#374151;color:var(--gray-700);font-size:15px;font-weight:600;margin:0 0 12px}.server-info p{color:#4b5563;color:var(--gray-600);font-size:14px;margin:4px 0}.server-info strong{color:#1f2937;color:var(--gray-800)}.ip-list{grid-gap:8px;display:grid;gap:8px;grid-template-columns:repeat(auto-fill,minmax(240px,1fr));list-style:none;margin:12px 0 0;padding:0}.ip-item{align-items:center;background:#f9fafb;background:var(--gray-50);border:1px solid #f3f4f6;border:1px solid var(--gray-100);border-radius:6px;border-radius:var(--radius-sm);display:flex;font-size:13px;gap:8px;padding:8px 12px}.interface-name{color:#374151;color:var(--gray-700);font-weight:600;white-space:nowrap}.ip-address{background:#eef2ff;background:var(--primary-light);border-radius:4px;border-radius:var(--radius-xs);color:#4f46e5;color:var(--primary);font-family:SF Mono,Fira Code,JetBrains Mono,Courier New,monospace}.docker-info,.ip-address{font-size:12px;font-weight:500;padding:2px 8px}.docker-info{background:#e0f2fe;border-radius:10px;color:#0284c7;color:var(--info);display:inline-block;margin-left:6px}.host-ip-info{border-top:1px solid #e5e7eb;border-top:1px solid var(--gray-200);margin-top:12px;padding-top:12px}.host-ip-info p{color:#4b5563;color:var(--gray-600);font-size:13px}.host-input{align-items:flex-end;display:flex;flex-wrap:wrap;gap:10px;margin-bottom:16px}.host-input input[type=text]{background:#fff;border:1.5px solid #d1d5db;border:1.5px solid var(--gray-300);border-radius:6px;border-radius:var(--radius-sm);flex:1 1;font-size:14px;min-width:180px;padding:10px 14px;transition:border-color .15s cubic-bezier(.4,0,.2,1),box-shadow .15s cubic-bezier(.4,0,.2,1);transition:border-color var(--transition),box-shadow var(--transition)}.host-input input[type=text]:focus{border-color:#4f46e5;border-color:var(--primary);box-shadow:0 0 0 3px #4f46e51a;outline:none}.host-input input[type=text]::placeholder{color:#9ca3af;color:var(--gray-400)}.time-inputs{align-items:center;display:flex;flex-wrap:wrap;gap:10px}.time-inputs label{align-items:center;color:#4b5563;color:var(--gray-600);display:flex;font-size:13px;gap:4px}.time-inputs label span{white-space:nowrap}.host-input button,.time-inputs button{background:#4f46e5;background:var(--primary);border:none;border-radius:6px;border-radius:var(--radius-sm);color:#fff;cursor:pointer;font-size:14px;font-weight:500;padding:10px 20px;transition:background .15s cubic-bezier(.4,0,.2,1),transform 50ms;transition:background var(--transition),transform 50ms;white-space:nowrap}.host-input button:hover{background:#4338ca;background:var(--primary-hover)}.host-input button:active{transform:scale(.97)}hr.simple-line{background:#e5e7eb;background:var(--gray-200);border:none;height:1px;margin:0 0 12px}.host-list{list-style:none;margin:0;padding:0}.host-item{align-items:center;display:flex;gap:12px;justify-content:space-between;padding:14px 16px;transition:background .15s cubic-bezier(.4,0,.2,1);transition:background var(--transition)}.host-item,.host-item:first-child{border-radius:6px;border-radius:var(--radius-sm)}.host-item:first-child{background:#f9fafb;background:var(--gray-50);color:#6b7280;color:var(--gray-500);font-size:13px;font-weight:600;letter-spacing:.05em;margin-bottom:4px;padding:10px 16px;text-transform:uppercase}.host-item:not(:first-child){border-bottom:1px solid #f3f4f6;border-bottom:1px solid var(--gray-100)}.host-item:not(:first-child):hover{background:#f9fafb;background:var(--gray-50)}.host-item:last-child{border-bottom:none}.host-info{align-items:center;display:flex;flex-grow:1;flex-wrap:wrap;gap:12px}span.host-text{flex:1 1;font-size:14px;line-height:1.5;min-width:140px}span.host-text strong{color:#1f2937;color:var(--gray-800);font-weight:600}input[type=time]{background:#fff;border:1.5px solid #d1d5db;border:1.5px solid var(--gray-300);border-radius:4px;border-radius:var(--radius-xs);font-family:inherit;font-size:13px;padding:6px 8px;transition:border-color .15s cubic-bezier(.4,0,.2,1),box-shadow .15s cubic-bezier(.4,0,.2,1);transition:border-color var(--transition),box-shadow var(--transition)}input[type=time]:focus{border-color:#4f46e5;border-color:var(--primary);box-shadow:0 0 0 3px #4f46e51a;outline:none}.time-controls{align-items:center;display:flex;gap:6px}.time-controls label{align-items:center;color:#6b7280;color:var(--gray-500);display:flex;font-size:13px}.remove-btn{align-items:center;background:#fff;border:1.5px solid #e5e7eb;border:1.5px solid var(--gray-200);border-radius:4px;border-radius:var(--radius-xs);color:#9ca3af;color:var(--gray-400);cursor:pointer;display:flex;font-size:14px;font-weight:600;height:30px;justify-content:center;min-width:30px;padding:0;transition:all .15s cubic-bezier(.4,0,.2,1);transition:all var(--transition);width:30px}.remove-btn:hover{background:#dc2626;background:var(--danger);border-color:#dc2626;border-color:var(--danger);color:#fff}.setting-row{align-items:center;display:flex;gap:16px;margin-bottom:14px}.setting-row label{color:#374151;color:var(--gray-700);flex-shrink:0;font-size:14px;font-weight:500;text-align:right;width:200px}.setting-row input[type=number],.setting-row input[type=text],.setting-row select{background:#fff;border:1.5px solid #d1d5db;border:1.5px solid var(--gray-300);border-radius:6px;border-radius:var(--radius-sm);flex:1 1;font-family:inherit;font-size:14px;padding:10px 14px;transition:border-color .15s cubic-bezier(.4,0,.2,1),box-shadow .15s cubic-bezier(.4,0,.2,1);transition:border-color var(--transition),box-shadow var(--transition)}.setting-row input[type=number]:focus,.setting-row input[type=text]:focus,.setting-row select:focus{border-color:#4f46e5;border-color:var(--primary);box-shadow:0 0 0 3px #4f46e51a;outline:none}.setting-row select{-webkit-appearance:none;appearance:none;background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%236b7280' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");background-position:right 12px center;background-repeat:no-repeat;cursor:pointer;padding-right:36px}.setting-row.full-width{flex-wrap:wrap}.setting-row.full-width label{width:200px}.setting-row.full-width input{flex:1 1;min-width:240px}.help-text{color:#9ca3af;color:var(--gray-400);font-size:12px;line-height:1.5;margin-left:216px;margin-top:-4px;width:100%}.actions{border-top:1px solid #f3f4f6;border-top:1px solid var(--gray-100);display:flex;gap:12px;margin-top:20px;padding-top:20px}.refresh-btn,.restart-btn,.save-btn{border:none;border-radius:6px;border-radius:var(--radius-sm);cursor:pointer;flex:1 1;font-size:14px;font-weight:600;letter-spacing:.01em;padding:12px 20px;transition:all .15s cubic-bezier(.4,0,.2,1);transition:all var(--transition)}.save-btn{background:#059669;background:var(--success);color:#fff}.save-btn:hover:not(:disabled){background:#047857;background:var(--success-hover);box-shadow:0 2px 8px #0596694d}.restart-btn{background:#d97706;background:var(--warning);color:#fff}.restart-btn:hover:not(:disabled){background:#b45309;background:var(--warning-hover);box-shadow:0 2px 8px #d977064d}.refresh-btn:disabled,.restart-btn:disabled,.save-btn:disabled{background:#d1d5db;background:var(--gray-300);box-shadow:none;color:#6b7280;color:var(--gray-500);cursor:not-allowed}.refresh-btn:active:not(:disabled),.refresh-table-btn:active:not(:disabled),.restart-btn:active:not(:disabled),.save-btn:active:not(:disabled){transform:scale(.98)}.refresh-btn{background:#0284c7;background:var(--info);color:#fff}.refresh-btn:hover:not(:disabled){background:#0369a1;background:var(--info-hover);box-shadow:0 2px 8px #0284c74d}.refresh-table-btn{margin-top:12px}.config-section p{color:#4b5563;color:var(--gray-600);font-size:14px;line-height:1.7;margin:6px 0}.config-section p b{color:#1f2937;color:var(--gray-800);font-weight:600}.config-section a{color:#4f46e5;color:var(--primary);font-weight:500;text-decoration:none;transition:color .15s cubic-bezier(.4,0,.2,1);transition:color var(--transition)}.config-section a:hover{color:#4338ca;color:var(--primary-hover);text-decoration:underline}#qrcode{background:#fff;border:1px solid #e5e7eb;border:1px solid var(--gray-200);border-radius:6px;border-radius:var(--radius-sm);margin-top:8px;padding:8px}button{font-family:inherit}.config-section>button{background:#fff;border:1.5px solid #d1d5db;border:1.5px solid var(--gray-300);border-radius:6px;border-radius:var(--radius-sm);color:#374151;color:var(--gray-700);cursor:pointer;font-size:14px;font-weight:500;padding:10px 20px;transition:all .15s cubic-bezier(.4,0,.2,1);transition:all var(--transition)}.config-section>button:hover:not(:disabled){background:#f9fafb;background:var(--gray-50);border-color:#9ca3af;border-color:var(--gray-400)}.config-section>button:disabled{cursor:not-allowed;opacity:.5}.weekday-controls{gap:2px}.weekday-btn,.weekday-controls{align-items:center;display:flex}.weekday-btn{background:#f3f4f6;background:var(--gray-100);border:1.5px solid #0000;border-radius:4px;border-radius:var(--radius-xs);color:#6b7280;color:var(--gray-500);cursor:pointer;font-size:12px;font-weight:500;height:30px;justify-content:center;padding:0;transition:all .15s cubic-bezier(.4,0,.2,1);transition:all var(--transition);width:30px}.weekday-btn:hover{background:#e5e7eb;background:var(--gray-200);color:#374151;color:var(--gray-700)}.weekday-btn.active{background:#4f46e5;background:var(--primary);border-color:#4f46e5;border-color:var(--primary);box-shadow:0 1px 3px #4f46e54d;color:#fff}.weekday-btn:focus{box-shadow:0 0 0 2px #4f46e54d;outline:none}.mac-input{align-items:center;display:flex;gap:8px}.mac-input input[type=text]{border:1.5px solid #d1d5db;border:1.5px solid var(--gray-300);border-radius:4px;border-radius:var(--radius-xs);font-family:SF Mono,Fira Code,JetBrains Mono,Courier New,monospace;font-size:12px;padding:6px 10px;transition:border-color .15s cubic-bezier(.4,0,.2,1),box-shadow .15s cubic-bezier(.4,0,.2,1);transition:border-color var(--transition),box-shadow var(--transition);width:130px}.mac-input input[type=text]:focus{border-color:#4f46e5;border-color:var(--primary);box-shadow:0 0 0 3px #4f46e51a;outline:none}.mac-input input[type=text]::placeholder{color:#9ca3af;color:var(--gray-400);font-family:inherit}.table-right-blank{min-width:30px}.title-mac-input{font-size:13px;min-width:138px;text-align:center}.title-time-controls{font-size:13px;min-width:190px;text-align:center}.title-weedkey-controls{font-size:13px;min-width:120px}.toast{align-items:center;animation:toastSlideIn .35s cubic-bezier(.16,1,.3,1);-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);border-radius:10px;box-shadow:0 10px 25px #00000026;color:#fff;display:flex;font-size:14px;font-weight:500;gap:12px;min-width:260px;padding:14px 20px;position:fixed;right:24px;top:24px;z-index:1000}@keyframes toastSlideIn{0%{opacity:0;transform:translateX(120%)}to{opacity:1;transform:translateX(0)}}.toast.success{background:#059669;background:var(--success);box-shadow:0 8px 20px #0596694d}.toast.error{background:#dc2626;background:var(--danger);box-shadow:0 8px 20px #dc26264d}.toast.info{background:#0284c7;background:var(--info);box-shadow:0 8px 20px #0284c74d}.toast-close{align-items:center;background:#fff3;border:none;border-radius:50%;color:#fff;cursor:pointer;display:flex;flex-shrink:0;font-size:18px;font-weight:400;height:24px;justify-content:center;margin-left:auto;padding:0;transition:background .15s cubic-bezier(.4,0,.2,1);transition:background var(--transition);width:24px}.toast-close:hover{background:#ffffff59}.config-section .ip-list{display:flex;flex-direction:column;gap:4px}.config-section .ip-item{background:#f9fafb;background:var(--gray-50)}@media (max-width:768px){.App{padding:12px 8px 32px}.config-section{padding:18px 16px}.host-info{gap:8px}.host-info,.setting-row{align-items:flex-start;flex-direction:column}.setting-row{gap:6px}.setting-row label{text-align:left;width:100%}.setting-row.full-width label{width:100%}.help-text{margin-left:0}.actions,.host-item{flex-direction:column}.host-item{align-items:flex-start;gap:8px}.remove-btn{align-self:flex-end}.time-controls{flex-wrap:wrap}.host-input{flex-direction:column}.host-input input[type=text]{min-width:100%}.ip-list{grid-template-columns:1fr}}@media (max-width:480px){.config-container h1{font-size:20px}.config-section h2{font-size:14px}.weekday-btn{font-size:11px;height:26px;width:26px}}
|
|
2
|
+
/*# sourceMappingURL=main.3f317ce6.css.map*/
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"static/css/main.3f317ce6.css","mappings":"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","sources":["index.css","App.css"],"sourcesContent":["body {\n margin: 0;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',\n 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n background: #f8fafc;\n}\n\ncode {\n font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', monospace;\n}\n","/* ===== 基础变量与全局 ===== */\n:root {\n --primary: #4f46e5;\n --primary-hover: #4338ca;\n --primary-light: #eef2ff;\n --success: #059669;\n --success-hover: #047857;\n --danger: #dc2626;\n --danger-hover: #b91c1c;\n --warning: #d97706;\n --warning-hover: #b45309;\n --info: #0284c7;\n --info-hover: #0369a1;\n --gray-50: #f9fafb;\n --gray-100: #f3f4f6;\n --gray-200: #e5e7eb;\n --gray-300: #d1d5db;\n --gray-400: #9ca3af;\n --gray-500: #6b7280;\n --gray-600: #4b5563;\n --gray-700: #374151;\n --gray-800: #1f2937;\n --gray-900: #111827;\n --radius: 8px;\n --radius-sm: 6px;\n --radius-xs: 4px;\n --shadow-sm: 0 1px 2px rgba(0,0,0,0.05);\n --shadow: 0 1px 3px rgba(0,0,0,0.1), 0 1px 2px rgba(0,0,0,0.06);\n --shadow-md: 0 4px 6px -1px rgba(0,0,0,0.1), 0 2px 4px -2px rgba(0,0,0,0.1);\n --shadow-lg: 0 10px 15px -3px rgba(0,0,0,0.1), 0 4px 6px -4px rgba(0,0,0,0.1);\n --transition: 150ms cubic-bezier(0.4, 0, 0.2, 1);\n}\n\n* {\n box-sizing: border-box;\n}\n\nbody {\n margin: 0;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',\n 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n}\n\n/* ===== 布局 ===== */\n.App {\n min-height: 100vh;\n background: linear-gradient(135deg, #f0f4ff 0%, #f8fafc 30%, #f0fdf4 70%, #fefce8 100%);\n padding: 24px 16px 48px;\n}\n\n.config-container {\n max-width: 960px;\n margin: 0 auto;\n position: relative;\n}\n\n.config-container h1 {\n text-align: center;\n font-size: 26px;\n font-weight: 700;\n color: var(--gray-800);\n margin: 0 0 28px;\n letter-spacing: -0.02em;\n}\n\n/* ===== Section 卡片 ===== */\n.config-section {\n background: white;\n border-radius: 12px;\n padding: 24px 28px;\n margin-bottom: 20px;\n box-shadow: var(--shadow);\n border: 1px solid var(--gray-100);\n transition: box-shadow var(--transition);\n}\n\n.config-section:hover {\n box-shadow: var(--shadow-md);\n}\n\n.config-section h2 {\n margin: 0 0 18px;\n font-size: 16px;\n font-weight: 600;\n color: var(--gray-800);\n padding-bottom: 12px;\n border-bottom: 2px solid var(--gray-100);\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.config-section h2::before {\n content: '';\n display: inline-block;\n width: 4px;\n height: 18px;\n background: var(--primary);\n border-radius: 2px;\n}\n\n.config-section h3 {\n margin: 0 0 12px;\n font-size: 15px;\n font-weight: 600;\n color: var(--gray-700);\n}\n\n/* ===== 服务器信息 ===== */\n.server-info p {\n margin: 4px 0;\n color: var(--gray-600);\n font-size: 14px;\n}\n\n.server-info strong {\n color: var(--gray-800);\n}\n\n.ip-list {\n list-style: none;\n padding: 0;\n margin: 12px 0 0;\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));\n gap: 8px;\n}\n\n.ip-item {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 12px;\n background: var(--gray-50);\n border-radius: var(--radius-sm);\n font-size: 13px;\n border: 1px solid var(--gray-100);\n}\n\n.interface-name {\n font-weight: 600;\n color: var(--gray-700);\n white-space: nowrap;\n}\n\n.ip-address {\n font-family: 'SF Mono', 'Fira Code', 'JetBrains Mono', 'Courier New', monospace;\n font-size: 12px;\n background: var(--primary-light);\n color: var(--primary);\n padding: 2px 8px;\n border-radius: var(--radius-xs);\n font-weight: 500;\n}\n\n.docker-info {\n display: inline-block;\n font-size: 12px;\n font-weight: 500;\n color: var(--info);\n background: #e0f2fe;\n padding: 2px 8px;\n border-radius: 10px;\n margin-left: 6px;\n}\n\n.host-ip-info {\n margin-top: 12px;\n padding-top: 12px;\n border-top: 1px solid var(--gray-200);\n}\n\n.host-ip-info p {\n font-size: 13px;\n color: var(--gray-600);\n}\n\n/* ===== 拦截主机列表 ===== */\n.host-input {\n display: flex;\n flex-wrap: wrap;\n gap: 10px;\n margin-bottom: 16px;\n align-items: flex-end;\n}\n\n.host-input input[type=\"text\"] {\n flex: 1;\n min-width: 180px;\n padding: 10px 14px;\n border: 1.5px solid var(--gray-300);\n border-radius: var(--radius-sm);\n font-size: 14px;\n transition: border-color var(--transition), box-shadow var(--transition);\n background: white;\n}\n\n.host-input input[type=\"text\"]:focus {\n outline: none;\n border-color: var(--primary);\n box-shadow: 0 0 0 3px rgba(79, 70, 229, 0.1);\n}\n\n.host-input input[type=\"text\"]::placeholder {\n color: var(--gray-400);\n}\n\n.time-inputs {\n display: flex;\n gap: 10px;\n align-items: center;\n flex-wrap: wrap;\n}\n\n.time-inputs label {\n display: flex;\n align-items: center;\n gap: 4px;\n font-size: 13px;\n color: var(--gray-600);\n}\n\n.time-inputs label span {\n white-space: nowrap;\n}\n\n.host-input button,\n.time-inputs button {\n padding: 10px 20px;\n background: var(--primary);\n color: white;\n border: none;\n border-radius: var(--radius-sm);\n cursor: pointer;\n font-size: 14px;\n font-weight: 500;\n transition: background var(--transition), transform 50ms;\n white-space: nowrap;\n}\n\n.host-input button:hover {\n background: var(--primary-hover);\n}\n\n.host-input button:active {\n transform: scale(0.97);\n}\n\nhr.simple-line {\n height: 1px;\n border: none;\n background: var(--gray-200);\n margin: 0 0 12px;\n}\n\n/* ===== 域名列表表头 ===== */\n.host-list {\n list-style: none;\n padding: 0;\n margin: 0;\n}\n\n.host-item {\n display: flex;\n justify-content: space-between;\n align-items: center;\n gap: 12px;\n padding: 14px 16px;\n border-radius: var(--radius-sm);\n transition: background var(--transition);\n}\n\n.host-item:first-child {\n background: var(--gray-50);\n border-radius: var(--radius-sm);\n margin-bottom: 4px;\n padding: 10px 16px;\n font-weight: 600;\n font-size: 13px;\n color: var(--gray-500);\n text-transform: uppercase;\n letter-spacing: 0.05em;\n}\n\n.host-item:not(:first-child) {\n border-bottom: 1px solid var(--gray-100);\n}\n\n.host-item:not(:first-child):hover {\n background: var(--gray-50);\n}\n\n.host-item:last-child {\n border-bottom: none;\n}\n\n.host-info {\n display: flex;\n flex-grow: 1;\n align-items: center;\n gap: 12px;\n flex-wrap: wrap;\n}\n\nspan.host-text {\n font-size: 14px;\n flex: 1;\n min-width: 140px;\n line-height: 1.5;\n}\n\nspan.host-text strong {\n color: var(--gray-800);\n font-weight: 600;\n}\n\n/* ===== 时间控件 ===== */\ninput[type=\"time\"] {\n padding: 6px 8px;\n border: 1.5px solid var(--gray-300);\n border-radius: var(--radius-xs);\n font-size: 13px;\n background: white;\n transition: border-color var(--transition), box-shadow var(--transition);\n font-family: inherit;\n}\n\ninput[type=\"time\"]:focus {\n outline: none;\n border-color: var(--primary);\n box-shadow: 0 0 0 3px rgba(79, 70, 229, 0.1);\n}\n\n.time-controls {\n display: flex;\n gap: 6px;\n align-items: center;\n}\n\n.time-controls label {\n display: flex;\n align-items: center;\n font-size: 13px;\n color: var(--gray-500);\n}\n\n/* ===== 删除按钮 ===== */\n.remove-btn {\n background: white;\n color: var(--gray-400);\n border: 1.5px solid var(--gray-200);\n width: 30px;\n height: 30px;\n min-width: 30px;\n cursor: pointer;\n border-radius: var(--radius-xs);\n font-size: 14px;\n font-weight: 600;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: all var(--transition);\n padding: 0;\n}\n\n.remove-btn:hover {\n background: var(--danger);\n color: white;\n border-color: var(--danger);\n}\n\n/* ===== 设置行 ===== */\n.setting-row {\n display: flex;\n align-items: center;\n margin-bottom: 14px;\n gap: 16px;\n}\n\n.setting-row label {\n width: 200px;\n text-align: right;\n font-weight: 500;\n color: var(--gray-700);\n flex-shrink: 0;\n font-size: 14px;\n}\n\n.setting-row input[type=\"text\"],\n.setting-row input[type=\"number\"],\n.setting-row select {\n flex: 1;\n padding: 10px 14px;\n border: 1.5px solid var(--gray-300);\n border-radius: var(--radius-sm);\n font-size: 14px;\n font-family: inherit;\n transition: border-color var(--transition), box-shadow var(--transition);\n background: white;\n}\n\n.setting-row input[type=\"text\"]:focus,\n.setting-row input[type=\"number\"]:focus,\n.setting-row select:focus {\n outline: none;\n border-color: var(--primary);\n box-shadow: 0 0 0 3px rgba(79, 70, 229, 0.1);\n}\n\n.setting-row select {\n cursor: pointer;\n appearance: none;\n background-image: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%236b7280' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E\");\n background-repeat: no-repeat;\n background-position: right 12px center;\n padding-right: 36px;\n}\n\n.setting-row.full-width {\n flex-wrap: wrap;\n}\n\n.setting-row.full-width label {\n width: 200px;\n}\n\n.setting-row.full-width input {\n flex: 1;\n min-width: 240px;\n}\n\n.help-text {\n width: 100%;\n margin-left: 216px;\n font-size: 12px;\n color: var(--gray-400);\n line-height: 1.5;\n margin-top: -4px;\n}\n\n/* ===== 操作按钮行 ===== */\n.actions {\n display: flex;\n gap: 12px;\n margin-top: 20px;\n padding-top: 20px;\n border-top: 1px solid var(--gray-100);\n}\n\n.save-btn,\n.restart-btn,\n.refresh-btn {\n flex: 1;\n padding: 12px 20px;\n border: none;\n border-radius: var(--radius-sm);\n cursor: pointer;\n font-size: 14px;\n font-weight: 600;\n transition: all var(--transition);\n letter-spacing: 0.01em;\n}\n\n.save-btn {\n background: var(--success);\n color: white;\n}\n\n.save-btn:hover:not(:disabled) {\n background: var(--success-hover);\n box-shadow: 0 2px 8px rgba(5, 150, 105, 0.3);\n}\n\n.restart-btn {\n background: var(--warning);\n color: white;\n}\n\n.restart-btn:hover:not(:disabled) {\n background: var(--warning-hover);\n box-shadow: 0 2px 8px rgba(217, 119, 6, 0.3);\n}\n\n.save-btn:disabled,\n.restart-btn:disabled,\n.refresh-btn:disabled {\n background: var(--gray-300);\n color: var(--gray-500);\n cursor: not-allowed;\n box-shadow: none;\n}\n\n.save-btn:active:not(:disabled),\n.restart-btn:active:not(:disabled),\n.refresh-btn:active:not(:disabled),\n.refresh-table-btn:active:not(:disabled) {\n transform: scale(0.98);\n}\n\n.refresh-btn {\n background: var(--info);\n color: white;\n}\n\n.refresh-btn:hover:not(:disabled) {\n background: var(--info-hover);\n box-shadow: 0 2px 8px rgba(2, 132, 199, 0.3);\n}\n\n.refresh-table-btn {\n margin-top: 12px;\n}\n\n/* ===== 代理设置信息区 ===== */\n.config-section p {\n margin: 6px 0;\n font-size: 14px;\n color: var(--gray-600);\n line-height: 1.7;\n}\n\n.config-section p b {\n color: var(--gray-800);\n font-weight: 600;\n}\n\n.config-section a {\n color: var(--primary);\n text-decoration: none;\n font-weight: 500;\n transition: color var(--transition);\n}\n\n.config-section a:hover {\n color: var(--primary-hover);\n text-decoration: underline;\n}\n\n#qrcode {\n margin-top: 8px;\n border-radius: var(--radius-sm);\n border: 1px solid var(--gray-200);\n padding: 8px;\n background: white;\n}\n\n/* ===== 通用按钮 ===== */\nbutton {\n font-family: inherit;\n}\n\n.config-section > button {\n padding: 10px 20px;\n background: white;\n color: var(--gray-700);\n border: 1.5px solid var(--gray-300);\n border-radius: var(--radius-sm);\n cursor: pointer;\n font-size: 14px;\n font-weight: 500;\n transition: all var(--transition);\n}\n\n.config-section > button:hover:not(:disabled) {\n background: var(--gray-50);\n border-color: var(--gray-400);\n}\n\n.config-section > button:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n/* ===== 星期几按钮 ===== */\n.weekday-controls {\n display: flex;\n gap: 2px;\n align-items: center;\n}\n\n.weekday-btn {\n width: 30px;\n height: 30px;\n padding: 0;\n background: var(--gray-100);\n color: var(--gray-500);\n font-size: 12px;\n font-weight: 500;\n border-radius: var(--radius-xs);\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n border: 1.5px solid transparent;\n transition: all var(--transition);\n}\n\n.weekday-btn:hover {\n background: var(--gray-200);\n color: var(--gray-700);\n}\n\n.weekday-btn.active {\n background: var(--primary);\n color: white;\n border-color: var(--primary);\n box-shadow: 0 1px 3px rgba(79, 70, 229, 0.3);\n}\n\n.weekday-btn:focus {\n outline: none;\n box-shadow: 0 0 0 2px rgba(79, 70, 229, 0.3);\n}\n\n/* ===== MAC 地址输入 ===== */\n.mac-input {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.mac-input input[type=\"text\"] {\n width: 130px;\n padding: 6px 10px;\n border: 1.5px solid var(--gray-300);\n border-radius: var(--radius-xs);\n font-size: 12px;\n font-family: 'SF Mono', 'Fira Code', 'JetBrains Mono', 'Courier New', monospace;\n transition: border-color var(--transition), box-shadow var(--transition);\n}\n\n.mac-input input[type=\"text\"]:focus {\n outline: none;\n border-color: var(--primary);\n box-shadow: 0 0 0 3px rgba(79, 70, 229, 0.1);\n}\n\n.mac-input input[type=\"text\"]::placeholder {\n color: var(--gray-400);\n font-family: inherit;\n}\n\n/* ===== 列表表头 ===== */\n.table-right-blank {\n min-width: 30px;\n}\n\n.title-mac-input {\n font-size: 13px;\n text-align: center;\n min-width: 138px;\n}\n\n.title-time-controls {\n font-size: 13px;\n text-align: center;\n min-width: 190px;\n}\n\n.title-weedkey-controls {\n font-size: 13px;\n min-width: 120px;\n}\n\n/* ===== Toast 通知 ===== */\n.toast {\n position: fixed;\n top: 24px;\n right: 24px;\n padding: 14px 20px;\n border-radius: 10px;\n color: white;\n font-weight: 500;\n font-size: 14px;\n box-shadow: 0 10px 25px rgba(0, 0, 0, 0.15);\n z-index: 1000;\n display: flex;\n align-items: center;\n gap: 12px;\n animation: toastSlideIn 0.35s cubic-bezier(0.16, 1, 0.3, 1);\n min-width: 260px;\n backdrop-filter: blur(8px);\n}\n\n@keyframes toastSlideIn {\n from {\n transform: translateX(120%);\n opacity: 0;\n }\n to {\n transform: translateX(0);\n opacity: 1;\n }\n}\n\n.toast.success {\n background: var(--success);\n box-shadow: 0 8px 20px rgba(5, 150, 105, 0.3);\n}\n\n.toast.error {\n background: var(--danger);\n box-shadow: 0 8px 20px rgba(220, 38, 38, 0.3);\n}\n\n.toast.info {\n background: var(--info);\n box-shadow: 0 8px 20px rgba(2, 132, 199, 0.3);\n}\n\n.toast-close {\n background: rgba(255,255,255,0.2);\n border: none;\n color: white;\n font-size: 18px;\n font-weight: 400;\n cursor: pointer;\n padding: 0;\n width: 24px;\n height: 24px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 50%;\n transition: background var(--transition);\n margin-left: auto;\n flex-shrink: 0;\n}\n\n.toast-close:hover {\n background: rgba(255,255,255,0.35);\n}\n\n/* ===== 路由表 ===== */\n.config-section .ip-list {\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n\n.config-section .ip-item {\n background: var(--gray-50);\n}\n\n/* ===== 响应式 ===== */\n@media (max-width: 768px) {\n .App {\n padding: 12px 8px 32px;\n }\n\n .config-section {\n padding: 18px 16px;\n }\n\n .host-info {\n flex-direction: column;\n align-items: flex-start;\n gap: 8px;\n }\n\n .setting-row {\n flex-direction: column;\n align-items: flex-start;\n gap: 6px;\n }\n\n .setting-row label {\n width: 100%;\n text-align: left;\n }\n\n .setting-row.full-width label {\n width: 100%;\n }\n\n .help-text {\n margin-left: 0;\n }\n\n .actions {\n flex-direction: column;\n }\n\n .host-item {\n flex-direction: column;\n align-items: flex-start;\n gap: 8px;\n }\n\n .remove-btn {\n align-self: flex-end;\n }\n\n .time-controls {\n flex-wrap: wrap;\n }\n\n .host-input {\n flex-direction: column;\n }\n\n .host-input input[type=\"text\"] {\n min-width: 100%;\n }\n\n .ip-list {\n grid-template-columns: 1fr;\n }\n}\n\n@media (max-width: 480px) {\n .config-container h1 {\n font-size: 20px;\n }\n\n .config-section h2 {\n font-size: 14px;\n }\n\n .weekday-btn {\n width: 26px;\n height: 26px;\n font-size: 11px;\n }\n}\n"],"names":[],"sourceRoot":""}
|