fix(ui): keep the confirm dialog's OK button in line with the others (#6782)

* fix(ui): keep the confirm dialog's OK button in line with the others

#styled-confirm-ok was moved down 2px (position: relative; top: 2px), so
the OK button sat 2px below Cancel and the alternate button in every
styledConfirm dialog. Its label, and the alternate button's, now sit in a
span nudged the same way as the Cancel label, so the text keeps its place
and no button moves. Stylesheets and app.js get a new cache-bust token.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* refactor(ui): build confirm labels inline and share the Cancel nudge rule

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(cache): keep upstream's service worker cache name format

dev's editor tests require CACHE_NAME to match
odysseus-v<N>-pr40-editor-precache, so keep the version bump and use
that suffix.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
John W
2026-11-03 05:29:42 +00:00
committed by GitHub
co-authored by Claude Opus 5.5
parent 682662d36f
commit 77964b0025
5 changed files with 70 additions and 52 deletions
+2 -4
View File
@@ -6523,10 +6523,8 @@ body.bg-pattern-ascii-fireflies {
}
.confirm-btn-secondary { background:var(--bg); color:var(--fg); }
.confirm-btn-secondary:hover { background:var(--border); }
#styled-confirm-ok {
position: relative;
top: 2px;
}
#styled-confirm-ok .styled-confirm-btn-label,
#styled-confirm-alt .styled-confirm-btn-label,
#styled-confirm-cancel .styled-confirm-cancel-label {
position:relative;
top:2px;
+23 -23
View File
@@ -247,32 +247,32 @@
real request is discarded and the font fetched a second time. -->
<link rel="preload" as="font" type="font/woff2" crossorigin href="/static/fonts/FiraCode-Regular.woff2">
<link rel="preload" as="font" type="font/woff2" crossorigin href="/static/fonts/FiraCode-SemiBold.woff2">
<link rel="stylesheet" href="/static/css/00-tokens.css?v=20261008confirmwrap1">
<link rel="stylesheet" href="/static/css/01-agent-chat.css?v=20261008confirmwrap1">
<link rel="stylesheet" href="/static/css/02-compare.css?v=20261008confirmwrap1">
<link rel="stylesheet" href="/static/css/03-agent-chat.css?v=20261008confirmwrap1">
<link rel="stylesheet" href="/static/css/04-memory.css?v=20261008confirmwrap1">
<link rel="stylesheet" href="/static/css/05-documents.css?v=20261008confirmwrap1">
<link rel="stylesheet" href="/static/css/06-admin-settings.css?v=20261008confirmwrap1">
<link rel="stylesheet" href="/static/css/07-documents.css?v=20261008confirmwrap1">
<link rel="stylesheet" href="/static/css/08-skills.css?v=20261008confirmwrap1">
<link rel="stylesheet" href="/static/css/09-gallery.css?v=20261008confirmwrap1">
<link rel="stylesheet" href="/static/css/10-cookbook.css?v=20261008confirmwrap1">
<link rel="stylesheet" href="/static/css/11-tasks.css?v=20261008confirmwrap1">
<link rel="stylesheet" href="/static/css/12-gallery.css?v=20261008confirmwrap1">
<link rel="stylesheet" href="/static/css/13-image-editor.css?v=20261008confirmwrap1">
<link rel="stylesheet" href="/static/css/14-email.css?v=20261008confirmwrap1">
<link rel="stylesheet" href="/static/css/15-notes.css?v=20261008confirmwrap1">
<link rel="stylesheet" href="/static/css/16-calendar.css?v=20261008confirmwrap1">
<link rel="stylesheet" href="/static/css/17-research.css?v=20261008confirmwrap1">
<link rel="stylesheet" href="/static/css/00-tokens.css?v=20261021confirmalign1">
<link rel="stylesheet" href="/static/css/01-agent-chat.css?v=20261021confirmalign1">
<link rel="stylesheet" href="/static/css/02-compare.css?v=20261021confirmalign1">
<link rel="stylesheet" href="/static/css/03-agent-chat.css?v=20261021confirmalign1">
<link rel="stylesheet" href="/static/css/04-memory.css?v=20261021confirmalign1">
<link rel="stylesheet" href="/static/css/05-documents.css?v=20261021confirmalign1">
<link rel="stylesheet" href="/static/css/06-admin-settings.css?v=20261021confirmalign1">
<link rel="stylesheet" href="/static/css/07-documents.css?v=20261021confirmalign1">
<link rel="stylesheet" href="/static/css/08-skills.css?v=20261021confirmalign1">
<link rel="stylesheet" href="/static/css/09-gallery.css?v=20261021confirmalign1">
<link rel="stylesheet" href="/static/css/10-cookbook.css?v=20261021confirmalign1">
<link rel="stylesheet" href="/static/css/11-tasks.css?v=20261021confirmalign1">
<link rel="stylesheet" href="/static/css/12-gallery.css?v=20261021confirmalign1">
<link rel="stylesheet" href="/static/css/13-image-editor.css?v=20261021confirmalign1">
<link rel="stylesheet" href="/static/css/14-email.css?v=20261021confirmalign1">
<link rel="stylesheet" href="/static/css/15-notes.css?v=20261021confirmalign1">
<link rel="stylesheet" href="/static/css/16-calendar.css?v=20261021confirmalign1">
<link rel="stylesheet" href="/static/css/17-research.css?v=20261021confirmalign1">
<!-- Panel stylesheets split out of style.css for maintainability. They are
eager and their order is load-bearing: the cascade is the concatenation of
these files in this order, so they must stay in this order here and in the
PRECACHE list in sw.js. None of them is lazy-loaded. -->
<link rel="stylesheet" href="/static/css/documents-gallery-editor.css?v=20261008confirmwrap1">
<link rel="stylesheet" href="/static/css/email-calendar-notes-tasks.css?v=20261008confirmwrap1">
<link rel="stylesheet" href="/static/css/cookbook-research-memory-settings.css?v=20261008confirmwrap1">
<link rel="modulepreload" href="/static/app.js?v=20261008confirmwrap1">
<link rel="stylesheet" href="/static/css/documents-gallery-editor.css?v=20261021confirmalign1">
<link rel="stylesheet" href="/static/css/email-calendar-notes-tasks.css?v=20261021confirmalign1">
<link rel="stylesheet" href="/static/css/cookbook-research-memory-settings.css?v=20261021confirmalign1">
<link rel="modulepreload" href="/static/app.js?v=20261021confirmalign1">
<link rel="modulepreload" href="/static/js/chat.js?v=20260917toolttft1">
<link rel="modulepreload" href="/static/js/ui.js?v=20260916largetoolscroll1">
<link rel="modulepreload" href="/static/js/sessions.js">
@@ -2709,7 +2709,7 @@
<script type="module" src="/static/js/censor.js"></script>
<script type="module" src="/static/js/settings.js?v=20260912writingstyle3"></script>
<script type="module" src="/static/js/assistant.js?v=20260912firefoxjscleanup1"></script>
<script type="module" src="/static/app.js?v=20261008confirmwrap1"></script> <!-- app.js must be LAST -->
<script type="module" src="/static/app.js?v=20261021confirmalign1"></script> <!-- app.js must be LAST -->
<script type="module" src="/static/js/init.js?v=20260829chatstyle12"></script>
<script type="module" src="/static/js/a11y.js"></script>
<script nonce="{{CSP_NONCE}}">if('serviceWorker' in navigator){navigator.serviceWorker.register('/static/sw.js?v=20260916autoscroll1').catch(()=>{});}</script>
+4 -2
View File
@@ -776,14 +776,16 @@ export function styledConfirm(message, { confirmText = 'Confirm', cancelText = '
if (titleEl) titleEl.textContent = title || 'Confirm';
msgEl.textContent = message;
// Labels sit in spans so CSS can nudge the text without moving the button.
const btnLabel = (text) => Object.assign(document.createElement('span'), { className: 'styled-confirm-btn-label', textContent: text });
// Use the affirmative label consistently for generic confirmations.
okBtn.textContent = confirmText === 'OK' ? 'Yes' : confirmText;
okBtn.replaceChildren(btnLabel(confirmText === 'OK' ? 'Yes' : confirmText));
cancelBtn.textContent = '';
const cancelLabel = document.createElement('span');
cancelLabel.className = 'styled-confirm-cancel-label';
cancelLabel.textContent = cancelText;
cancelBtn.appendChild(cancelLabel);
altBtn.textContent = alternateText || '';
altBtn.replaceChildren(btnLabel(alternateText || ''));
okBtn.className = danger ? 'confirm-btn confirm-btn-danger' : 'confirm-btn confirm-btn-primary';
cancelBtn.className = 'confirm-btn confirm-btn-secondary';
altBtn.className = 'confirm-btn confirm-btn-secondary';
+23 -23
View File
@@ -7,7 +7,7 @@
// - Other static assets (images/fonts/libs): cache-first with bg refresh.
// - API / non-GET: never cached.
// Bump CACHE_NAME whenever the precache list or SW logic changes.
const CACHE_NAME = 'odysseus-v1136-pr40-editor-precache';
const CACHE_NAME = 'odysseus-v1137-pr40-editor-precache';
// KaTeX resolves these from its own stylesheet, so caching the CSS without them
// gives offline math fallback glyphs instead of proper typesetting.
@@ -41,28 +41,28 @@ const PRECACHE = [
'/static/js/modalVisibility.js',
'/static/js/compare/sse.js',
'/',
'/static/css/00-tokens.css?v=20261008confirmwrap1',
'/static/css/01-agent-chat.css?v=20261008confirmwrap1',
'/static/css/02-compare.css?v=20261008confirmwrap1',
'/static/css/03-agent-chat.css?v=20261008confirmwrap1',
'/static/css/04-memory.css?v=20261008confirmwrap1',
'/static/css/05-documents.css?v=20261008confirmwrap1',
'/static/css/06-admin-settings.css?v=20261008confirmwrap1',
'/static/css/07-documents.css?v=20261008confirmwrap1',
'/static/css/08-skills.css?v=20261008confirmwrap1',
'/static/css/09-gallery.css?v=20261008confirmwrap1',
'/static/css/10-cookbook.css?v=20261008confirmwrap1',
'/static/css/11-tasks.css?v=20261008confirmwrap1',
'/static/css/12-gallery.css?v=20261008confirmwrap1',
'/static/css/13-image-editor.css?v=20261008confirmwrap1',
'/static/css/14-email.css?v=20261008confirmwrap1',
'/static/css/15-notes.css?v=20261008confirmwrap1',
'/static/css/16-calendar.css?v=20261008confirmwrap1',
'/static/css/17-research.css?v=20261008confirmwrap1',
'/static/css/documents-gallery-editor.css?v=20261008confirmwrap1',
'/static/css/email-calendar-notes-tasks.css?v=20261008confirmwrap1',
'/static/css/cookbook-research-memory-settings.css?v=20261008confirmwrap1',
'/static/app.js?v=20261008confirmwrap1',
'/static/css/00-tokens.css?v=20261021confirmalign1',
'/static/css/01-agent-chat.css?v=20261021confirmalign1',
'/static/css/02-compare.css?v=20261021confirmalign1',
'/static/css/03-agent-chat.css?v=20261021confirmalign1',
'/static/css/04-memory.css?v=20261021confirmalign1',
'/static/css/05-documents.css?v=20261021confirmalign1',
'/static/css/06-admin-settings.css?v=20261021confirmalign1',
'/static/css/07-documents.css?v=20261021confirmalign1',
'/static/css/08-skills.css?v=20261021confirmalign1',
'/static/css/09-gallery.css?v=20261021confirmalign1',
'/static/css/10-cookbook.css?v=20261021confirmalign1',
'/static/css/11-tasks.css?v=20261021confirmalign1',
'/static/css/12-gallery.css?v=20261021confirmalign1',
'/static/css/13-image-editor.css?v=20261021confirmalign1',
'/static/css/14-email.css?v=20261021confirmalign1',
'/static/css/15-notes.css?v=20261021confirmalign1',
'/static/css/16-calendar.css?v=20261021confirmalign1',
'/static/css/17-research.css?v=20261021confirmalign1',
'/static/css/documents-gallery-editor.css?v=20261021confirmalign1',
'/static/css/email-calendar-notes-tasks.css?v=20261021confirmalign1',
'/static/css/cookbook-research-memory-settings.css?v=20261021confirmalign1',
'/static/app.js?v=20261021confirmalign1',
'/static/js/storage.js',
'/static/js/appConfig.js',
'/static/js/ui.js?v=20260916largetoolscroll1',
+18
View File
@@ -58,6 +58,24 @@ def test_styled_confirm_cancel_or_close_label_is_shifted_without_moving_button()
assert "top:2px;" in rule
def test_styled_confirm_ok_and_alternate_labels_shift_without_moving_buttons():
# Moving #styled-confirm-ok itself (position:relative; top:2px) left it 2px
# below Cancel and the alternate button. The OK and alternate labels get the
# same label nudge as Cancel instead, and no rule moves a footer button.
css = app_css()
assert "okBtn.replaceChildren(btnLabel(" in _UI
assert "altBtn.replaceChildren(btnLabel(" in _UI
rule_start = css.index("#styled-confirm-ok .styled-confirm-btn-label")
rule = css[rule_start:css.index("}", rule_start)]
assert "#styled-confirm-alt .styled-confirm-btn-label" in rule
assert "position:relative;" in rule and "top:2px;" in rule
for selector in ("#styled-confirm-ok {", "#styled-confirm-alt {", "#styled-confirm-cancel {"):
if selector in css:
block = css[css.index(selector):].split("}", 1)[0]
assert "top:" not in block.replace(" ", ""), selector
def test_styled_confirm_buttons_grow_to_fit_wrapped_labels():
# The global `button { height:32px }` held a two-line label (e.g.
# "Delete chat and images") to one line's height, so its second line