Add local-mode workspace, ZIP import/export, and richer pin/ADC/serial sims
Boot: - Editor now picks local vs server mode based on URL flag, sign-in state, and a stale local-mode flag. Signed-in users are no longer bounced to IndexedDB if they had previously clicked "Use locally". Local mode: - New LocalWorkspaceClient (src/static/local-workspace.js) with pluggable IndexedDB and File System Access backends. Picked folder handles persist across reloads with a Reconnect button when the permission lapses. - Static-only host: scripts/serve_static_editor.py serves src/static/ with COOP/COEP so SharedArrayBuffer-backed sims keep working. - Bundled MicroPython stubs ship under src/static/bundled-lib/ for static hosting; FastAPI also exposes them at /api/public/lib-bundle. Workspace import / export: - Zero-dep ZIP encoder + reader (STORE + DEFLATE via DecompressionStream). Export/Import buttons in the workspace badge work in both local and server modes; imports are confined to code/. Pin / ADC / Serial simulation: - machine.py grows ADC, UART, expanded Pin, and PWM mocks, all driven by SharedArrayBuffer when cross-origin isolated and falling back to postMessage + [pin-out] stdout markers otherwise — pins, ADC slider, and serial input now keep working over plain HTTP / LAN-IP origins. - NeoPixel pins are claimed via a [pin-claim] marker and dropped from the Pins panel so the data line doesn't flicker per write(). - New demos: adc_slider_demo.py, pin_demo.py, serial_demo.py. Lib layout: - Single source of truth at repo lib/; workspace/lib/ caching layer removed and the directory deleted. Filesystem service reads stubs directly from PROJECT_ROOT/lib. UI: - Home page slimmed to "Sign in" + "Use locally" with optional editor / manage-users links. Admin user/invite UI moved to /users. - Workspace badge gains storage indicator, Folder…/Reconnect, Export, Import, and Exit controls. - Mobile-friendly tweaks: safer-area padding, larger touch targets, iOS-zoom-proof serial input, file-tree highlight fix. Tests: - test_auth.py patches PROJECT_ROOT for the lib-shared test so the repo-root lib refactor stays green. test_api.py asserts the new "LED Editor" branding. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -16,7 +16,8 @@ body {
|
||||
button,
|
||||
.tab,
|
||||
.file-item,
|
||||
.mode-btn {
|
||||
.menu-item,
|
||||
.menu-toggle {
|
||||
touch-action: manipulation;
|
||||
}
|
||||
|
||||
@@ -28,7 +29,7 @@ button,
|
||||
}
|
||||
|
||||
.sidebar-toggle {
|
||||
display: none;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 40px;
|
||||
@@ -37,7 +38,8 @@ button,
|
||||
background: white;
|
||||
color: #2d3748;
|
||||
border-radius: 8px;
|
||||
font-size: 1.2rem;
|
||||
font-size: 1.4rem;
|
||||
line-height: 1;
|
||||
cursor: pointer;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
@@ -46,10 +48,99 @@ button,
|
||||
background: #f7fafc;
|
||||
}
|
||||
|
||||
.sidebar-toggle .sidebar-toggle-icon {
|
||||
display: inline-block;
|
||||
transition: transform 0.15s ease;
|
||||
}
|
||||
|
||||
/* Flip the chevron when the file browser is hidden. */
|
||||
.sidebar-toggle[aria-expanded="false"] .sidebar-toggle-icon {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
.sidebar-backdrop {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Editor-header dropdown menu (Home + run options). */
|
||||
.header-menu {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.menu-toggle {
|
||||
list-style: none;
|
||||
cursor: pointer;
|
||||
padding: 0.45rem 0.7rem;
|
||||
border: 1px solid #e2e8f0;
|
||||
border-radius: 6px;
|
||||
background: white;
|
||||
color: #4a5568;
|
||||
font-size: 1.1rem;
|
||||
line-height: 1;
|
||||
user-select: none;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-width: 40px;
|
||||
min-height: 36px;
|
||||
}
|
||||
|
||||
.menu-toggle::-webkit-details-marker {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.menu-toggle::marker {
|
||||
display: none;
|
||||
content: '';
|
||||
}
|
||||
|
||||
.menu-toggle:hover {
|
||||
background: #f7fafc;
|
||||
border-color: #cbd5e0;
|
||||
}
|
||||
|
||||
.header-menu[open] > .menu-toggle {
|
||||
background: #edf2f7;
|
||||
border-color: #cbd5e0;
|
||||
}
|
||||
|
||||
.menu-content {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: calc(100% + 6px);
|
||||
background: white;
|
||||
border: 1px solid #cbd5e0;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 8px 22px rgba(0, 0, 0, 0.18);
|
||||
z-index: 60;
|
||||
min-width: 220px;
|
||||
padding: 0.35rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.1rem;
|
||||
}
|
||||
|
||||
.menu-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.55rem;
|
||||
padding: 0.55rem 0.7rem;
|
||||
border-radius: 6px;
|
||||
text-decoration: none;
|
||||
color: #2d3748;
|
||||
font-size: 0.9rem;
|
||||
cursor: pointer;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.menu-item:hover {
|
||||
background: #f7fafc;
|
||||
}
|
||||
|
||||
.menu-checkbox input[type="checkbox"] {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* Sidebar */
|
||||
.sidebar {
|
||||
width: 300px;
|
||||
@@ -108,6 +199,8 @@ button,
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
transition: background-color 0.2s;
|
||||
touch-action: manipulation;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
}
|
||||
|
||||
.file-item:hover {
|
||||
@@ -116,6 +209,7 @@ button,
|
||||
|
||||
.file-item.selected {
|
||||
background-color: #3182ce;
|
||||
box-shadow: inset 0 0 0 2px rgba(255, 255, 255, 0.22);
|
||||
}
|
||||
|
||||
.file-item.drag-target {
|
||||
@@ -131,11 +225,6 @@ button,
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.file-item.root-drop {
|
||||
border: 1px dashed #4a5568;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.file-icon {
|
||||
font-size: 1rem;
|
||||
}
|
||||
@@ -179,6 +268,49 @@ button,
|
||||
border-radius: 6px;
|
||||
padding: 0.2rem 0.45rem;
|
||||
white-space: nowrap;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.4rem;
|
||||
}
|
||||
|
||||
.workspace-badge-label {
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
max-width: 220px;
|
||||
}
|
||||
|
||||
.workspace-badge-exit,
|
||||
.workspace-badge-action {
|
||||
appearance: none;
|
||||
border: 1px solid #cbd5e1;
|
||||
background: transparent;
|
||||
color: #475569;
|
||||
border-radius: 4px;
|
||||
padding: 0.05rem 0.4rem;
|
||||
font-size: 0.7rem;
|
||||
cursor: pointer;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.workspace-badge-exit:hover,
|
||||
.workspace-badge-action:hover {
|
||||
background: #e2e8f0;
|
||||
}
|
||||
|
||||
.workspace-badge-action {
|
||||
border-color: #93c5fd;
|
||||
color: #1d4ed8;
|
||||
}
|
||||
|
||||
.workspace-badge-action:hover {
|
||||
background: #dbeafe;
|
||||
}
|
||||
|
||||
.workspace-badge-note {
|
||||
font-size: 0.7rem;
|
||||
color: #94a3b8;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
#current-file {
|
||||
@@ -199,31 +331,6 @@ button,
|
||||
color: #e53e3e;
|
||||
}
|
||||
|
||||
.mode-toggle {
|
||||
display: inline-flex;
|
||||
border: 1px solid #cbd5e0;
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.mode-btn {
|
||||
border: none;
|
||||
background: #edf2f7;
|
||||
color: #4a5568;
|
||||
padding: 0.45rem 0.8rem;
|
||||
font-size: 0.85rem;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.mode-btn + .mode-btn {
|
||||
border-left: 1px solid #cbd5e0;
|
||||
}
|
||||
|
||||
.mode-btn.active {
|
||||
background: #3182ce;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.editor-actions {
|
||||
display: flex;
|
||||
gap: 0.5rem;
|
||||
@@ -240,6 +347,21 @@ button,
|
||||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
.icon-btn {
|
||||
font-size: 1rem;
|
||||
line-height: 1;
|
||||
padding: 0.5rem 0.75rem;
|
||||
min-width: 40px;
|
||||
}
|
||||
|
||||
#run-btn.icon-btn {
|
||||
color: #2f855a;
|
||||
}
|
||||
|
||||
#stop-btn.icon-btn {
|
||||
color: #c53030;
|
||||
}
|
||||
|
||||
.editor-actions button:hover:not(:disabled) {
|
||||
background-color: #f7fafc;
|
||||
border-color: #cbd5e0;
|
||||
@@ -254,23 +376,6 @@ button,
|
||||
background-color: #edf2f7;
|
||||
}
|
||||
|
||||
.run-main-toggle {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.45rem;
|
||||
border: 1px solid #e2e8f0;
|
||||
border-radius: 6px;
|
||||
padding: 0.4rem 0.6rem;
|
||||
font-size: 0.85rem;
|
||||
color: #374151;
|
||||
background: white;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.run-main-toggle input[type="checkbox"] {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.editor-container {
|
||||
flex: 1;
|
||||
position: relative;
|
||||
@@ -375,7 +480,7 @@ button,
|
||||
font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
padding: 1rem;
|
||||
padding: 0;
|
||||
resize: none;
|
||||
}
|
||||
|
||||
@@ -386,6 +491,18 @@ button,
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
/* Pin line-number gutter hard to the left edge of the editor pane. */
|
||||
.cm-editor .cm-gutters {
|
||||
border-right: 1px solid #e2e8f0;
|
||||
background: #f7fafc;
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
.cm-editor .cm-content {
|
||||
padding-top: 0.5rem;
|
||||
padding-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.cm-focused {
|
||||
outline: none;
|
||||
}
|
||||
@@ -396,6 +513,15 @@ button,
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background: #0f172a;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.console-container.is-collapsed {
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.console-container.is-collapsed .console-output {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.led-sim-panel {
|
||||
@@ -481,11 +607,415 @@ button,
|
||||
box-shadow: inset 0 0 8px rgba(0, 0, 0, 0.45);
|
||||
}
|
||||
|
||||
.pin-panel {
|
||||
border-top: 1px solid #e2e8f0;
|
||||
background: #0b1220;
|
||||
color: #e5e7eb;
|
||||
padding: 0.55rem 0.75rem 0.7rem;
|
||||
}
|
||||
|
||||
.pin-panel.hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.pin-panel-header {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
justify-content: space-between;
|
||||
gap: 0.75rem;
|
||||
margin-bottom: 0.45rem;
|
||||
}
|
||||
|
||||
.pin-panel-title {
|
||||
font-size: 0.85rem;
|
||||
font-weight: 600;
|
||||
color: #f3f4f6;
|
||||
}
|
||||
|
||||
.pin-panel-hint {
|
||||
font-size: 0.7rem;
|
||||
color: #94a3b8;
|
||||
}
|
||||
|
||||
.pin-rows {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.35rem;
|
||||
max-height: 26vh;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.pin-row {
|
||||
display: grid;
|
||||
grid-template-columns: 70px 24px 56px 1fr 90px;
|
||||
align-items: center;
|
||||
gap: 0.55rem;
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
|
||||
.pin-row-label {
|
||||
color: #cbd5e1;
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
|
||||
.pin-led {
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
border-radius: 50%;
|
||||
background: #1e293b;
|
||||
border: 1px solid #334155;
|
||||
box-shadow: inset 0 0 4px rgba(0, 0, 0, 0.6);
|
||||
justify-self: center;
|
||||
}
|
||||
|
||||
.pin-led.on {
|
||||
background: #fde047;
|
||||
border-color: #facc15;
|
||||
box-shadow: 0 0 10px rgba(253, 224, 71, 0.7), inset 0 0 4px rgba(0, 0, 0, 0.25);
|
||||
}
|
||||
|
||||
.pin-toggle {
|
||||
appearance: none;
|
||||
border: 1px solid #334155;
|
||||
background: #1e293b;
|
||||
color: #e5e7eb;
|
||||
border-radius: 6px;
|
||||
padding: 0.2rem 0;
|
||||
font-family: 'SFMono-Regular', Menlo, monospace;
|
||||
font-size: 0.85rem;
|
||||
cursor: pointer;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.pin-toggle.on {
|
||||
background: #16a34a;
|
||||
border-color: #15803d;
|
||||
color: #f0fdf4;
|
||||
}
|
||||
|
||||
.pin-pwm-bar {
|
||||
position: relative;
|
||||
height: 10px;
|
||||
background: #1e293b;
|
||||
border-radius: 999px;
|
||||
border: 1px solid #334155;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.pin-pwm-fill {
|
||||
height: 100%;
|
||||
width: 0%;
|
||||
background: linear-gradient(90deg, #38bdf8, #818cf8);
|
||||
transition: width 80ms linear;
|
||||
}
|
||||
|
||||
.pin-row-detail {
|
||||
text-align: right;
|
||||
font-size: 0.72rem;
|
||||
color: #94a3b8;
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
|
||||
@media (max-width: 600px) {
|
||||
.pin-row {
|
||||
grid-template-columns: 60px 22px 50px 1fr 70px;
|
||||
gap: 0.4rem;
|
||||
font-size: 0.75rem;
|
||||
}
|
||||
.pin-row-detail {
|
||||
font-size: 0.68rem;
|
||||
}
|
||||
}
|
||||
|
||||
.adc-panel {
|
||||
border-top: 1px solid #e2e8f0;
|
||||
background: #0f172a;
|
||||
color: #e5e7eb;
|
||||
padding: 0.6rem 0.75rem 0.75rem;
|
||||
}
|
||||
|
||||
.adc-panel.hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.adc-panel-header {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
justify-content: space-between;
|
||||
gap: 0.75rem;
|
||||
margin-bottom: 0.45rem;
|
||||
}
|
||||
|
||||
.adc-panel-title {
|
||||
font-size: 0.85rem;
|
||||
font-weight: 600;
|
||||
letter-spacing: 0.02em;
|
||||
color: #f3f4f6;
|
||||
}
|
||||
|
||||
.adc-panel-hint {
|
||||
font-size: 0.72rem;
|
||||
color: #9ca3af;
|
||||
}
|
||||
|
||||
.adc-sliders {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.4rem;
|
||||
max-height: 32vh;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.adc-row {
|
||||
display: grid;
|
||||
grid-template-columns: 90px 1fr 130px;
|
||||
align-items: center;
|
||||
gap: 0.6rem;
|
||||
}
|
||||
|
||||
.adc-row-label {
|
||||
font-size: 0.8rem;
|
||||
color: #cbd5e1;
|
||||
}
|
||||
|
||||
.adc-slider {
|
||||
width: 100%;
|
||||
appearance: none;
|
||||
-webkit-appearance: none;
|
||||
height: 6px;
|
||||
background: #1e293b;
|
||||
border-radius: 999px;
|
||||
outline: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.adc-slider::-webkit-slider-thumb {
|
||||
-webkit-appearance: none;
|
||||
appearance: none;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
border-radius: 50%;
|
||||
background: #38bdf8;
|
||||
border: 2px solid #0f172a;
|
||||
cursor: grab;
|
||||
box-shadow: 0 0 0 1px rgba(56, 189, 248, 0.3);
|
||||
}
|
||||
|
||||
.adc-slider::-webkit-slider-thumb:active {
|
||||
cursor: grabbing;
|
||||
}
|
||||
|
||||
.adc-slider::-moz-range-thumb {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
border-radius: 50%;
|
||||
background: #38bdf8;
|
||||
border: 2px solid #0f172a;
|
||||
cursor: grab;
|
||||
}
|
||||
|
||||
.adc-readout {
|
||||
font-family: 'SFMono-Regular', Menlo, monospace;
|
||||
font-size: 0.78rem;
|
||||
color: #94a3b8;
|
||||
text-align: right;
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
|
||||
@media (max-width: 600px) {
|
||||
.adc-row {
|
||||
grid-template-columns: 1fr;
|
||||
gap: 0.25rem;
|
||||
padding-bottom: 0.25rem;
|
||||
border-bottom: 1px solid rgba(148, 163, 184, 0.15);
|
||||
}
|
||||
|
||||
.adc-row-label {
|
||||
font-size: 0.78rem;
|
||||
}
|
||||
|
||||
.adc-readout {
|
||||
text-align: left;
|
||||
}
|
||||
}
|
||||
|
||||
.serial-panel {
|
||||
border-top: 1px solid #e2e8f0;
|
||||
background: #0b1220;
|
||||
color: #e5e7eb;
|
||||
padding: 0.55rem 0.75rem 0.7rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.45rem;
|
||||
}
|
||||
|
||||
.serial-panel.hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.serial-header {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
gap: 0.6rem;
|
||||
}
|
||||
|
||||
.serial-title {
|
||||
font-size: 0.85rem;
|
||||
font-weight: 600;
|
||||
color: #f3f4f6;
|
||||
}
|
||||
|
||||
.serial-meta {
|
||||
font-size: 0.72rem;
|
||||
color: #94a3b8;
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
|
||||
.serial-clear {
|
||||
appearance: none;
|
||||
border: 1px solid #334155;
|
||||
background: #1e293b;
|
||||
color: #e5e7eb;
|
||||
padding: 0.15rem 0.55rem;
|
||||
border-radius: 6px;
|
||||
font-size: 0.72rem;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.serial-clear:hover {
|
||||
background: #243244;
|
||||
}
|
||||
|
||||
.serial-output {
|
||||
background: #020617;
|
||||
border: 1px solid #1e293b;
|
||||
border-radius: 6px;
|
||||
padding: 0.55rem 0.7rem;
|
||||
font-family: 'SFMono-Regular', Menlo, Consolas, monospace;
|
||||
font-size: 0.82rem;
|
||||
line-height: 1.4;
|
||||
height: 120px;
|
||||
max-height: 28vh;
|
||||
overflow-y: auto;
|
||||
white-space: pre-wrap;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
.serial-rx {
|
||||
color: #e2e8f0;
|
||||
}
|
||||
|
||||
.serial-tx {
|
||||
color: #34d399;
|
||||
}
|
||||
|
||||
.serial-form {
|
||||
display: flex;
|
||||
gap: 0.5rem;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.serial-input {
|
||||
flex: 1 1 auto;
|
||||
min-width: 0;
|
||||
background: #0f172a;
|
||||
border: 1px solid #334155;
|
||||
color: #f8fafc;
|
||||
padding: 0.4rem 0.6rem;
|
||||
border-radius: 6px;
|
||||
font-family: 'SFMono-Regular', Menlo, Consolas, monospace;
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
|
||||
.serial-input:focus {
|
||||
outline: none;
|
||||
border-color: #38bdf8;
|
||||
box-shadow: 0 0 0 2px rgba(56, 189, 248, 0.25);
|
||||
}
|
||||
|
||||
.serial-newline {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.25rem;
|
||||
font-size: 0.75rem;
|
||||
color: #cbd5e1;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.serial-send {
|
||||
appearance: none;
|
||||
border: 1px solid #1d4ed8;
|
||||
background: #2563eb;
|
||||
color: #fff;
|
||||
font-weight: 600;
|
||||
padding: 0.4rem 0.85rem;
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
font-size: 0.82rem;
|
||||
}
|
||||
|
||||
.serial-send:hover {
|
||||
background: #1d4ed8;
|
||||
}
|
||||
|
||||
@media (max-width: 600px) {
|
||||
.serial-output {
|
||||
height: 110px;
|
||||
font-size: 0.78rem;
|
||||
}
|
||||
|
||||
.serial-form {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.serial-input {
|
||||
flex: 1 1 100%;
|
||||
}
|
||||
|
||||
.serial-newline {
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
.serial-send {
|
||||
flex: 0 0 auto;
|
||||
margin-left: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.console-header {
|
||||
padding: 0.5rem 0.75rem;
|
||||
font-size: 0.85rem;
|
||||
color: #cbd5e1;
|
||||
border-bottom: 1px solid #1e293b;
|
||||
background: transparent;
|
||||
border-left: 0;
|
||||
border-right: 0;
|
||||
border-top: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
width: 100%;
|
||||
text-align: left;
|
||||
cursor: pointer;
|
||||
font-family: inherit;
|
||||
}
|
||||
|
||||
.console-header:hover {
|
||||
background: rgba(255, 255, 255, 0.04);
|
||||
}
|
||||
|
||||
.console-header .chevron {
|
||||
display: inline-block;
|
||||
transition: transform 0.15s ease;
|
||||
color: #94a3b8;
|
||||
}
|
||||
|
||||
.console-container.is-collapsed .console-header .chevron {
|
||||
transform: rotate(-90deg);
|
||||
}
|
||||
|
||||
.console-container.is-collapsed .console-header {
|
||||
border-bottom: 0;
|
||||
}
|
||||
|
||||
.console-output {
|
||||
@@ -574,6 +1104,13 @@ button,
|
||||
border-color: #2c5aa0;
|
||||
}
|
||||
|
||||
/* Desktop: hide the file browser when collapsed via the hamburger toggle. */
|
||||
@media (min-width: 769px) {
|
||||
.sidebar.is-collapsed {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
/* Responsive design */
|
||||
@media (max-width: 768px) {
|
||||
.container {
|
||||
@@ -638,51 +1175,53 @@ button,
|
||||
}
|
||||
|
||||
.editor-header {
|
||||
padding: 0.55rem 0.65rem;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.45rem;
|
||||
padding: 0.5rem 0.6rem;
|
||||
flex-wrap: nowrap;
|
||||
gap: 0.4rem;
|
||||
align-items: center;
|
||||
padding-top: max(0.55rem, env(safe-area-inset-top));
|
||||
padding-top: max(0.5rem, env(safe-area-inset-top));
|
||||
}
|
||||
|
||||
.file-info {
|
||||
flex: 1 1 auto;
|
||||
min-width: 0;
|
||||
gap: 0.5rem;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.4rem;
|
||||
flex-wrap: nowrap;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.file-info .runtime-hint {
|
||||
.save-status {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
#workspace-badge {
|
||||
font-size: 0.7rem;
|
||||
padding: 0.15rem 0.4rem;
|
||||
}
|
||||
|
||||
.mode-toggle {
|
||||
order: 3;
|
||||
}
|
||||
|
||||
.mode-btn {
|
||||
min-height: 36px;
|
||||
padding: 0.5rem 0.85rem;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
max-width: 8rem;
|
||||
}
|
||||
|
||||
.editor-actions {
|
||||
width: 100%;
|
||||
order: 4;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.4rem;
|
||||
flex: 0 0 auto;
|
||||
gap: 0.35rem;
|
||||
}
|
||||
|
||||
.editor-actions button {
|
||||
flex: 1 1 110px;
|
||||
.editor-actions .icon-btn {
|
||||
flex: 0 0 auto;
|
||||
font-size: 1.05rem;
|
||||
padding: 0.45rem 0.7rem;
|
||||
min-width: 40px;
|
||||
min-height: 40px;
|
||||
font-size: 0.95rem;
|
||||
}
|
||||
|
||||
.run-main-toggle {
|
||||
flex: 1 1 calc(50% - 0.4rem);
|
||||
.menu-toggle {
|
||||
min-height: 40px;
|
||||
font-size: 0.85rem;
|
||||
flex: 0 0 auto;
|
||||
padding: 0.45rem 0.55rem;
|
||||
}
|
||||
|
||||
.tabs {
|
||||
@@ -756,6 +1295,57 @@ button,
|
||||
}
|
||||
}
|
||||
|
||||
/* ADC / Pins / Serial: touch-friendly on phones + safe-area padding */
|
||||
@media (max-width: 768px) {
|
||||
.adc-panel,
|
||||
.pin-panel,
|
||||
.serial-panel {
|
||||
padding-left: max(0.75rem, env(safe-area-inset-left));
|
||||
padding-right: max(0.75rem, env(safe-area-inset-right));
|
||||
padding-bottom: max(0.65rem, env(safe-area-inset-bottom));
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
}
|
||||
|
||||
.adc-slider {
|
||||
min-height: 2.75rem;
|
||||
padding: 0.75rem 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.adc-slider::-webkit-slider-thumb {
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
}
|
||||
|
||||
.adc-slider::-moz-range-thumb {
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
}
|
||||
|
||||
.pin-toggle {
|
||||
min-height: 44px;
|
||||
min-width: 44px;
|
||||
padding: 0.35rem 0.45rem;
|
||||
}
|
||||
|
||||
.pin-led {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
}
|
||||
|
||||
.serial-send,
|
||||
.serial-clear {
|
||||
min-height: 44px;
|
||||
padding: 0.4rem 0.85rem;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.serial-input {
|
||||
min-height: 44px;
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
/* Hide drawer affordances entirely on desktop, even with [hidden] flipped off. */
|
||||
@media (min-width: 769px) {
|
||||
.sidebar-backdrop {
|
||||
|
||||
Reference in New Issue
Block a user