mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-09-30 12:39:42 +02:00
fix(mobile,respawn-ui): unbury the session-options modal on phones; regroup the Respawn tab
Mobile fixes (user-reported: stuck in Session Options with no way to close): - Modals now stack at z-index 1300, above the fixed mobile/tablet header (z-index 1200) that was burying the modal header and its close button — the full-screen modal was undismissable on phones - Duration presets collapse to one compact 24px row (was a 3-row grid) - Hide the tab detach (open-in-new-window) button on viewports <=768px Respawn tab regrouped so its two features read as separate options: - New green-tinted "Respawn loop" box wraps duration, presets, cycle steps, and the status/Enable row — a visual sibling of the blue auto-resume box; includes a short explanation of the loop - Enable/status row moved from the top of the tab to the bottom of the box, so it no longer reads as a modal-level confirm button - Font sizes unified: feature titles match; step checkboxes (2./3.) match the step labels (1./4.); "Respawn Cycle" renamed "Cycle Steps" CLAUDE.md: add usage-limit-patterns.ts to the Session row; app.js ~3.7K Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -129,7 +129,7 @@ Codeman is a Claude Code session manager with web interface and autonomous Ralph
|
||||
| **Infra** | `src/hooks-config.ts`, `src/push-store.ts`, `src/tunnel-manager.ts`, `src/image-watcher.ts`, `src/file-stream-manager.ts` | |
|
||||
| **Plan** | `src/plan-orchestrator.ts`, `src/prompts/*.ts`, `src/templates/` (`claude-md.ts` + `case-template.md`, the CLAUDE.md scaffold generated into new cases) | |
|
||||
| **Web** | `src/web/server.ts` ★, `src/web/sse-events.ts`, `src/web/routes/*.ts` (15 route modules + barrel; `session-routes.ts` ★), `src/web/route-helpers.ts`, `src/web/ports/*.ts`, `src/web/middleware/auth.ts`, `src/web/schemas.ts`, `src/web/self-update.ts` | |
|
||||
| **Frontend** | `src/web/public/app.js` (~3.6K lines, core) + 5 infra modules (`constants.js`, `mobile-handlers.js`, `voice-input.js`, `notification-manager.js`, `keyboard-accessory.js`) + 7 domain modules (`terminal-ui.js`, `respawn-ui.js`, `ralph-panel.js`, `orchestrator-panel.js`, `settings-ui.js`, `panels-ui.js`, `session-ui.js`) + 5 feature modules (`ralph-wizard.js`, `api-client.js`, `subagent-windows.js`, `input-cjk.js`, `image-input.js`) + `sw.js` | |
|
||||
| **Frontend** | `src/web/public/app.js` (~3.7K lines, core) + 5 infra modules (`constants.js`, `mobile-handlers.js`, `voice-input.js`, `notification-manager.js`, `keyboard-accessory.js`) + 7 domain modules (`terminal-ui.js`, `respawn-ui.js`, `ralph-panel.js`, `orchestrator-panel.js`, `settings-ui.js`, `panels-ui.js`, `session-ui.js`) + 5 feature modules (`ralph-wizard.js`, `api-client.js`, `subagent-windows.js`, `input-cjk.js`, `image-input.js`) + `sw.js` | |
|
||||
| **Types** | `src/types/index.ts` (barrel) → 15 domain files; also `src/types.ts` root re-export | See `@fileoverview` in index.ts |
|
||||
|
||||
★ = Large, central file (>50KB) — read its `@fileoverview` first. All files have `@fileoverview` JSDoc — read that before diving in. Discovery aid: `grep -l '@fileoverview' src/web/routes/*.ts` lists all route modules; same grep works for `src/types/`, `src/web/public/*.js`.
|
||||
|
||||
+17
-12
@@ -604,17 +604,6 @@
|
||||
<div class="modal-tab-content" id="respawn-tab">
|
||||
<!-- Respawn Settings Section -->
|
||||
<div class="session-respawn-section" id="sessionRespawnSection">
|
||||
<div class="respawn-header">
|
||||
<div class="session-respawn-status" id="sessionRespawnStatus">
|
||||
<span class="respawn-status-indicator"></span>
|
||||
<span class="respawn-status-text">Not active</span>
|
||||
</div>
|
||||
<div class="respawn-actions">
|
||||
<button class="btn-toolbar btn-success btn-sm" onclick="app.enableRespawnFromModal()" id="modalEnableRespawnBtn">Enable</button>
|
||||
<button class="btn-toolbar btn-danger btn-sm" onclick="app.stopRespawnFromModal()" id="modalStopRespawnBtn" style="display: none;">Stop</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="auto-resume-box">
|
||||
<label class="checkbox-inline">
|
||||
<input type="checkbox" id="modalAutoResumeEnabled" onchange="app.autoSaveAutoResume()">
|
||||
@@ -624,6 +613,10 @@
|
||||
<span class="form-hint">If Claude pauses on a usage limit ("limit reached · resets 3pm"), Codeman waits for the reset time and automatically continues the work. Independent of the respawn loop below.</span>
|
||||
</div>
|
||||
|
||||
<div class="respawn-loop-box">
|
||||
<div class="respawn-loop-title">Respawn loop</div>
|
||||
<span class="form-hint respawn-loop-hint">One autonomous work cycle: whenever Claude goes idle, Codeman sends the update prompt, optionally runs /clear + /init, and kickstarts the next round — repeating for the chosen duration. All settings below belong to this loop; configure them, then press Enable.</span>
|
||||
|
||||
<div class="form-row">
|
||||
<label>Duration</label>
|
||||
<div class="duration-presets">
|
||||
@@ -660,7 +653,7 @@
|
||||
<p class="form-hint" id="presetDescriptionHint"></p>
|
||||
</div>
|
||||
|
||||
<div class="form-section-header">Respawn Cycle</div>
|
||||
<div class="form-section-header">Cycle Steps</div>
|
||||
<div class="form-row">
|
||||
<label>1. Update Prompt</label>
|
||||
<textarea id="modalRespawnPrompt" rows="1" placeholder="Prompt to send when idle" onchange="app.autoSaveRespawnConfig()" style="resize: vertical; min-height: 30px;">update all the docs and CLAUDE.md</textarea>
|
||||
@@ -686,6 +679,18 @@
|
||||
<textarea id="modalRespawnKickstart" rows="1" placeholder="Optional: prompt if /init doesn't trigger work" onchange="app.autoSaveRespawnConfig()" style="resize: vertical; min-height: 30px;"></textarea>
|
||||
<span class="form-hint">Sent only when /init completes but Claude stays idle · Auto-accept presses Enter for plan approvals and default options</span>
|
||||
</div>
|
||||
|
||||
<div class="respawn-header">
|
||||
<div class="session-respawn-status" id="sessionRespawnStatus">
|
||||
<span class="respawn-status-indicator"></span>
|
||||
<span class="respawn-status-text">Not active</span>
|
||||
</div>
|
||||
<div class="respawn-actions">
|
||||
<button class="btn-toolbar btn-success btn-sm" onclick="app.enableRespawnFromModal()" id="modalEnableRespawnBtn">Enable</button>
|
||||
<button class="btn-toolbar btn-danger btn-sm" onclick="app.stopRespawnFromModal()" id="modalStopRespawnBtn" style="display: none;">Stop</button>
|
||||
</div>
|
||||
</div>
|
||||
</div><!-- End respawn-loop-box -->
|
||||
</div>
|
||||
</div><!-- End respawn-tab -->
|
||||
|
||||
|
||||
+42
-18
@@ -36,6 +36,13 @@ html.mobile-init .file-browser-panel {
|
||||
html {
|
||||
touch-action: manipulation;
|
||||
}
|
||||
|
||||
/* No "open in new window" (detach) on phones/tablets — popped-out browser
|
||||
windows aren't usable there. !important beats the hover/detached reveal
|
||||
rules in styles.css */
|
||||
.session-tab .tab-detach {
|
||||
display: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
/* ============================================================================
|
||||
@@ -200,6 +207,12 @@ html.mobile-init .file-browser-panel {
|
||||
|
||||
/* ---- Settings Modal: Tablet Optimizations ---- */
|
||||
|
||||
/* Modals must stack above the fixed tablet header (z-index 1200) so the
|
||||
modal header with the close button stays visible */
|
||||
.modal {
|
||||
z-index: 1300;
|
||||
}
|
||||
|
||||
.modal-tabs {
|
||||
overflow-x: auto;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
@@ -1215,6 +1228,13 @@ html.mobile-init .file-browser-panel {
|
||||
max-height: 35vh;
|
||||
}
|
||||
|
||||
/* Modals must stack above the fixed mobile header (z-index 1200), or the
|
||||
modal header with the close button is buried underneath it and the
|
||||
full-screen modal cannot be dismissed */
|
||||
.modal {
|
||||
z-index: 1300;
|
||||
}
|
||||
|
||||
/* Full-screen modals on phones */
|
||||
.modal-content {
|
||||
width: 100%;
|
||||
@@ -1528,42 +1548,36 @@ html.mobile-init .file-browser-panel {
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
/* Duration preset buttons — grid layout, 4 columns for even spacing */
|
||||
/* Duration preset buttons — one compact row */
|
||||
.duration-presets {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.2rem;
|
||||
}
|
||||
|
||||
.duration-preset-btn {
|
||||
min-height: 32px;
|
||||
padding: 0.2rem 0.25rem;
|
||||
font-size: 0.65rem;
|
||||
border-radius: 5px;
|
||||
min-height: 24px;
|
||||
padding: 0.1rem 0.4rem;
|
||||
font-size: 0.6rem;
|
||||
border-radius: 4px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/* Custom duration — spans full row below */
|
||||
.duration-custom {
|
||||
grid-column: 1 / -1;
|
||||
display: flex;
|
||||
gap: 0.25rem;
|
||||
gap: 0.2rem;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.duration-custom .duration-preset-btn {
|
||||
flex: 0 0 auto;
|
||||
min-width: 50px;
|
||||
}
|
||||
|
||||
.duration-custom-input.visible {
|
||||
flex: 1;
|
||||
flex: 0 1 auto;
|
||||
}
|
||||
|
||||
.duration-custom-input input {
|
||||
width: 100%;
|
||||
min-height: 28px;
|
||||
width: 64px;
|
||||
min-height: 24px;
|
||||
font-size: 16px; /* Prevents iOS zoom */
|
||||
padding: 0.1rem 0.3rem;
|
||||
}
|
||||
|
||||
/* Preset selector row — full-width dropdown, buttons below */
|
||||
@@ -1622,6 +1636,16 @@ html.mobile-init .file-browser-panel {
|
||||
height: 18px;
|
||||
}
|
||||
|
||||
/* Respawn-loop box title matches the auto-resume title; its cycle-step
|
||||
checkboxes match the step labels */
|
||||
#sessionOptionsModal .respawn-loop-title {
|
||||
font-size: 0.75rem;
|
||||
}
|
||||
|
||||
#sessionOptionsModal .respawn-loop-box .checkbox-inline {
|
||||
font-size: 0.65rem;
|
||||
}
|
||||
|
||||
/* Respawn options row — stack if needed */
|
||||
#sessionOptionsModal .respawn-options-row {
|
||||
gap: 0.5rem;
|
||||
|
||||
@@ -4645,15 +4645,16 @@ body.solo-mode .btn-lifecycle-log {
|
||||
width: 60px;
|
||||
}
|
||||
|
||||
/* Respawn header with status and actions */
|
||||
/* Respawn status + Enable/Stop row — sits at the bottom of the Respawn tab,
|
||||
below the settings it acts on */
|
||||
.respawn-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 1rem;
|
||||
margin-bottom: 0.75rem;
|
||||
padding-bottom: 0.75rem;
|
||||
border-bottom: 1px solid var(--border);
|
||||
margin-top: 0.75rem;
|
||||
padding-top: 0.75rem;
|
||||
border-top: 1px solid rgba(34, 197, 94, 0.2);
|
||||
}
|
||||
|
||||
.respawn-header .respawn-actions {
|
||||
@@ -4692,6 +4693,39 @@ body.solo-mode .btn-lifecycle-log {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
/* Respawn loop box — groups every setting that belongs to the autonomous
|
||||
respawn cycle (duration, presets, cycle prompts, enable). Green like its
|
||||
Enable button; a visual sibling of the standalone auto-resume option above */
|
||||
.respawn-loop-box {
|
||||
margin: 0.75rem 0;
|
||||
padding: 0.6rem 0.75rem;
|
||||
background: rgba(34, 197, 94, 0.05);
|
||||
border: 1px solid rgba(34, 197, 94, 0.3);
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.respawn-loop-title {
|
||||
font-size: 0.85rem;
|
||||
font-weight: 500;
|
||||
color: var(--text);
|
||||
margin-bottom: 0.3rem;
|
||||
}
|
||||
|
||||
.respawn-loop-hint {
|
||||
display: block;
|
||||
margin-top: 0;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.respawn-loop-box .form-section-header {
|
||||
border-bottom-color: rgba(34, 197, 94, 0.2);
|
||||
}
|
||||
|
||||
/* Match the cycle-step checkboxes (2./3.) to the step labels (1./4.) */
|
||||
.respawn-loop-box .checkbox-inline {
|
||||
font-size: 0.7rem;
|
||||
}
|
||||
|
||||
.auto-resume-status {
|
||||
display: none;
|
||||
font-size: 0.7rem;
|
||||
|
||||
Reference in New Issue
Block a user