@@ -127,16 +127,25 @@ def _shell(body: str) -> bytes:
127127button.secondary {{ background: white; color: var(--ink); border-color: var(--line); }}
128128.actions {{ display: flex; flex-wrap: wrap; gap: 10px; align-items: end; }}
129129.actions > * {{ width: auto; }}
130- table {{ width: 100%; border-collapse: collapse; font-size: 14px; }}
131- th, td {{ border-bottom: 1px solid var(--line); padding: 9px; text-align: left; vertical-align: top; }}
132- code {{ overflow-wrap: anywhere; }}
130+ .device-grid {{ display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 360px), 1fr)); gap: 12px; }}
131+ .device-card {{ border: 1px solid var(--line); border-radius: 8px; padding: 12px; min-width: 0; }}
132+ .device-card-head {{ display: flex; gap: 10px; align-items: center; justify-content: space-between; min-width: 0; }}
133+ .pick-row {{ display: flex; grid-template-columns: none; flex-direction: row; align-items: center; gap: 8px; min-width: 0; color: var(--ink); }}
134+ .pick-row input {{ width: auto; min-height: auto; }}
135+ .pick-row strong {{ overflow-wrap: anywhere; }}
136+ .device-meta {{ display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; margin: 12px 0 0; }}
137+ .device-meta div {{ min-width: 0; }}
138+ .device-meta .wide {{ grid-column: 1 / -1; }}
139+ .device-meta dt {{ color: var(--muted); font-size: 12px; margin-bottom: 3px; }}
140+ .device-meta dd {{ margin: 0; min-width: 0; }}
141+ code {{ display: inline-block; max-width: 100%; overflow-wrap: anywhere; word-break: break-word; }}
133142.muted {{ color: var(--muted); }}
134143.badge {{ border: 1px solid var(--line); border-radius: 999px; padding: 2px 8px; color: var(--ok); }}
135144.notice {{ border-left: 4px solid var(--warn); padding: 10px 12px; background: #fff7ed; }}
136145pre {{ max-height: 360px; overflow: auto; padding: 12px; background: #111827; color: #d1fae5; border-radius: 8px; }}
137146iframe {{ width: 100%; min-height: 420px; border: 1px solid var(--line); border-radius: 8px; background: white; }}
138147@media (max-width: 720px) {{
139- table {{ display: block; overflow-x: auto ; }}
148+ .device-meta {{ grid-template-columns: 1fr ; }}
140149 .actions > * {{ width: 100%; }}
141150}}
142151</style>
@@ -197,7 +206,7 @@ def render_home(query: dict[str, list[str]], notice: str = "") -> bytes:
197206 <h2>Release Bundle</h2>
198207 <p class="muted">{ html .escape (bundle_text )} </p>
199208 <form method="post" action="/import?workspace={ html .escape (workspace_id )} " enctype="multipart/form-data">
200- <label>Tarball<input type="file" name="tarball" accept=".tar,.tar.gz,.tgz"></label>
209+ <label>Tarball<input type="file" name="tarball" accept=".tar,.tar.gz,.tgz,application/gzip,application/x-tar "></label>
201210 <div class="actions"><button { "disabled" if not workspace else "" } >Import tarball</button></div>
202211 </form>
203212</section>
@@ -233,10 +242,7 @@ def render_home(query: dict[str, list[str]], notice: str = "") -> bytes:
233242<section>
234243 <h2>Generated Devices</h2>
235244 <form method="post" action="/flash?workspace={ html .escape (workspace_id )} ">
236- <table>
237- <thead><tr><th></th><th>Serial</th><th>VID / PID</th><th>Manual code</th><th>QR payload</th><th>Status</th></tr></thead>
238- <tbody>{ render_device_rows (devices , selected_serial )} </tbody>
239- </table>
245+ <div class="device-grid">{ render_device_rows (devices , selected_serial )} </div>
240246 <div class="grid">
241247 <label>Serial port<select name="port">{ render_port_options (ports , selected_port )} </select></label>
242248 <label>Options<span><input type="checkbox" name="erase" value="1"> Erase first</span><span><input type="checkbox" name="monitor" value="1"> Monitor after flash</span></label>
0 commit comments