@wendongfly/myhi 1.3.191 → 1.3.192

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/dist/login.html CHANGED
@@ -1,163 +1,175 @@
1
- <!DOCTYPE html>
2
- <html lang="zh-CN">
3
- <head>
4
- <meta charset="UTF-8">
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, viewport-fit=cover">
6
- <meta name="theme-color" content="#0d1117">
7
- <meta name="apple-mobile-web-app-capable" content="yes">
8
- <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
9
- <link rel="apple-touch-icon" href="/icon.png">
10
- <link rel="manifest" href="/manifest.json">
11
- <title>myhi</title>
12
- <style>
13
- * { box-sizing: border-box; margin: 0; padding: 0; }
14
- html, body {
15
- height: 100%;
16
- background: #0d1117;
17
- color: #e6edf3;
18
- font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
19
- }
20
- body {
21
- display: flex;
22
- align-items: center;
23
- justify-content: center;
24
- padding: env(safe-area-inset-top) env(safe-area-inset-right)
25
- env(safe-area-inset-bottom) env(safe-area-inset-left);
26
- }
27
-
28
- .card {
29
- width: 100%;
30
- max-width: 340px;
31
- padding: 2.5rem 2rem;
32
- display: flex;
33
- flex-direction: column;
34
- align-items: center;
35
- gap: 1.5rem;
36
- }
37
-
38
- .logo {
39
- font-size: 2.2rem;
40
- font-weight: 800;
41
- letter-spacing: -1px;
42
- }
43
- .logo span { color: #7c3aed; }
44
-
45
- form {
46
- width: 100%;
47
- display: flex;
48
- flex-direction: column;
49
- gap: 0.85rem;
50
- }
51
-
52
- input[type=password] {
53
- width: 100%;
54
- background: #161b22;
55
- border: 1.5px solid #21262d;
56
- border-radius: 10px;
57
- padding: 0.85rem 1rem;
58
- color: #e6edf3;
59
- font-size: 1.1rem;
60
- text-align: center;
61
- letter-spacing: 0.2em;
62
- outline: none;
63
- transition: border-color 0.15s;
64
- -webkit-appearance: none;
65
- }
66
- input[type=password]:focus { border-color: #7c3aed; }
67
- input[type=password]::placeholder { letter-spacing: normal; font-size: 0.9rem; color: #4a5568; }
68
-
69
- button {
70
- width: 100%;
71
- background: #7c3aed;
72
- color: #fff;
73
- border: none;
74
- border-radius: 10px;
75
- padding: 0.85rem;
76
- font-size: 1rem;
77
- font-weight: 600;
78
- cursor: pointer;
79
- transition: background 0.15s;
80
- -webkit-appearance: none;
81
- }
82
- button:active { background: #6d28d9; }
83
- button:disabled { background: #4a5568; cursor: not-allowed; }
84
-
85
- .error {
86
- font-size: 0.82rem;
87
- color: #f85149;
88
- text-align: center;
89
- min-height: 1.2em;
90
- }
91
-
92
- .occupied {
93
- font-size: 0.9rem;
94
- color: #f0883e;
95
- text-align: center;
96
- line-height: 1.6;
97
- padding: 0.8rem;
98
- background: rgba(240, 136, 62, 0.1);
99
- border-radius: 10px;
100
- display: none;
101
- }
102
-
103
- .hint {
104
- font-size: 0.75rem;
105
- color: #4a5568;
106
- text-align: center;
107
- line-height: 1.5;
108
- }
109
- </style>
110
- </head>
111
- <body>
112
- <div class="card">
113
- <div class="logo">my<span>hi</span></div>
114
-
115
- <div class="occupied" id="occupied"></div>
116
-
117
- <form method="POST" action="/login">
118
- <input type="password" name="password" placeholder="输入密码" autofocus autocomplete="current-password">
119
- <div class="error" id="err"></div>
120
- <button type="submit" id="btn">进入</button>
121
- </form>
122
-
123
- <div class="hint">密码见服务器启动日志<br>或编辑 ~/.myhi/password</div>
124
- </div>
125
-
126
- <script>
127
- const errType = new URLSearchParams(location.search).get('error');
128
- const errUser = new URLSearchParams(location.search).get('user');
129
- if (errType === 'locked') {
130
- document.getElementById('err').textContent = '登录尝试过多,请 5 分钟后重试';
131
- } else if (errType === 'occupied' && errUser) {
132
- document.getElementById('err').textContent = errUser + ' 正在使用中,同账号可直接登录,不同账号请让对方退出';
133
- } else if (errType) {
134
- document.getElementById('err').textContent = '密码错误,请重试';
135
- }
136
- document.querySelector('input').focus();
137
-
138
- // 轮询登录状态(独占模式)
139
- const occupiedEl = document.getElementById('occupied');
140
- const btnEl = document.getElementById('btn');
141
- const inputEl = document.querySelector('input[type=password]');
142
-
143
- async function checkStatus() {
144
- try {
145
- const res = await fetch('/api/status');
146
- const data = await res.json();
147
- if (data.occupied) {
148
- occupiedEl.textContent = data.userName + ' 正在使用中' + (data.releasing ? '\n对方已离线,即将自动释放…' : '\n同账号可直接登录');
149
- occupiedEl.style.display = 'block';
150
- } else if (data.onlineUsers && data.onlineUsers.length > 0) {
151
- occupiedEl.textContent = '当前在线: ' + data.onlineUsers.join(', ');
152
- occupiedEl.style.display = 'block';
153
- } else {
154
- occupiedEl.style.display = 'none';
155
- }
156
- } catch {}
157
- }
158
-
159
- checkStatus();
160
- setInterval(checkStatus, 3000);
161
- </script>
162
- </body>
163
- </html>
1
+ <!DOCTYPE html>
2
+ <html lang="zh-CN">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, viewport-fit=cover">
6
+ <meta name="theme-color" content="#0d1117">
7
+ <meta name="apple-mobile-web-app-capable" content="yes">
8
+ <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
9
+ <link rel="apple-touch-icon" href="/icon.png">
10
+ <link rel="manifest" href="/manifest.json">
11
+ <title>myhi</title>
12
+ <script src="/theme.js"></script>
13
+ <script>
14
+ // 主题:浏览器选过的优先,否则用服务端默认(新装浅色、老机器深色),与其他页面一致
15
+ (function(){try{var t=localStorage.getItem('myhi_theme')||window.MYHI_DEFAULT_THEME||'dark';
16
+ if(t==='system') t=matchMedia('(prefers-color-scheme: light)').matches?'light':'dark';
17
+ if(t!=='dark') document.documentElement.setAttribute('data-theme',t);
18
+ var m=document.querySelector('meta[name="theme-color"]'); if(m) m.setAttribute('content',t==='light'?'#ffffff':t==='black'?'#000000':'#0d1117');
19
+ }catch(e){}})();
20
+ </script>
21
+ <style>
22
+ :root { --bg:#0d1117; --surface:#161b22; --border:#21262d; --text:#e6edf3; --muted:#4a5568; --accent:#7c3aed; --accent2:#6d28d9; }
23
+ :root[data-theme="light"] { --bg:#ffffff; --surface:#f6f8fa; --border:#d0d7de; --text:#1f2328; --muted:#8c959f; --accent:#8250df; --accent2:#6f42c1; }
24
+ :root[data-theme="black"] { --bg:#000000; --surface:#0a0a0a; --border:#262626; }
25
+ * { box-sizing: border-box; margin: 0; padding: 0; }
26
+ html, body {
27
+ height: 100%;
28
+ background: var(--bg);
29
+ color: var(--text);
30
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
31
+ }
32
+ body {
33
+ display: flex;
34
+ align-items: center;
35
+ justify-content: center;
36
+ padding: env(safe-area-inset-top) env(safe-area-inset-right)
37
+ env(safe-area-inset-bottom) env(safe-area-inset-left);
38
+ }
39
+
40
+ .card {
41
+ width: 100%;
42
+ max-width: 340px;
43
+ padding: 2.5rem 2rem;
44
+ display: flex;
45
+ flex-direction: column;
46
+ align-items: center;
47
+ gap: 1.5rem;
48
+ }
49
+
50
+ .logo {
51
+ font-size: 2.2rem;
52
+ font-weight: 800;
53
+ letter-spacing: -1px;
54
+ }
55
+ .logo span { color: var(--accent); }
56
+
57
+ form {
58
+ width: 100%;
59
+ display: flex;
60
+ flex-direction: column;
61
+ gap: 0.85rem;
62
+ }
63
+
64
+ input[type=password] {
65
+ width: 100%;
66
+ background: var(--surface);
67
+ border: 1.5px solid var(--border);
68
+ border-radius: 10px;
69
+ padding: 0.85rem 1rem;
70
+ color: var(--text);
71
+ font-size: 1.1rem;
72
+ text-align: center;
73
+ letter-spacing: 0.2em;
74
+ outline: none;
75
+ transition: border-color 0.15s;
76
+ -webkit-appearance: none;
77
+ }
78
+ input[type=password]:focus { border-color: var(--accent); }
79
+ input[type=password]::placeholder { letter-spacing: normal; font-size: 0.9rem; color: var(--muted); }
80
+
81
+ button {
82
+ width: 100%;
83
+ background: var(--accent);
84
+ color: #fff;
85
+ border: none;
86
+ border-radius: 10px;
87
+ padding: 0.85rem;
88
+ font-size: 1rem;
89
+ font-weight: 600;
90
+ cursor: pointer;
91
+ transition: background 0.15s;
92
+ -webkit-appearance: none;
93
+ }
94
+ button:active { background: var(--accent2); }
95
+ button:disabled { background: #4a5568; cursor: not-allowed; }
96
+
97
+ .error {
98
+ font-size: 0.82rem;
99
+ color: #f85149;
100
+ text-align: center;
101
+ min-height: 1.2em;
102
+ }
103
+
104
+ .occupied {
105
+ font-size: 0.9rem;
106
+ color: #f0883e;
107
+ text-align: center;
108
+ line-height: 1.6;
109
+ padding: 0.8rem;
110
+ background: rgba(240, 136, 62, 0.1);
111
+ border-radius: 10px;
112
+ display: none;
113
+ }
114
+
115
+ .hint {
116
+ font-size: 0.75rem;
117
+ color: var(--muted);
118
+ text-align: center;
119
+ line-height: 1.5;
120
+ }
121
+ </style>
122
+ </head>
123
+ <body>
124
+ <div class="card">
125
+ <div class="logo">my<span>hi</span></div>
126
+
127
+ <div class="occupied" id="occupied"></div>
128
+
129
+ <form method="POST" action="/login">
130
+ <input type="password" name="password" placeholder="输入密码" autofocus autocomplete="current-password">
131
+ <div class="error" id="err"></div>
132
+ <button type="submit" id="btn">进入</button>
133
+ </form>
134
+
135
+ <div class="hint">密码见服务器启动日志<br>或编辑 ~/.myhi/password</div>
136
+ </div>
137
+
138
+ <script>
139
+ const errType = new URLSearchParams(location.search).get('error');
140
+ const errUser = new URLSearchParams(location.search).get('user');
141
+ if (errType === 'locked') {
142
+ document.getElementById('err').textContent = '登录尝试过多,请 5 分钟后重试';
143
+ } else if (errType === 'occupied' && errUser) {
144
+ document.getElementById('err').textContent = errUser + ' 正在使用中,同账号可直接登录,不同账号请让对方退出';
145
+ } else if (errType) {
146
+ document.getElementById('err').textContent = '密码错误,请重试';
147
+ }
148
+ document.querySelector('input').focus();
149
+
150
+ // 轮询登录状态(独占模式)
151
+ const occupiedEl = document.getElementById('occupied');
152
+ const btnEl = document.getElementById('btn');
153
+ const inputEl = document.querySelector('input[type=password]');
154
+
155
+ async function checkStatus() {
156
+ try {
157
+ const res = await fetch('/api/status');
158
+ const data = await res.json();
159
+ if (data.occupied) {
160
+ occupiedEl.textContent = data.userName + ' 正在使用中' + (data.releasing ? '\n对方已离线,即将自动释放…' : '\n同账号可直接登录');
161
+ occupiedEl.style.display = 'block';
162
+ } else if (data.onlineUsers && data.onlineUsers.length > 0) {
163
+ occupiedEl.textContent = '当前在线: ' + data.onlineUsers.join(', ');
164
+ occupiedEl.style.display = 'block';
165
+ } else {
166
+ occupiedEl.style.display = 'none';
167
+ }
168
+ } catch {}
169
+ }
170
+
171
+ checkStatus();
172
+ setInterval(checkStatus, 3000);
173
+ </script>
174
+ </body>
175
+ </html>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wendongfly/myhi",
3
- "version": "1.3.191",
3
+ "version": "1.3.192",
4
4
  "description": "Web-based terminal sharing with chat UI — control your terminal from phone via LAN/Tailscale",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",