mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-10-08 16:39:42 +02:00
Merge pull request #368 from shenlvkang-collab/pr/mobile-add-case-submit
fix(mobile): give the Add Case modal a reachable submit button
This commit is contained in:
@@ -0,0 +1,16 @@
|
|||||||
|
---
|
||||||
|
"aicodeman": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
fix(mobile): give the Add Case modal a reachable submit button
|
||||||
|
|
||||||
|
`mobile.css` hides `#createCaseModal`'s `.set-foot` on phones, and unlike the Settings
|
||||||
|
modal that header carries no `set-head-save` — so the Create/Link button existed nowhere
|
||||||
|
on a phone and the modal could not be submitted at all. Adds the header button and drives
|
||||||
|
both together, so whichever one is pressed the other shows the same pending state and is
|
||||||
|
equally unclickable.
|
||||||
|
|
||||||
|
Add Case follows the Settings modal's header-save pattern, so it picks up the existing
|
||||||
|
`.set-head-actions:has(.set-head-save)` tray and `.set-head-save` sizing below 860px with no
|
||||||
|
new CSS; the `mobile.css` comment that still listed Add Case as a lone-× sheet is updated to
|
||||||
|
match.
|
||||||
@@ -2589,8 +2589,15 @@
|
|||||||
<div class="modal-content modal-lg set-shell">
|
<div class="modal-content modal-lg set-shell">
|
||||||
<div class="modal-header set-shell-head">
|
<div class="modal-header set-shell-head">
|
||||||
<h3>Add Case</h3>
|
<h3>Add Case</h3>
|
||||||
|
<!-- mobile.css hides this modal's .set-foot, so on a phone the footer's
|
||||||
|
Create/Link button is unreachable and the modal cannot be submitted
|
||||||
|
at all. Mirrors the Settings modal's header Save: close first in the
|
||||||
|
DOM so the focus trap still lands on it, row-reverse puts this to
|
||||||
|
its left. Both buttons are driven together by switchCaseModalTab()
|
||||||
|
and submitCaseModal(). -->
|
||||||
<div class="set-head-actions">
|
<div class="set-head-actions">
|
||||||
<button class="modal-close" onclick="app.closeCreateCaseModal()" aria-label="Close create case">×</button>
|
<button class="modal-close" onclick="app.closeCreateCaseModal()" aria-label="Close create case">×</button>
|
||||||
|
<button class="set-head-save" id="caseModalSubmitMobile" onclick="app.submitCaseModal()">Create</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="set-body">
|
<div class="set-body">
|
||||||
|
|||||||
@@ -3333,8 +3333,10 @@ html:is([data-skin="paper-gray"], [data-skin="solarized-light"], [data-skin="cat
|
|||||||
recessed tray and matching pill geometry instead of reading as a fat
|
recessed tray and matching pill geometry instead of reading as a fat
|
||||||
accent pill parked beside a stray × glyph. Tray colors come from skin
|
accent pill parked beside a stray × glyph. Tray colors come from skin
|
||||||
tokens, never a hardcoded black alpha, or the light skins get a grey slab.
|
tokens, never a hardcoded black alpha, or the light skins get a grey slab.
|
||||||
`:has()` keeps the tray off the two sheets that carry a lone × (Session
|
`:has()` keeps the tray off Session Options, the one sheet left carrying a
|
||||||
Options and Add Case save from inside their own forms). */
|
lone × because it saves from inside its own per-section forms. Add Case
|
||||||
|
now has a header save of its own (its footer is hidden below 860px, so
|
||||||
|
that button is the only way to submit it there), and picks up the tray. */
|
||||||
:is(#appSettingsModal, #sessionOptionsModal, #createCaseModal) .set-head-actions:has(.set-head-save) {
|
:is(#appSettingsModal, #sessionOptionsModal, #createCaseModal) .set-head-actions:has(.set-head-save) {
|
||||||
padding: 3px;
|
padding: 3px;
|
||||||
border: 1px solid var(--border);
|
border: 1px solid var(--border);
|
||||||
|
|||||||
@@ -2550,15 +2550,19 @@ Object.assign(CodemanApp.prototype, {
|
|||||||
// A switched-to panel starts at its own top.
|
// A switched-to panel starts at its own top.
|
||||||
const doc = document.getElementById('createCaseDoc');
|
const doc = document.getElementById('createCaseDoc');
|
||||||
if (doc) doc.scrollTop = 0;
|
if (doc) doc.scrollTop = 0;
|
||||||
// Update submit button (hide for manage tab)
|
// Update submit buttons (hide for manage tab). Two of them: mobile.css hides
|
||||||
const submitBtn = document.getElementById('caseModalSubmit');
|
// this modal's .set-foot, so phones submit through the header button instead.
|
||||||
|
const submitBtns = ['caseModalSubmit', 'caseModalSubmitMobile']
|
||||||
|
.map((id) => document.getElementById(id))
|
||||||
|
.filter(Boolean);
|
||||||
if (tabName === 'case-manage') {
|
if (tabName === 'case-manage') {
|
||||||
submitBtn.style.display = 'none';
|
submitBtns.forEach((btn) => {
|
||||||
|
btn.style.display = 'none';
|
||||||
|
});
|
||||||
this.renderCaseManageList();
|
this.renderCaseManageList();
|
||||||
this.refreshDockerExports();
|
this.refreshDockerExports();
|
||||||
} else {
|
} else {
|
||||||
submitBtn.style.display = '';
|
const label =
|
||||||
submitBtn.textContent =
|
|
||||||
tabName === 'case-create'
|
tabName === 'case-create'
|
||||||
? 'Create'
|
? 'Create'
|
||||||
: tabName === 'case-clone'
|
: tabName === 'case-clone'
|
||||||
@@ -2568,6 +2572,10 @@ Object.assign(CodemanApp.prototype, {
|
|||||||
: tabName === 'case-docker'
|
: tabName === 'case-docker'
|
||||||
? 'Link Docker'
|
? 'Link Docker'
|
||||||
: 'Link';
|
: 'Link';
|
||||||
|
submitBtns.forEach((btn) => {
|
||||||
|
btn.style.display = '';
|
||||||
|
btn.textContent = label;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
// Focus appropriate input
|
// Focus appropriate input
|
||||||
if (tabName === 'case-create') {
|
if (tabName === 'case-create') {
|
||||||
@@ -2588,14 +2596,19 @@ Object.assign(CodemanApp.prototype, {
|
|||||||
},
|
},
|
||||||
|
|
||||||
async submitCaseModal() {
|
async submitCaseModal() {
|
||||||
const btn = document.getElementById('caseModalSubmit');
|
// Both submit buttons move together: whichever one the user pressed, the
|
||||||
const originalText = btn.textContent;
|
// other must show the same pending state and be equally unclickable.
|
||||||
btn.classList.add('loading');
|
const btns = ['caseModalSubmit', 'caseModalSubmitMobile'].map((id) => document.getElementById(id)).filter(Boolean);
|
||||||
btn.textContent =
|
const originalText = btns.map((btn) => btn.textContent);
|
||||||
|
const pendingText =
|
||||||
this.caseModalTab === 'case-create' ? 'Creating...' : this.caseModalTab === 'case-clone' ? 'Cloning...' : 'Linking...';
|
this.caseModalTab === 'case-create' ? 'Creating...' : this.caseModalTab === 'case-clone' ? 'Cloning...' : 'Linking...';
|
||||||
// A clone holds this request open for minutes; without disabling the button a
|
// A clone holds this request open for minutes; without disabling the button a
|
||||||
// second click fires a second clone (the loser then fails on ALREADY_EXISTS).
|
// second click fires a second clone (the loser then fails on ALREADY_EXISTS).
|
||||||
btn.disabled = true;
|
btns.forEach((btn) => {
|
||||||
|
btn.classList.add('loading');
|
||||||
|
btn.textContent = pendingText;
|
||||||
|
btn.disabled = true;
|
||||||
|
});
|
||||||
try {
|
try {
|
||||||
if (this.caseModalTab === 'case-create') {
|
if (this.caseModalTab === 'case-create') {
|
||||||
await this.createCase();
|
await this.createCase();
|
||||||
@@ -2609,9 +2622,11 @@ Object.assign(CodemanApp.prototype, {
|
|||||||
await this.linkCase();
|
await this.linkCase();
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
btn.classList.remove('loading');
|
btns.forEach((btn, index) => {
|
||||||
btn.disabled = false;
|
btn.classList.remove('loading');
|
||||||
btn.textContent = originalText;
|
btn.disabled = false;
|
||||||
|
btn.textContent = originalText[index];
|
||||||
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user