ui: redesign WiFi list with signal bars and cleaner layout
- Replace <select> with scrollable list of clickable items - Show signal strength as 4-bar icon instead of percentage text - Remove security info from parentheses, show lock icon only - Smaller font size for compact mobile display Made-with: Cursor
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
fix: pre-scan WiFi before entering AP mode
|
ui: redesign WiFi list with signal bars and cleaner layout
|
||||||
|
|
||||||
wlan0 cannot scan while in AP mode (hardware limitation).
|
- Replace <select> with scrollable list of clickable items
|
||||||
Now scan nearby networks before starting hotspot and cache
|
- Show signal strength as 4-bar icon instead of percentage text
|
||||||
the results for the captive portal page.
|
- Remove security info from parentheses, show lock icon only
|
||||||
|
- Smaller font size for compact mobile display
|
||||||
|
|||||||
@@ -162,9 +162,19 @@ body{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;b
|
|||||||
.device-id{text-align:center;background:#f8f9fa;border-radius:8px;padding:8px;margin-bottom:20px;font-size:14px;color:#555}
|
.device-id{text-align:center;background:#f8f9fa;border-radius:8px;padding:8px;margin-bottom:20px;font-size:14px;color:#555}
|
||||||
.device-id strong{color:#1a1a2e;font-size:16px}
|
.device-id strong{color:#1a1a2e;font-size:16px}
|
||||||
label{display:block;font-size:14px;font-weight:500;margin-bottom:6px;color:#555}
|
label{display:block;font-size:14px;font-weight:500;margin-bottom:6px;color:#555}
|
||||||
select,input{width:100%;padding:12px;border:1.5px solid #ddd;border-radius:8px;font-size:15px;outline:none;transition:border-color .2s}
|
input{width:100%;padding:12px;border:1.5px solid #ddd;border-radius:8px;font-size:15px;outline:none;transition:border-color .2s}
|
||||||
select:focus,input:focus{border-color:#4a6cf7}
|
input:focus{border-color:#4a6cf7}
|
||||||
.field{margin-bottom:16px}
|
.field{margin-bottom:16px}
|
||||||
|
.wifi-list{max-height:220px;overflow-y:auto;border:1.5px solid #ddd;border-radius:8px;margin-bottom:16px}
|
||||||
|
.wifi-item{display:flex;align-items:center;padding:10px 12px;border-bottom:1px solid #f0f0f0;cursor:pointer;font-size:13px;transition:background .15s}
|
||||||
|
.wifi-item:last-child{border-bottom:none}
|
||||||
|
.wifi-item:hover,.wifi-item.active{background:#e8f0fe}
|
||||||
|
.wifi-item.active{font-weight:600;color:#1a1a2e}
|
||||||
|
.wifi-name{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
||||||
|
.wifi-signal{display:flex;align-items:flex-end;gap:1.5px;height:14px;margin-left:8px;flex-shrink:0}
|
||||||
|
.wifi-signal i{display:block;width:3px;background:#ccc;border-radius:1px}
|
||||||
|
.wifi-signal i.on{background:#4a6cf7}
|
||||||
|
.wifi-lock{margin-left:6px;font-size:11px;color:#888;flex-shrink:0}
|
||||||
.btn{width:100%;padding:14px;background:linear-gradient(135deg,#4a6cf7,#3b5de7);color:#fff;border:none;border-radius:8px;font-size:16px;font-weight:600;cursor:pointer;transition:opacity .2s}
|
.btn{width:100%;padding:14px;background:linear-gradient(135deg,#4a6cf7,#3b5de7);color:#fff;border:none;border-radius:8px;font-size:16px;font-weight:600;cursor:pointer;transition:opacity .2s}
|
||||||
.btn:hover{opacity:.9}
|
.btn:hover{opacity:.9}
|
||||||
.btn:disabled{opacity:.5;cursor:not-allowed}
|
.btn:disabled{opacity:.5;cursor:not-allowed}
|
||||||
@@ -188,11 +198,9 @@ select:focus,input:focus{border-color:#4a6cf7}
|
|||||||
</div>
|
</div>
|
||||||
<div class="device-id">设备 ID: <strong>${this._clawId}</strong></div>
|
<div class="device-id">设备 ID: <strong>${this._clawId}</strong></div>
|
||||||
|
|
||||||
<button class="btn btn-scan" onclick="doScan()">🔍 扫描 WiFi</button>
|
|
||||||
|
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<label for="ssid">WiFi 网络</label>
|
<label>WiFi 网络</label>
|
||||||
<select id="ssid"><option value="">-- 点击上方扫描 --</option></select>
|
<div class="wifi-list" id="wifiList"><div style="padding:12px;text-align:center;color:#999;font-size:13px">加载中...</div></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="manual">
|
<div class="manual">
|
||||||
@@ -200,6 +208,7 @@ select:focus,input:focus{border-color:#4a6cf7}
|
|||||||
<label for="manualToggle">手动输入 SSID</label>
|
<label for="manualToggle">手动输入 SSID</label>
|
||||||
<input type="text" id="manualSsid" placeholder="输入 WiFi 名称" style="display:none;margin-top:8px">
|
<input type="text" id="manualSsid" placeholder="输入 WiFi 名称" style="display:none;margin-top:8px">
|
||||||
</div>
|
</div>
|
||||||
|
<input type="hidden" id="selectedSsid" value="">
|
||||||
|
|
||||||
<div class="field" style="margin-top:16px">
|
<div class="field" style="margin-top:16px">
|
||||||
<label for="password">密码</label>
|
<label for="password">密码</label>
|
||||||
@@ -214,35 +223,56 @@ select:focus,input:focus{border-color:#4a6cf7}
|
|||||||
function $(id){return document.getElementById(id)}
|
function $(id){return document.getElementById(id)}
|
||||||
function setStatus(msg,type){var s=$('status');s.textContent=msg;s.className='status '+type}
|
function setStatus(msg,type){var s=$('status');s.textContent=msg;s.className='status '+type}
|
||||||
|
|
||||||
|
function signalBars(pct){
|
||||||
|
var bars=[4,7,10,14];
|
||||||
|
var on=pct>=80?4:pct>=60?3:pct>=40?2:1;
|
||||||
|
return bars.map(function(h,i){
|
||||||
|
return '<i style="height:'+h+'px" class="'+(i<on?'on':'')+'"></i>';
|
||||||
|
}).join('');
|
||||||
|
}
|
||||||
|
|
||||||
|
function selectWifi(ssid){
|
||||||
|
$('selectedSsid').value=ssid;
|
||||||
|
var items=document.querySelectorAll('.wifi-item');
|
||||||
|
items.forEach(function(el){el.classList.toggle('active',el.dataset.ssid===ssid)});
|
||||||
|
}
|
||||||
|
|
||||||
async function doScan(){
|
async function doScan(){
|
||||||
$('connectBtn').disabled=true;
|
var list=$('wifiList');
|
||||||
setStatus('正在扫描...','info');
|
list.innerHTML='<div style="padding:12px;text-align:center;color:#999;font-size:13px">加载中...</div>';
|
||||||
try{
|
try{
|
||||||
var r=await fetch('/api/scan');
|
var r=await fetch('/api/scan');
|
||||||
var d=await r.json();
|
var d=await r.json();
|
||||||
var sel=$('ssid');
|
var arr=d.wifi||[];
|
||||||
sel.innerHTML='<option value="">-- 请选择 --</option>';
|
if(arr.length===0){
|
||||||
(d.wifi||[]).forEach(function(w){
|
list.innerHTML='<div style="padding:12px;text-align:center;color:#999;font-size:13px">未发现网络,请手动输入</div>';
|
||||||
var o=document.createElement('option');
|
return;
|
||||||
o.value=w.ssid;
|
}
|
||||||
o.textContent=w.ssid+' ('+w.signal+'% '+w.security+')';
|
list.innerHTML='';
|
||||||
sel.appendChild(o);
|
arr.forEach(function(w){
|
||||||
|
var div=document.createElement('div');
|
||||||
|
div.className='wifi-item';
|
||||||
|
div.dataset.ssid=w.ssid;
|
||||||
|
div.onclick=function(){selectWifi(w.ssid)};
|
||||||
|
var lock=w.security&&w.security!=='Open'?'🔒':'';
|
||||||
|
div.innerHTML='<span class="wifi-name">'+w.ssid+'</span>'
|
||||||
|
+'<span class="wifi-signal">'+signalBars(w.signal)+'</span>'
|
||||||
|
+'<span class="wifi-lock">'+lock+'</span>';
|
||||||
|
list.appendChild(div);
|
||||||
});
|
});
|
||||||
var msg='发现 '+d.wifi.length+' 个网络';
|
}catch(e){
|
||||||
if(d.wifi.length===0) msg='未发现网络,请手动输入 SSID';
|
list.innerHTML='<div style="padding:12px;text-align:center;color:#c62828;font-size:13px">加载失败</div>';
|
||||||
setStatus(msg,'ok');
|
}
|
||||||
}catch(e){setStatus('扫描失败: '+e.message,'err')}
|
|
||||||
$('connectBtn').disabled=false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function toggleManual(){
|
function toggleManual(){
|
||||||
var on=$('manualToggle').checked;
|
var on=$('manualToggle').checked;
|
||||||
$('manualSsid').style.display=on?'block':'none';
|
$('manualSsid').style.display=on?'block':'none';
|
||||||
$('ssid').style.display=on?'none':'block';
|
$('wifiList').style.display=on?'none':'block';
|
||||||
}
|
}
|
||||||
|
|
||||||
async function doConnect(){
|
async function doConnect(){
|
||||||
var ssid=$('manualToggle').checked?$('manualSsid').value:$('ssid').value;
|
var ssid=$('manualToggle').checked?$('manualSsid').value:$('selectedSsid').value;
|
||||||
var pw=$('password').value;
|
var pw=$('password').value;
|
||||||
if(!ssid){setStatus('请选择或输入 WiFi','err');return}
|
if(!ssid){setStatus('请选择或输入 WiFi','err');return}
|
||||||
$('connectBtn').disabled=true;
|
$('connectBtn').disabled=true;
|
||||||
@@ -251,7 +281,7 @@ async function doConnect(){
|
|||||||
var r=await fetch('/api/connect',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({ssid:ssid,password:pw})});
|
var r=await fetch('/api/connect',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({ssid:ssid,password:pw})});
|
||||||
var d=await r.json();
|
var d=await r.json();
|
||||||
if(d.success){
|
if(d.success){
|
||||||
setStatus('✓ 设备正在连接 WiFi,热点将关闭。如连接失败,热点会自动恢复,请重新连接配网。','ok');
|
setStatus('✓ 设备正在连接 WiFi,热点将关闭。如连接失败,热点会自动恢复。','ok');
|
||||||
}else{
|
}else{
|
||||||
setStatus('失败: '+(d.error||'未知错误'),'err');
|
setStatus('失败: '+(d.error||'未知错误'),'err');
|
||||||
$('connectBtn').disabled=false;
|
$('connectBtn').disabled=false;
|
||||||
|
|||||||
Reference in New Issue
Block a user