diff --git a/app.py b/app.py index 1e10a79..419f4d8 100644 --- a/app.py +++ b/app.py @@ -35,7 +35,8 @@ WIFI_BOOT_WAIT = 25 # Sekunden warten beim Start bevor AP gestartet wird DEFAULT_CONFIG = { # USB - 'source_port': None, 'dest_port': None, + 'source_port': None, 'source_label': '', + 'dest_port': None, 'dest_label': '', 'folder_format': '%Y-%m-%d', 'add_time': True, 'subfolder': True, 'auto_copy': True, # WiFi @@ -522,6 +523,8 @@ def r_wifi_status(): # ── HTML Template ───────────────────────────────────────────────────────────── +# ── HTML Template ───────────────────────────────────────────────────────────── + HTML = r""" @@ -534,11 +537,10 @@ HTML = r""" body{background:var(--bg);color:var(--txt);font-family:system-ui,sans-serif;padding:1rem 1rem 4rem;min-height:100vh} h1{font-size:1.35rem;font-weight:700;display:flex;align-items:center;gap:.5rem;margin-bottom:1.25rem} h2{font-size:.72rem;font-weight:700;text-transform:uppercase;letter-spacing:.08em;color:var(--mut);margin-bottom:.8rem} -.wrap{max-width:940px;margin:0 auto;display:grid;gap:.85rem;grid-template-columns:1fr} +.wrap{max-width:960px;margin:0 auto;display:grid;gap:.85rem;grid-template-columns:1fr} @media(min-width:600px){.wrap{grid-template-columns:1fr 1fr}} .card{background:var(--s1);border:1px solid var(--brd);border-radius:.8rem;padding:1.1rem} .span2{grid-column:1/-1} -/* Buttons */ .btn{display:inline-flex;align-items:center;gap:.3rem;padding:.38rem .82rem;border:1px solid var(--brd);border-radius:.4rem;background:transparent;color:var(--txt);font-size:.84rem;cursor:pointer;transition:.15s;white-space:nowrap} .btn:hover{border-color:var(--acc);color:var(--acc)} .btn:disabled{opacity:.4;cursor:default} @@ -550,27 +552,10 @@ h2{font-size:.72rem;font-weight:700;text-transform:uppercase;letter-spacing:.08e .btn.danger:hover{background:rgba(239,68,68,.1)} .btn.sm{padding:.25rem .55rem;font-size:.75rem} .btn-row{display:flex;flex-wrap:wrap;gap:.5rem;margin-top:.8rem} -/* Progress */ .prog-wrap{margin:.6rem 0 .3rem;height:6px;background:var(--bg);border-radius:3px;overflow:hidden} .prog-bar{height:100%;background:var(--acc);border-radius:3px;transition:width .4s ease} .prog-info{font-size:.78rem;color:var(--mut);min-height:1.1rem} -/* Status */ .st-ok{color:var(--grn)}.st-run{color:var(--acc)}.st-err{color:var(--red)}.st-idle{color:var(--mut)} -/* Devices */ -.dev-list{display:flex;flex-direction:column;gap:.5rem} -.dev{padding:.65rem .85rem;border:1px solid var(--brd);border-radius:.5rem;transition:.15s} -.dev:hover{border-color:var(--acc)} -.dev.src{border-color:var(--grn);background:rgba(34,197,94,.06)} -.dev.dst{border-color:var(--acc);background:rgba(59,130,246,.06)} -.dev-top{display:flex;align-items:center;gap:.5rem;flex-wrap:wrap} -.dev-name{font-weight:600;font-size:.9rem} -.badge{font-size:.65rem;font-weight:700;text-transform:uppercase;padding:.12rem .42rem;border-radius:.25rem} -.b-src{background:rgba(34,197,94,.15);color:var(--grn)} -.b-dst{background:rgba(59,130,246,.15);color:var(--acc)} -.dev-meta{font-size:.74rem;color:var(--mut);display:flex;gap:.4rem;flex-wrap:wrap;margin:.25rem 0} -.dev-meta span{background:var(--bg);padding:.1rem .35rem;border-radius:.2rem} -.dev-acts{display:flex;gap:.4rem;margin-top:.35rem} -/* Form fields */ .field{margin-bottom:.8rem} .field label{display:block;font-size:.81rem;color:var(--mut);margin-bottom:.3rem} .field input,.field select{width:100%;padding:.44rem .65rem;background:var(--bg);border:1px solid var(--brd);border-radius:.4rem;color:var(--txt);font-size:.88rem} @@ -578,31 +563,40 @@ h2{font-size:.72rem;font-weight:700;text-transform:uppercase;letter-spacing:.08e .field input[type=password]{letter-spacing:.05em} .tog{display:flex;align-items:center;gap:.5rem;margin-bottom:.65rem;cursor:pointer;user-select:none;font-size:.88rem} .tog input{accent-color:var(--acc);width:16px;height:16px;cursor:pointer} -/* Log */ .log-box{font-family:ui-monospace,monospace;font-size:.76rem;max-height:220px;overflow-y:auto} .log-entry{display:flex;gap:.5rem;padding:.2rem 0;border-bottom:1px solid rgba(51,65,85,.5)} .log-t{color:var(--mut);flex-shrink:0} .empty{color:var(--mut);font-size:.86rem;padding:.25rem 0} -/* WiFi status bar */ .wifi-bar{display:flex;align-items:center;gap:.6rem;padding:.55rem .85rem;border-radius:.5rem;border:1px solid var(--brd);background:var(--s2);font-size:.84rem;flex-wrap:wrap} .wifi-dot{width:8px;height:8px;border-radius:50%;flex-shrink:0} -.wifi-dot.green{background:var(--grn)} -.wifi-dot.blue{background:var(--pur)} -.wifi-dot.grey{background:var(--mut)} -.wifi-info{flex:1;min-width:0} +.wifi-dot.green{background:var(--grn)}.wifi-dot.blue{background:var(--pur)}.wifi-dot.grey{background:var(--mut)} .wifi-ip{font-family:monospace;font-size:.8rem;color:var(--mut)} -/* Tab strip for config */ .tabs{display:flex;gap:.25rem;margin-bottom:.9rem;border-bottom:1px solid var(--brd);padding-bottom:.5rem} .tab{padding:.3rem .7rem;border-radius:.35rem;font-size:.82rem;cursor:pointer;color:var(--mut);transition:.15s} .tab.active{background:var(--acc);color:#fff} .tab-pane{display:none}.tab-pane.active{display:block} -/* Network list */ -.net-list{display:flex;flex-direction:column;gap:.35rem;max-height:220px;overflow-y:auto;margin-top:.5rem} +.net-list{display:flex;flex-direction:column;gap:.35rem;max-height:200px;overflow-y:auto;margin-top:.5rem} .net-item{display:flex;align-items:center;gap:.5rem;padding:.35rem .55rem;border:1px solid var(--brd);border-radius:.4rem;cursor:pointer;transition:.15s;font-size:.84rem} .net-item:hover{border-color:var(--acc);background:rgba(59,130,246,.05)} .net-signal{font-size:.72rem;color:var(--mut);margin-left:auto} .flash{font-size:.78rem;padding:.25rem 0;min-height:1.2rem} .flash.ok{color:var(--grn)}.flash.err{color:var(--red)} +/* Port Slots */ +.port-grid{display:grid;grid-template-columns:1fr 1fr;gap:.85rem} +@media(max-width:599px){.port-grid{grid-template-columns:1fr}} +.port-slot{border:2px solid var(--brd);border-radius:.7rem;padding:1rem;transition:border-color .2s} +.port-slot.has-src{border-color:var(--grn)} +.port-slot.has-dst{border-color:var(--acc)} +.port-role{font-size:.65rem;font-weight:800;text-transform:uppercase;letter-spacing:.1em;padding:.18rem .5rem;border-radius:.25rem;display:inline-block;margin-bottom:.65rem} +.port-role.src{background:rgba(34,197,94,.15);color:var(--grn)} +.port-role.dst{background:rgba(59,130,246,.15);color:var(--acc)} +.port-status{display:flex;align-items:center;gap:.65rem;padding:.65rem .8rem;background:var(--bg);border-radius:.5rem;margin-bottom:.8rem;min-height:54px} +.pdot{width:10px;height:10px;border-radius:50%;flex-shrink:0;transition:.3s} +.pdot.on{background:var(--grn);box-shadow:0 0 6px var(--grn)} +.pdot.off{background:var(--brd)} +.port-dev-name{font-weight:600;font-size:.9rem;line-height:1.3} +.port-dev-sub{font-size:.73rem;color:var(--mut);font-family:monospace;margin-top:.1rem} +.port-hint{font-size:.73rem;color:var(--mut);margin-top:.65rem;padding:.5rem .65rem;background:var(--bg);border-radius:.4rem;border-left:3px solid var(--brd)} @@ -611,12 +605,12 @@ h2{font-size:.72rem;font-weight:700;text-transform:uppercase;letter-spacing:.08e

- + PiCopy

-
+
-
+
Verbinde…
@@ -639,10 +633,69 @@ h2{font-size:.72rem;font-weight:700;text-transform:uppercase;letter-spacing:.08e
- +
-

Verbundene USB-Geräte

-
Lade…
+

USB Port Konfiguration

+ +
+ + +
+
Quelle
+
+
+
+
Nicht verbunden
+
Kein Port konfiguriert
+
+
+
+ + +
+
+ + +
+ +
+
Stecke den USB-Stick in den gewünschten Port, wähle ihn hier aus und klicke Speichern. PiCopy merkt sich diesen physischen Port dauerhaft.
+
+ + +
+
Ziel
+
+
+
+
Nicht verbunden
+
Kein Port konfiguriert
+
+
+
+ + +
+
+ + +
+ +
+
Stecke das Ziel-Laufwerk in den gewünschten Port, wähle es aus und klicke Speichern. Ab dann wird dieser Port immer als Ziel verwendet.
+
+ +
+ + +
@@ -651,15 +704,15 @@ h2{font-size:.72rem;font-weight:700;text-transform:uppercase;letter-spacing:.08e
- - + +
@@ -668,20 +721,16 @@ h2{font-size:.72rem;font-weight:700;text-transform:uppercase;letter-spacing:.08e

WiFi-Einstellungen

-
Heimnetz
-
Hotspot (AP)
+
Heimnetz
+
Hotspot (AP)
- -
-
- WLAN für die Verbindung mit deinem Router. Wenn nicht erreichbar, startet PiCopy automatisch einen eigenen Hotspot. -
+
Heimnetz für die Router-Verbindung. Wenn nicht erreichbar, startet PiCopy automatisch einen Hotspot.
- +
@@ -692,13 +741,8 @@ h2{font-size:.72rem;font-weight:700;text-transform:uppercase;letter-spacing:.08e
- -
-
- Der Hotspot wird automatisch gestartet wenn kein Heimnetz erreichbar ist.
- IP: 10.42.0.1  ·  Port: 8080 -
+
Dieser Hotspot startet automatisch wenn kein Heimnetz erreichbar ist.
IP des Pi im Hotspot-Modus: 10.42.0.1:8080
@@ -712,93 +756,146 @@ h2{font-size:.72rem;font-weight:700;text-transform:uppercase;letter-spacing:.08e
- +

Protokoll

Noch keine Einträge
-
- +