From bfb0ceaaa33cfe95d3fe773a093c7409a5c76d41 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=D0=90=D0=BD=D1=82=D0=BE=D0=BD=20=D0=A2=D1=80=D0=BE=D1=88?=
=?UTF-8?q?=D0=B8=D0=BD?=
Date: Fri, 7 Aug 2026 01:04:00 +0300
Subject: [PATCH] connected state redesign: sim/nosim svg, spin animation,
dark:invert, pysimSetConnected()
---
index.html | 48 ++++++++++++++++++++++++++++++------------------
nosim.svg | 48 ++++++++++++++++++++++++++++++++++++++++++++++++
style.css | 31 +++++++++++--------------------
3 files changed, 89 insertions(+), 38 deletions(-)
create mode 100644 nosim.svg
diff --git a/index.html b/index.html
index 30c71b9..eb6aa12 100644
--- a/index.html
+++ b/index.html
@@ -827,13 +827,17 @@
-
-
-
Connected
-
Equip card
-
Check status
-
Reset card
-
Disconnect from pySim
+
+
+
+
+ Equip card
+ Check status
+ Reset card
+ Disconnect from pySim
+
+
+
@@ -2436,9 +2440,13 @@ async function pysimFetch(path, body) {
return await res.json();
}
-function pysimSetDot(ok) {
- const dot = document.getElementById('pysim-status-dot');
- dot.className = 'inline-block w-3 h-3 rounded-full ' + (ok ? 'bg-green-500' : 'bg-red-500');
+function pysimSetConnected(state) {
+ const img = document.getElementById('pysim-status-img');
+ if (state === 'spin') {
+ img.src = 'sim_anim.svg';
+ } else {
+ img.src = state ? 'sim.svg' : 'nosim.svg';
+ }
}
function pysimShowConnected(connected) {
@@ -2451,7 +2459,7 @@ async function pysimRefresh() {
const statusEl = document.getElementById('pysim-status');
try {
const data = await pysimFetch('/api/status');
- pysimSetDot(true);
+ pysimSetConnected(true);
let html = 'Reader:
' + esc(data.reader || 'none') + ' ' +
' | Card:
' + esc(data.card || 'none') + ' ' +
' | Profile:
' + esc(data.profile || 'none') + ' ' +
@@ -2475,7 +2483,7 @@ async function pysimRefresh() {
statusEl.innerHTML = html;
return true;
} catch (e) {
- pysimSetDot(false);
+ pysimSetConnected(false);
statusEl.textContent = 'Connection failed: ' + e.message;
return false;
}
@@ -2489,6 +2497,7 @@ async function pysimConnect() {
btn.textContent = 'Connecting...';
const statusEl = document.getElementById('pysim-status');
statusEl.innerHTML = '
Checking card... ';
+ pysimSetConnected('spin');
try {
const status = await pysimFetch('/api/status');
if (!status.app_ready) {
@@ -2496,21 +2505,21 @@ async function pysimConnect() {
}
const cmd = await pysimFetch('/api/command', { cmd: 'status' });
if (cmd.output && (cmd.output.includes('Exception') || cmd.output.includes('ProtocolError'))) {
- pysimSetDot(false);
+ pysimSetConnected(false);
statusEl.innerHTML = '
No card detected. Insert card and click Equip card button ';
pysimShowConnected(true);
btn.textContent = 'Connected';
btn.disabled = false;
return;
}
- pysimSetDot(true);
+ pysimSetConnected(true);
pysimShowConnected(true);
await pysimRefresh();
pysimLoadCommands();
pysimFsRefresh();
btn.textContent = 'Connected';
} catch (e) {
- pysimSetDot(false);
+ pysimSetConnected(false);
statusEl.innerHTML = '
Connection failed: ' + esc(e.message) + ' ';
btn.textContent = 'Connect';
}
@@ -2520,7 +2529,7 @@ async function pysimConnect() {
function pysimDisconnect() {
pysimShowConnected(false);
document.getElementById('pysim-status').textContent = '';
- pysimSetDot(false);
+ pysimSetConnected(false);
}
async function pysimRunCmd(cmd) {
@@ -2528,13 +2537,13 @@ async function pysimRunCmd(cmd) {
try {
const result = await pysimFetch('/api/command', { cmd });
if (result.output && (result.output.includes('Exception') || result.output.includes('ProtocolError') || result.output.includes('SwMatchError'))) {
- pysimSetDot(false);
+ pysimSetConnected(false);
statusEl.innerHTML = '
No card detected. Insert card and click Equip card button ';
return null;
}
return result;
} catch (e) {
- pysimSetDot(false);
+ pysimSetConnected(false);
statusEl.innerHTML = '
No card detected. Insert card and click Equip card button ';
return null;
}
@@ -2543,6 +2552,7 @@ async function pysimRunCmd(cmd) {
async function pysimStatusCmd() {
const statusEl = document.getElementById('pysim-status');
statusEl.innerHTML = '
Checking... ';
+ pysimSetConnected('spin');
const result = await pysimRunCmd('status');
if (result) await pysimRefresh();
}
@@ -2550,6 +2560,7 @@ async function pysimStatusCmd() {
async function pysimResetCmd() {
const statusEl = document.getElementById('pysim-status');
statusEl.innerHTML = '
Resetting... ';
+ pysimSetConnected('spin');
const result = await pysimRunCmd('reset');
if (result) {
await pysimRefresh();
@@ -2560,6 +2571,7 @@ async function pysimResetCmd() {
async function pysimEquipCmd() {
const statusEl = document.getElementById('pysim-status');
statusEl.innerHTML = '
Equipping... ';
+ pysimSetConnected('spin');
const result = await pysimRunCmd('equip');
if (result) {
await pysimRefresh();
diff --git a/nosim.svg b/nosim.svg
new file mode 100644
index 0000000..308b0c3
--- /dev/null
+++ b/nosim.svg
@@ -0,0 +1,48 @@
+
+
+
+
diff --git a/style.css b/style.css
index 34ea3ae..bc002f6 100644
--- a/style.css
+++ b/style.css
@@ -611,10 +611,6 @@ video {
display: block;
}
-.inline-block {
- display: inline-block;
-}
-
.flex {
display: flex;
}
@@ -627,8 +623,8 @@ video {
display: none;
}
-.h-3 {
- height: 0.75rem;
+.h-16 {
+ height: 4rem;
}
.min-h-20 {
@@ -663,10 +659,6 @@ video {
width: 6rem;
}
-.w-3 {
- width: 0.75rem;
-}
-
.w-6 {
width: 1.5rem;
}
@@ -679,6 +671,10 @@ video {
width: 100%;
}
+.min-w-0 {
+ min-width: 0px;
+}
+
.max-w-4xl {
max-width: 56rem;
}
@@ -832,21 +828,11 @@ video {
background-color: rgb(249 250 251 / var(--tw-bg-opacity, 1));
}
-.bg-green-500 {
- --tw-bg-opacity: 1;
- background-color: rgb(34 197 94 / var(--tw-bg-opacity, 1));
-}
-
.bg-neutral-50 {
--tw-bg-opacity: 1;
background-color: rgb(250 250 250 / var(--tw-bg-opacity, 1));
}
-.bg-red-500 {
- --tw-bg-opacity: 1;
- background-color: rgb(239 68 68 / var(--tw-bg-opacity, 1));
-}
-
.bg-transparent {
background-color: transparent;
}
@@ -1174,6 +1160,11 @@ video {
color: rgb(250 204 21 / var(--tw-text-opacity, 1));
}
+.dark\:invert:is(.dark *) {
+ --tw-invert: invert(100%);
+ filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow);
+}
+
.dark\:hover\:bg-slate-600:hover:is(.dark *) {
--tw-bg-opacity: 1;
background-color: rgb(71 85 105 / var(--tw-bg-opacity, 1));