Spaces:
Running
Running
github-actions[bot] commited on
Commit Β·
490c735
1
Parent(s): 8594c9f
Deploy 89f5564
Browse filesThe composer chip was stealing the whole input
Source: https://github.com/WINTER4000/turingDNA/commit/89f55640721fd670b6f18460c232eaf6c79b590c
- dee/static/app.css +55 -11
- dee/static/cockpit.js +7 -2
- dee/static/index.html +6 -6
- tests/test_mobile_reach.py +12 -2
dee/static/app.css
CHANGED
|
@@ -7936,11 +7936,11 @@ body[data-ui="bench"] #navTuring { display: none; }
|
|
| 7936 |
display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
|
| 7937 |
padding: 9px 14px; border-bottom: 1px solid var(--line);
|
| 7938 |
background: var(--bg-raised); flex: 0 0 auto;
|
| 7939 |
-
/* Wrap, don't clip. The tools row
|
| 7940 |
-
|
| 7941 |
-
|
| 7942 |
-
|
| 7943 |
-
the
|
| 7944 |
/* Nothing escapes the header. `align-items: baseline` also mis-aligned
|
| 7945 |
the 11px hint against 24px buttons β the text sat low enough to look
|
| 7946 |
like it belonged to the row below. */
|
|
@@ -8339,13 +8339,20 @@ body[data-pe-full="1"] .pe-fullbar { display: flex; }
|
|
| 8339 |
to send, not as a notification about something that already happened. */
|
| 8340 |
.cp-selchip {
|
| 8341 |
display: flex; align-items: center; gap: 8px;
|
| 8342 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 8343 |
border: 1px solid var(--line-strong); border-radius: 75px;
|
| 8344 |
background: var(--bg-raised);
|
| 8345 |
font-family: var(--font-mono); font-size: 11px; color: var(--ink-soft);
|
| 8346 |
max-width: 100%;
|
| 8347 |
}
|
| 8348 |
.cp-selchip-t { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
|
|
|
|
|
|
|
|
| 8349 |
.cp-selchip-x {
|
| 8350 |
flex: 0 0 auto; width: 20px; height: 20px; margin-left: auto;
|
| 8351 |
display: grid; place-items: center;
|
|
@@ -8353,6 +8360,13 @@ body[data-pe-full="1"] .pe-fullbar { display: flex; }
|
|
| 8353 |
color: var(--ink-faint); font-size: 14px; line-height: 1; cursor: pointer;
|
| 8354 |
}
|
| 8355 |
.cp-selchip-x:hover { background: var(--bg-app); color: var(--ink); }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 8356 |
|
| 8357 |
/* βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 8358 |
THE STAGE β what the agent is doing, shown ON the workspace.
|
|
@@ -9123,15 +9137,35 @@ body[data-cockpit]:not([data-bench="open"]) .cockpit { top: 0; }
|
|
| 9123 |
|
| 9124 |
/* ββ composer βββββββββββββββββββββββββββββββββββββββββββββββββββββββββ */
|
| 9125 |
.cp-compose {
|
| 9126 |
-
flex
|
| 9127 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 9128 |
border: 1px solid var(--line-strong); border-radius: 22px;
|
| 9129 |
background: var(--bg-app);
|
| 9130 |
}
|
| 9131 |
.cp-compose:focus-within { border-color: var(--ink-soft); box-shadow: 0 0 0 3px var(--brand-ring); }
|
| 9132 |
.cp-compose textarea {
|
| 9133 |
flex: 1; resize: none; border: 0; border-radius: 0;
|
| 9134 |
-
padding: 8px 0; font: inherit; line-height: 1.45;
|
| 9135 |
background: none; color: var(--ink); font-family: inherit;
|
| 9136 |
/* The global `textarea { min-height: 160px }` above is for SEQUENCE
|
| 9137 |
boxes. It also hit the chat composer, which only set max-height: 160px
|
|
@@ -9160,6 +9194,16 @@ body[data-cockpit]:not([data-bench="open"]) .cockpit { top: 0; }
|
|
| 9160 |
color: var(--on-ink); font-size: 15px; line-height: 1;
|
| 9161 |
}
|
| 9162 |
.cp-send:hover { opacity: 0.86; }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 9163 |
|
| 9164 |
/* ββ Model picker, under the composer ββββββββββββββββββββββββββββββββββββ
|
| 9165 |
Deliberately quiet: it is a setting you touch rarely, sitting under the one
|
|
@@ -9309,7 +9353,7 @@ body[data-cockpit]:not([data-bench="open"]) .cockpit { top: 0; }
|
|
| 9309 |
reopen, which is why the rail felt like a modal. */
|
| 9310 |
body[data-cockpit="min"] .cp-transcript,
|
| 9311 |
body[data-cockpit="min"] .cp-meter { display: none; }
|
| 9312 |
-
body[data-cockpit="min"] .cp-compose { display:
|
| 9313 |
|
| 9314 |
/* A desktop rule pins the rail to top:0 when it's a full-height column
|
| 9315 |
beside the canvas. On a phone the rail is the BOTTOM half, so `bottom`
|
|
@@ -10155,7 +10199,7 @@ body.de-agent-run .dna-edit-actions { display: none; }
|
|
| 10155 |
slide-over: this is a bottom sheet again. */
|
| 10156 |
body[data-cockpit="min"] .cp-transcript,
|
| 10157 |
body[data-cockpit="min"] .cp-meter { display: none; }
|
| 10158 |
-
body[data-cockpit="min"] .cp-compose { display:
|
| 10159 |
body[data-cockpit="min"] .cp-head {
|
| 10160 |
writing-mode: horizontal-tb; height: auto;
|
| 10161 |
justify-content: space-between; padding: 12px 12px 8px; gap: 10px;
|
|
|
|
| 7936 |
display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
|
| 7937 |
padding: 9px 14px; border-bottom: 1px solid var(--line);
|
| 7938 |
background: var(--bg-raised); flex: 0 0 auto;
|
| 7939 |
+
/* Wrap, don't clip. The tools row wraps internally and the hint beside
|
| 7940 |
+
it yields first (see .pe-pane-hint), so a narrow pane costs a second
|
| 7941 |
+
row of buttons rather than a control sliced in half by the overflow
|
| 7942 |
+
below. Buttons themselves stay `flex: 0 0 auto` β one narrower than
|
| 7943 |
+
its own label is the bug this header already had once. */
|
| 7944 |
/* Nothing escapes the header. `align-items: baseline` also mis-aligned
|
| 7945 |
the 11px hint against 24px buttons β the text sat low enough to look
|
| 7946 |
like it belonged to the row below. */
|
|
|
|
| 8339 |
to send, not as a notification about something that already happened. */
|
| 8340 |
.cp-selchip {
|
| 8341 |
display: flex; align-items: center; gap: 8px;
|
| 8342 |
+
/* Spans both composer columns, so it sits ABOVE the input rather than
|
| 8343 |
+
beside it. `1 / -1` (not `span 2`) keeps it correct if a column is ever
|
| 8344 |
+
added. */
|
| 8345 |
+
grid-column: 1 / -1;
|
| 8346 |
+
margin: 0 0 6px; padding: 5px 6px 5px 11px;
|
| 8347 |
border: 1px solid var(--line-strong); border-radius: 75px;
|
| 8348 |
background: var(--bg-raised);
|
| 8349 |
font-family: var(--font-mono); font-size: 11px; color: var(--ink-soft);
|
| 8350 |
max-width: 100%;
|
| 8351 |
}
|
| 8352 |
.cp-selchip-t { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
| 8353 |
+
/* The range never shrinks: it is the part of the chip you cannot get from
|
| 8354 |
+
anywhere else on screen. The name above it yields instead. */
|
| 8355 |
+
.cp-selchip-n { flex: 0 0 auto; white-space: nowrap; color: var(--ink-faint); }
|
| 8356 |
.cp-selchip-x {
|
| 8357 |
flex: 0 0 auto; width: 20px; height: 20px; margin-left: auto;
|
| 8358 |
display: grid; place-items: center;
|
|
|
|
| 8360 |
color: var(--ink-faint); font-size: 14px; line-height: 1; cursor: pointer;
|
| 8361 |
}
|
| 8362 |
.cp-selchip-x:hover { background: var(--bg-app); color: var(--ink); }
|
| 8363 |
+
/* `[hidden]` is a UA rule (`display: none`) and loses to ANY author
|
| 8364 |
+
`display:` β including the `display: flex` above. So with nothing selected
|
| 8365 |
+
the chip kept its border and padding and rendered as a stray 19x12 pill
|
| 8366 |
+
inside the composer, permanently. Same class of bug that
|
| 8367 |
+
tests/test_hidden_attribute.py guards against; invisible to that test
|
| 8368 |
+
because this node is built in cockpit.js, not in index.html. */
|
| 8369 |
+
.cp-selchip[hidden] { display: none; }
|
| 8370 |
|
| 8371 |
/* βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 8372 |
THE STAGE β what the agent is doing, shown ON the workspace.
|
|
|
|
| 9137 |
|
| 9138 |
/* ββ composer βββββββββββββββββββββββββββββββββββββββββββββββββββββββββ */
|
| 9139 |
.cp-compose {
|
| 9140 |
+
/* GRID, not flex. The attached-region chip is a CHILD of this form, and
|
| 9141 |
+
under flex it became a third item on the SAME ROW as the textarea and
|
| 9142 |
+
the send button. A chip carrying a construct name runs ~340px wide and
|
| 9143 |
+
cannot shrink; the textarea is `flex: 1 1 0%`, so it absorbed the whole
|
| 9144 |
+
shortfall, collapsed to 0px, and shoved the send button 39px OUTSIDE
|
| 9145 |
+
the rounded border. Two columns plus an auto-placed full-width chip row
|
| 9146 |
+
mean the chip can never take the input's width away from it again.
|
| 9147 |
+
Auto-placement handles both states: with the chip display:none it is
|
| 9148 |
+
not a grid item, so the input and send sit on row 1 and no empty row
|
| 9149 |
+
is reserved. */
|
| 9150 |
+
flex: 0 0 auto;
|
| 9151 |
+
display: grid;
|
| 9152 |
+
grid-template-columns: minmax(0, 1fr) auto;
|
| 9153 |
+
align-items: end;
|
| 9154 |
+
column-gap: 6px;
|
| 9155 |
+
margin: 10px 12px 12px;
|
| 9156 |
+
/* Symmetric. This was `4px 4px 4px 16px` β 16px of inset on the left and
|
| 9157 |
+
4px on the right, which is what makes the bar read as lopsided. The
|
| 9158 |
+
text's 16px inset now comes from the textarea's own padding-left, so
|
| 9159 |
+
the shell can inset the chip and the send button equally on both
|
| 9160 |
+
sides. */
|
| 9161 |
+
padding: 5px;
|
| 9162 |
border: 1px solid var(--line-strong); border-radius: 22px;
|
| 9163 |
background: var(--bg-app);
|
| 9164 |
}
|
| 9165 |
.cp-compose:focus-within { border-color: var(--ink-soft); box-shadow: 0 0 0 3px var(--brand-ring); }
|
| 9166 |
.cp-compose textarea {
|
| 9167 |
flex: 1; resize: none; border: 0; border-radius: 0;
|
| 9168 |
+
padding: 8px 0 8px 11px; font: inherit; line-height: 1.45;
|
| 9169 |
background: none; color: var(--ink); font-family: inherit;
|
| 9170 |
/* The global `textarea { min-height: 160px }` above is for SEQUENCE
|
| 9171 |
boxes. It also hit the chat composer, which only set max-height: 160px
|
|
|
|
| 9194 |
color: var(--on-ink); font-size: 15px; line-height: 1;
|
| 9195 |
}
|
| 9196 |
.cp-send:hover { opacity: 0.86; }
|
| 9197 |
+
@media (min-width: 901px) {
|
| 9198 |
+
/* Matched to the textarea's one-line height. At 32px against a 34px input
|
| 9199 |
+
the bottoms aligned (align-items: end) but the tops did not, so the
|
| 9200 |
+
button sat 2px low in the pill β the other half of "asymmetric".
|
| 9201 |
+
This block sits AFTER `.cp-send` deliberately: same specificity, so the
|
| 9202 |
+
later rule is the one that wins. Written above the base rule first, it
|
| 9203 |
+
lost silently and the button stayed 32px. On a phone the 46px
|
| 9204 |
+
tap-target floor further down outranks this on purpose. */
|
| 9205 |
+
.cp-send { width: 34px; height: 34px; }
|
| 9206 |
+
}
|
| 9207 |
|
| 9208 |
/* ββ Model picker, under the composer ββββββββββββββββββββββββββββββββββββ
|
| 9209 |
Deliberately quiet: it is a setting you touch rarely, sitting under the one
|
|
|
|
| 9353 |
reopen, which is why the rail felt like a modal. */
|
| 9354 |
body[data-cockpit="min"] .cp-transcript,
|
| 9355 |
body[data-cockpit="min"] .cp-meter { display: none; }
|
| 9356 |
+
body[data-cockpit="min"] .cp-compose { display: grid; }
|
| 9357 |
|
| 9358 |
/* A desktop rule pins the rail to top:0 when it's a full-height column
|
| 9359 |
beside the canvas. On a phone the rail is the BOTTOM half, so `bottom`
|
|
|
|
| 10199 |
slide-over: this is a bottom sheet again. */
|
| 10200 |
body[data-cockpit="min"] .cp-transcript,
|
| 10201 |
body[data-cockpit="min"] .cp-meter { display: none; }
|
| 10202 |
+
body[data-cockpit="min"] .cp-compose { display: grid; }
|
| 10203 |
body[data-cockpit="min"] .cp-head {
|
| 10204 |
writing-mode: horizontal-tb; height: auto;
|
| 10205 |
justify-content: space-between; padding: 12px 12px 8px; gap: 10px;
|
dee/static/cockpit.js
CHANGED
|
@@ -1905,8 +1905,13 @@
|
|
| 1905 |
if (!el) return;
|
| 1906 |
if (!_sel) { el.hidden = true; el.innerHTML = ""; return; }
|
| 1907 |
el.hidden = false;
|
| 1908 |
-
|
| 1909 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1910 |
+ "\u2013" + _sel.to.toLocaleString()
|
| 1911 |
+ " (" + _sel.length.toLocaleString() + " bp)</span>"
|
| 1912 |
+ '<button type="button" class="cp-selchip-x" aria-label="Don\'t send this selection">\u00d7</button>';
|
|
|
|
| 1905 |
if (!el) return;
|
| 1906 |
if (!_sel) { el.hidden = true; el.innerHTML = ""; return; }
|
| 1907 |
el.hidden = false;
|
| 1908 |
+
// Name and coordinates are SEPARATE spans on purpose. As one string
|
| 1909 |
+
// the whole thing ellipsised from the right, so a long construct name
|
| 1910 |
+
// ate the coordinates β "pCambia2300-LUX6_-_SEB - 7,347-8,810 (1,464 bβ¦"
|
| 1911 |
+
// dropped the one part you cannot reconstruct from the editor title.
|
| 1912 |
+
// Now the name truncates and the range always survives.
|
| 1913 |
+
el.innerHTML = '<span class="cp-selchip-t">' + esc(_sel.name) + '</span>'
|
| 1914 |
+
+ '<span class="cp-selchip-n">' + _sel.from.toLocaleString()
|
| 1915 |
+ "\u2013" + _sel.to.toLocaleString()
|
| 1916 |
+ " (" + _sel.length.toLocaleString() + " bp)</span>"
|
| 1917 |
+ '<button type="button" class="cp-selchip-x" aria-label="Don\'t send this selection">\u00d7</button>';
|
dee/static/index.html
CHANGED
|
@@ -112,7 +112,7 @@
|
|
| 112 |
<!-- ?v= query bumps invalidate browser + iframe asset caches when app.css /
|
| 113 |
app.js change. Bump these numbers whenever you ship a frontend update β
|
| 114 |
without them, users keep getting the stale file for up to a week. -->
|
| 115 |
-
<link rel="stylesheet" href="/static/app.css?v=
|
| 116 |
<!-- The work catalog + the draggable rail. Kept out of app.css so two new
|
| 117 |
self-contained surfaces stay reviewable; every colour is an app.css
|
| 118 |
token, so both themes work with nothing added. -->
|
|
@@ -2394,7 +2394,7 @@
|
|
| 2394 |
<button class="pe-mapbtn pe-mapbtn--icon" type="button" id="peZoomIn" title="Zoom in" aria-label="Zoom in">+</button>
|
| 2395 |
<button class="pe-mapbtn" type="button" id="peZoomFit" title="Fit the whole map">Fit</button>
|
| 2396 |
<button class="pe-mapbtn" type="button" id="peZoomSel"
|
| 2397 |
-
title="Zoom the map to the selected region">
|
| 2398 |
<!-- The map draws unique cutters by
|
| 2399 |
default: an enzyme that cuts once is
|
| 2400 |
a cloning handle, one that cuts
|
|
@@ -3132,9 +3132,9 @@
|
|
| 3132 |
<!-- Cloning reference data must load before app.js so the Designer
|
| 3133 |
can read VECTORS / ENZYMES / CLONING_METHODS / TAGS / LINKERS. -->
|
| 3134 |
<script src="/static/cloning_db.js?v=20260530-ui-polish" defer></script>
|
| 3135 |
-
<script src="/static/context.js?v=
|
| 3136 |
-
<script src="/static/lineage.js?v=
|
| 3137 |
-
<script src="/static/app.js?v=
|
| 3138 |
<!-- The decision trace, BEFORE cockpit.js: applyEvent calls TDTrace.push
|
| 3139 |
on the very first event, and both are `defer`, so document order is
|
| 3140 |
load order. Loading it after would drop the opening events of a
|
|
@@ -3143,7 +3143,7 @@
|
|
| 3143 |
<!-- THE COCKPIT β the persistent orchestrator rail. Loads after app.js so
|
| 3144 |
TDBench/TDStructure exist when a tool result asks the workspace to
|
| 3145 |
render something. This is the only conversation surface in the app. -->
|
| 3146 |
-
<script src="/static/cockpit.js?v=
|
| 3147 |
<!-- structcard before catalog: the catalog calls TDStructCard.observe as
|
| 3148 |
soon as it paints. Both are defer, so document order is load order. -->
|
| 3149 |
<script src="/static/structcard.js?v=20260811-buildC" defer></script>
|
|
|
|
| 112 |
<!-- ?v= query bumps invalidate browser + iframe asset caches when app.css /
|
| 113 |
app.js change. Bump these numbers whenever you ship a frontend update β
|
| 114 |
without them, users keep getting the stale file for up to a week. -->
|
| 115 |
+
<link rel="stylesheet" href="/static/app.css?v=20260824-composer4" />
|
| 116 |
<!-- The work catalog + the draggable rail. Kept out of app.css so two new
|
| 117 |
self-contained surfaces stay reviewable; every colour is an app.css
|
| 118 |
token, so both themes work with nothing added. -->
|
|
|
|
| 2394 |
<button class="pe-mapbtn pe-mapbtn--icon" type="button" id="peZoomIn" title="Zoom in" aria-label="Zoom in">+</button>
|
| 2395 |
<button class="pe-mapbtn" type="button" id="peZoomFit" title="Fit the whole map">Fit</button>
|
| 2396 |
<button class="pe-mapbtn" type="button" id="peZoomSel"
|
| 2397 |
+
title="Zoom the map to the selected region">Selection</button>
|
| 2398 |
<!-- The map draws unique cutters by
|
| 2399 |
default: an enzyme that cuts once is
|
| 2400 |
a cloning handle, one that cuts
|
|
|
|
| 3132 |
<!-- Cloning reference data must load before app.js so the Designer
|
| 3133 |
can read VECTORS / ENZYMES / CLONING_METHODS / TAGS / LINKERS. -->
|
| 3134 |
<script src="/static/cloning_db.js?v=20260530-ui-polish" defer></script>
|
| 3135 |
+
<script src="/static/context.js?v=20260824-composer4" defer></script>
|
| 3136 |
+
<script src="/static/lineage.js?v=20260824-composer4" defer></script>
|
| 3137 |
+
<script src="/static/app.js?v=20260824-composer4" defer></script>
|
| 3138 |
<!-- The decision trace, BEFORE cockpit.js: applyEvent calls TDTrace.push
|
| 3139 |
on the very first event, and both are `defer`, so document order is
|
| 3140 |
load order. Loading it after would drop the opening events of a
|
|
|
|
| 3143 |
<!-- THE COCKPIT β the persistent orchestrator rail. Loads after app.js so
|
| 3144 |
TDBench/TDStructure exist when a tool result asks the workspace to
|
| 3145 |
render something. This is the only conversation surface in the app. -->
|
| 3146 |
+
<script src="/static/cockpit.js?v=20260824-composer4" defer></script>
|
| 3147 |
<!-- structcard before catalog: the catalog calls TDStructCard.observe as
|
| 3148 |
soon as it paints. Both are defer, so document order is load order. -->
|
| 3149 |
<script src="/static/structcard.js?v=20260811-buildC" defer></script>
|
tests/test_mobile_reach.py
CHANGED
|
@@ -194,8 +194,18 @@ def test_the_small_detent_is_a_working_state_not_a_closed_one():
|
|
| 194 |
Hiding the composer would turn it into a dead bar you can only reopen,
|
| 195 |
which is what made the rail feel like a modal."""
|
| 196 |
block = _all_phone_css(_read(_APP_CSS))
|
| 197 |
-
|
| 198 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 199 |
# and the transcript is what yields, not the head β the head carries the
|
| 200 |
# live status, so "Designing guidesβ¦" is readable at 132px.
|
| 201 |
assert 'body[data-cockpit="min"] .cp-transcript' in block
|
|
|
|
| 194 |
Hiding the composer would turn it into a dead bar you can only reopen,
|
| 195 |
which is what made the rail feel like a modal."""
|
| 196 |
block = _all_phone_css(_read(_APP_CSS))
|
| 197 |
+
# The guarantee is that the composer is still DISPLAYED at peek β not
|
| 198 |
+
# which layout mode it uses. It was `display: flex` until the attached-
|
| 199 |
+
# region chip was given its own row and the composer became a grid;
|
| 200 |
+
# pinning the mechanism made a correct change look like a regression.
|
| 201 |
+
# An author `display: none` here is the thing that would actually break
|
| 202 |
+
# peek, so that is what this asserts. Every occurrence, not the first:
|
| 203 |
+
# two phone blocks set this and `re.search` would only ever see one.
|
| 204 |
+
decls = re.findall(r'body\[data-cockpit="min"\] \.cp-compose \{([^}]*)\}', block)
|
| 205 |
+
assert decls, "peek must keep the composer"
|
| 206 |
+
for d in decls:
|
| 207 |
+
assert "display:" in d and "display: none" not in d, (
|
| 208 |
+
"peek must keep the composer visible, got: " + d.strip())
|
| 209 |
# and the transcript is what yields, not the head β the head carries the
|
| 210 |
# live status, so "Designing guidesβ¦" is readable at 132px.
|
| 211 |
assert 'body[data-cockpit="min"] .cp-transcript' in block
|