Skip to content

Commit 1386573

Browse files
committed
favicon + ui cleanup
1 parent 7b555e5 commit 1386573

4 files changed

Lines changed: 76 additions & 26 deletions

File tree

ser2tcp/html/app.js

Lines changed: 27 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -378,10 +378,12 @@ function renderPortCard(port, index) {
378378
};
379379
li.appendChild(urlEl);
380380
if (s.data !== false) {
381+
const tokenParam = s.token
382+
? '?token=' + encodeURIComponent(s.token) : '';
381383
const linksDiv = el('div', null, 'ws-links');
382-
linksDiv.innerHTML = '<a href="/xterm/' + s.endpoint
384+
linksDiv.innerHTML = '<a href="/xterm/' + s.endpoint + tokenParam
383385
+ '" class="detect-link" target="_blank" rel="noopener">Terminal</a>'
384-
+ '<a href="/raw/' + s.endpoint
386+
+ '<a href="/raw/' + s.endpoint + tokenParam
385387
+ '" class="detect-link" target="_blank" rel="noopener">Raw</a>';
386388
li.appendChild(linksDiv);
387389
}
@@ -877,6 +879,23 @@ function renderServerBox(srv, index, total) {
877879
wsToken.placeholder = '(use global auth)';
878880
wsToken.value = srv.token || '';
879881
wsRow2.appendChild(wsToken);
882+
const wsGenBtn = el('button', null, 'btn-icon');
883+
wsGenBtn.type = 'button';
884+
wsGenBtn.title = 'Generate token';
885+
wsGenBtn.innerHTML = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 2l-2 2m-7.61 7.61a5.5 5.5 0 1 1-7.778 7.778 5.5 5.5 0 0 1 7.777-7.777zm0 0L15.5 7.5m0 0l3 3L22 7l-3-3m-3.5 3.5L19 4"/></svg>';
886+
wsGenBtn.onclick = () => { wsToken.value = crypto.randomUUID(); };
887+
wsRow2.appendChild(wsGenBtn);
888+
const wsCopyBtn = el('button', null, 'btn-icon');
889+
wsCopyBtn.type = 'button';
890+
wsCopyBtn.title = 'Copy token';
891+
wsCopyBtn.innerHTML = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="9" y="9" width="13" height="13" rx="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg>';
892+
wsCopyBtn.onclick = () => {
893+
if (wsToken.value) navigator.clipboard.writeText(wsToken.value).then(() => {
894+
wsCopyBtn.style.color = 'var(--success)';
895+
setTimeout(() => { wsCopyBtn.style.color = ''; }, 1000);
896+
});
897+
};
898+
wsRow2.appendChild(wsCopyBtn);
880899
wsDiv.appendChild(wsRow2);
881900
box.appendChild(wsDiv);
882901

@@ -1401,7 +1420,7 @@ function showUserEditor(login, user) {
14011420
<div class="edit-buttons">
14021421
<button type="button" class="btn-primary user-save-btn">Save</button>
14031422
${!isNew ? '<button type="button" class="btn-danger user-delete-btn">Delete</button>' : ''}
1404-
<button type="button" class="user-cancel-btn">Cancel</button>
1423+
<button type="button" class="btn btn-secondary user-cancel-btn">Cancel</button>
14051424
</div>
14061425
`;
14071426
card.querySelector('.user-save-btn').addEventListener('click', () => saveUser(isNew ? null : login, card));
@@ -1425,7 +1444,7 @@ function showTokenEditor(tokenId, tok) {
14251444
card.className = 'section user-edit';
14261445
card.dataset.tokenId = isNew ? 'new' : tokenId;
14271446
const title = isNew ? 'New API Token' : 'Edit API Token';
1428-
const tokenValue = tok.token || generateToken();
1447+
const tokenValue = tok.token || crypto.randomUUID();
14291448
card.innerHTML = `
14301449
<h3>${title}</h3>
14311450
<div class="field-row">
@@ -1445,11 +1464,11 @@ function showTokenEditor(tokenId, tok) {
14451464
<div class="edit-buttons">
14461465
<button type="button" class="btn-primary token-save-btn">Save</button>
14471466
${!isNew ? '<button type="button" class="btn-danger token-delete-btn">Delete</button>' : ''}
1448-
<button type="button" class="token-cancel-btn">Cancel</button>
1467+
<button type="button" class="btn btn-secondary token-cancel-btn">Cancel</button>
14491468
</div>
14501469
`;
14511470
card.querySelector('.token-generate-btn').addEventListener('click', () => {
1452-
card.querySelector('.token-value-input').value = generateToken();
1471+
card.querySelector('.token-value-input').value = crypto.randomUUID();
14531472
});
14541473
card.querySelector('.token-copy-btn').addEventListener('click', () => {
14551474
const input = card.querySelector('.token-value-input');
@@ -1468,11 +1487,6 @@ function showTokenEditor(tokenId, tok) {
14681487
card.querySelector('.token-name').focus();
14691488
}
14701489

1471-
function generateToken() {
1472-
const arr = new Uint8Array(32);
1473-
crypto.getRandomValues(arr);
1474-
return Array.from(arr, b => b.toString(16).padStart(2, '0')).join('');
1475-
}
14761490

14771491
async function saveUser(login, card) {
14781492
const isNew = login === null;
@@ -1641,7 +1655,7 @@ function showSessionEditor() {
16411655
</div>
16421656
<div class="edit-buttons">
16431657
<button type="button" class="btn-primary" id="save-session-btn">Save</button>
1644-
<button type="button" id="cancel-session-btn">Cancel</button>
1658+
<button type="button" class="btn btn-secondary" id="cancel-session-btn">Cancel</button>
16451659
</div>
16461660
`;
16471661
existing.replaceWith(card);
@@ -1701,7 +1715,7 @@ function showHttpEditor(index, srv) {
17011715
<div class="edit-buttons">
17021716
<button type="button" class="btn-primary http-save-btn">Save</button>
17031717
${!isNew ? '<button type="button" class="btn-danger http-delete-btn">Delete</button>' : ''}
1704-
<button type="button" class="http-cancel-btn">Cancel</button>
1718+
<button type="button" class="btn btn-secondary http-cancel-btn">Cancel</button>
17051719
</div>
17061720
`;
17071721
card.querySelector('.http-ssl').addEventListener('change', e => {

ser2tcp/html/favicon.svg

Lines changed: 35 additions & 0 deletions
Loading

ser2tcp/html/index.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
<meta charset="utf-8">
55
<meta name="viewport" content="width=device-width, initial-scale=1">
66
<title>ser2tcp</title>
7+
<link rel="icon" type="image/svg+xml" href="favicon.svg">
78
<link rel="stylesheet" href="style.css">
89
</head>
910
<body>

ser2tcp/html/style.css

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
--bg-input-focus: #fff;
66
--text-input-focus: #333;
77
--bg-server: #f8f8f8;
8+
--bg-secondary-btn: #e0e0e0;
89
--border: transparent;
910
--border-light: #eee;
1011
--text: #333;
@@ -18,7 +19,6 @@
1819
--edit-border: #4a9eff;
1920
--badge-bg: #e8e8e8;
2021
--badge-text: #666;
21-
--nav-bg: transparent;
2222
--dialog-bg: #fff;
2323
--dialog-overlay: rgba(0,0,0,0.4);
2424
--signal-off-bg: #e0e0e0;
@@ -36,6 +36,7 @@
3636
--bg-input-focus: #111;
3737
--text-input-focus: #eee;
3838
--bg-server: #2c2c2c;
39+
--bg-secondary-btn: #3a3a3a;
3940
--border: transparent;
4041
--border-light: #3a3a3a;
4142
--text: #ddd;
@@ -49,7 +50,6 @@
4950
--edit-border: #5aadff;
5051
--badge-bg: #333;
5152
--badge-text: #aaa;
52-
--nav-bg: transparent;
5353
--dialog-bg: #2a2a2a;
5454
--dialog-overlay: rgba(0,0,0,0.6);
5555
--signal-off-bg: #333;
@@ -68,6 +68,7 @@
6868
--bg-input-focus: #111;
6969
--text-input-focus: #eee;
7070
--bg-server: #2c2c2c;
71+
--bg-secondary-btn: #3a3a3a;
7172
--border: transparent;
7273
--border-light: #3a3a3a;
7374
--text: #ddd;
@@ -81,7 +82,6 @@
8182
--edit-border: #5aadff;
8283
--badge-bg: #333;
8384
--badge-text: #aaa;
84-
--nav-bg: transparent;
8585
--dialog-bg: #2a2a2a;
8686
--dialog-overlay: rgba(0,0,0,0.6);
8787
--signal-off-bg: #333;
@@ -147,9 +147,9 @@ button { padding: 0.4em 1em; border: none; border-radius: 6px;
147147
.btn-primary:hover { background: var(--accent-hover); }
148148
.btn-danger { background: var(--danger); }
149149
.btn-danger:hover { opacity: 0.9; }
150-
.btn-secondary { background: none; border: 1px solid var(--border);
150+
.btn-secondary { background: var(--bg-secondary-btn); border: none;
151151
color: var(--text-secondary); }
152-
.btn-secondary:hover { background: var(--bg-server); }
152+
.btn-secondary:hover { filter: brightness(1.1); }
153153
.btn-small { padding: 0.2em 0.6em; font-size: 0.85em; }
154154
.btn-icon { padding: 0.3em; width: 2em; height: 2em; display: inline-flex;
155155
align-items: center; justify-content: center; background: var(--bg-server);
@@ -205,7 +205,7 @@ button { padding: 0.4em 1em; border: none; border-radius: 6px;
205205
.section-header:first-child { margin-top: 0; }
206206
.token-value { font-family: monospace; font-size: 0.9em; color: var(--text-secondary);
207207
cursor: pointer; margin: 0.3em 0; transition: color 0.2s; }
208-
.token-value:hover { color: var(--primary); }
208+
.token-value:hover { color: var(--accent); }
209209
.token-value.copied { color: var(--success); }
210210
.token-value.copied::after { content: ' (copied)'; font-family: inherit; }
211211
.port-edit, .http-edit, .user-edit { background: var(--bg-card); padding: 1em 1.2em; margin: 0;
@@ -240,8 +240,8 @@ button { padding: 0.4em 1em; border: none; border-radius: 6px;
240240
background: none; color: var(--text-muted); padding: 0.2em;
241241
border: none; display: flex; align-items: center; }
242242
.server-box .btn-remove:hover { color: var(--danger); }
243-
.server-box .btn-remove:disabled { color: var(--border); cursor: default; }
244-
.server-box .btn-remove:disabled:hover { color: var(--border); }
243+
.server-box .btn-remove:disabled { color: var(--text-muted); opacity: 0.3; cursor: default; }
244+
.server-box .btn-remove:disabled:hover { color: var(--text-muted); }
245245
.server-box .btn-remove svg { width: 1.1em; height: 1.1em; }
246246
.edit-actions { display: flex; gap: 0.5em; margin-top: 1em; }
247247
.edit-actions .spacer { flex: 1; }
@@ -257,8 +257,8 @@ button { padding: 0.4em 1em; border: none; border-radius: 6px;
257257
.detected-grid { display: grid;
258258
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
259259
gap: 0.8em; }
260-
.detected-card { opacity: 0.75; }
261-
.detected-card { display: flex; flex-direction: column; padding-bottom: 3em; }
260+
.detected-card { display: flex; flex-direction: column; padding-bottom: 3em;
261+
opacity: 0.75; }
262262
.detected-card .port-card-header { margin-bottom: 0.3em; }
263263
.detected-card .port-card-title { font-weight: bold; font-family: monospace; font-size: 1.1em; }
264264
.detected-card .port-card-desc { color: var(--text-muted); font-size: 0.85em; margin-top: 0.1em; }
@@ -286,14 +286,14 @@ button { padding: 0.4em 1em; border: none; border-radius: 6px;
286286
.ctl-signal-label { min-width: auto !important; display: inline-flex;
287287
align-items: center; gap: 0.2em; font-size: 0.9em; }
288288
.srv-control-fields { margin-top: 0.5em; padding-top: 0.5em;
289-
border-top: 1px dashed var(--border); }
289+
border-top: 1px dashed var(--border-light); }
290290
.srv-ip-filter { margin-top: 0.5em; padding-top: 0.5em;
291-
border-top: 1px dashed var(--border); }
291+
border-top: 1px dashed var(--border-light); }
292292
.ctl-poll-interval { max-width: 8em; }
293293
.setting-row { display: flex; align-items: center; gap: 0.8em; margin: 0.6em 0; }
294294
.setting-row label { min-width: 10em; }
295295
.setting-row input[type="text"], .setting-row input[type="number"] { flex: 1; }
296-
.ssl-fields { margin-left: 1em; border-left: 2px solid var(--border); padding-left: 1em; }
296+
.ssl-fields { margin-left: 1em; border-left: 2px solid var(--border-light); padding-left: 1em; }
297297
.signal-indicators { display: flex; gap: 0.3em; margin: 0.4em 0; }
298298
.signal-badge { display: inline-block; padding: 0.2em 0.5em; border-radius: 3px;
299299
font-size: 1em; font-weight: bold; font-family: monospace; }

0 commit comments

Comments
 (0)