cc23b76a1f2c7dc6a29c227661bfb0ce4d20eb54 lrnassar Fri Sep 4 13:43:48 2026 -0700 BLAT page polish from QA: Load example button, corrected input limits, wording fixes. refs #37996 Load example is a chip-style button with a mouseover instead of a hyperlink. Removed the Show input limits modal; corrected the limits in hgTracksHelp.html, stale since 2013 (DNA is 75,000 bases per sequence and 187,500 combined, protein and translated 10,000 and 25,000), added a #blatLimits anchor and pointed the two over-limit BLAT warnings and the form at it. Genome selector: section title Target assembly, type-to-search hint in the dropdown, Shortcuts: label, input and Query type select sized to match. Similar tools sidebar uses house-style hyphens and corrects the findMotif name and description. Share and rename text now states link lifetimes accurately (snapshot links last years, only sessions are permanent). Alignment page buttons match .gbPill, summary strip spacing fixed, New BLAT search button demoted from primary. Documents blatResultsGroup in ex.hg.conf. diff --git src/hg/js/utils.js src/hg/js/utils.js index 5234d6df826..5f27b64a1fd 100644 --- src/hg/js/utils.js +++ src/hg/js/utils.js @@ -5236,52 +5236,55 @@ // The suggestions themselves come from exactly where they did before: recent genomes from // localStorage, popular ones from the JSON printGenomeSearchBar embeds, and everything else from // hubApi/findGenome via processFindGenome. var genomeSelectorStyleDone = false; function genomeSelectorInjectStyle() { /* One stylesheet for every selector on the page; injected rather than added to HGStyle.css so * the component is self-contained and can be dropped into a CGI without a second edit. */ if (genomeSelectorStyleDone) { return; } genomeSelectorStyleDone = true; var css = ` .gsWrap { position:relative; max-width:620px; } .gsField { display:flex; align-items:stretch; border:1px solid #9aa6b2; background:#fff; } .gsField.gsFocus { border-color:#14487f; box-shadow:0 0 0 2px rgba(20,72,127,0.18); } - .gsField input[type=text] { flex:1; min-width:0; border:0; outline:none; padding:11px 12px; - font-size:16px; font-family:inherit; color:#23303f; background:transparent; } + .gsField input[type=text] { flex:1; min-width:0; border:0; outline:none; padding:9px 12px; + font-size:15px; font-family:inherit; color:#23303f; background:transparent; } .gsCaret { border:0; border-left:1px solid #dbe1e7; background:#f4f7f9; width:42px; display:flex; align-items:center; justify-content:center; cursor:pointer; color:#14487f; } .gsCaret:hover { background:#e7edf2; } .gsMenu { position:absolute; z-index:20; top:calc(100% + 4px); left:0; right:0; background:#fff; border:1px solid #c3ccd5; box-shadow:0 8px 24px rgba(20,40,70,0.16); max-height:296px; overflow:auto; display:none; } .gsMenu.gsOpen { display:block; } /* Tighter than the design's spacing: the mockup shows five rows, the real list runs to fifteen * or more, so the padding that reads as comfortable there turns into a lot of scrolling here. * Trimming the vertical padding fits roughly a third more rows in the same panel. */ .gsHead { padding:3px 12px; font-size:11.5px; font-weight:700; letter-spacing:0.06em; text-transform:uppercase; color:#7c8896; background:#f4f7f9; border-bottom:1px solid #e6eaee; position:sticky; top:0; } .gsRow { display:flex; align-items:baseline; gap:8px; padding:3px 12px; cursor:pointer; border-bottom:1px solid #f0f3f6; line-height:1.4; } .gsRow.gsActive { background:#eef4fa; } .gsRow .gsName { font-size:14px; color:#23303f; font-weight:600; } .gsRow .gsSpecies { font-size:13px; color:#6b7885; font-style:italic; } .gsRow .gsAcc { margin-left:auto; font-size:12.5px; color:#8b96a2; font-variant-numeric:tabular-nums; } .gsEmpty { padding:10px 12px; font-size:14px; color:#6b7885; } + /* Shown only in the browse (common genomes) view: the user who opens the menu and does not + * find their species in the short list is exactly the one who needs to learn they can type. */ + .gsHint { padding:6px 12px; font-size:12.5px; color:#6b7885; border-bottom:1px solid #e6eaee; } .gsPicks { margin-top:10px; display:flex; align-items:center; flex-wrap:wrap; gap:8px; } .gsPicksLabel { font-size:13px; color:#6b7885; } /* Smaller than the design's 14px and than the house minimum: these are short, high-contrast db * names on a secondary row, and keeping them small stops the shortcuts from competing with the * field above. Weight 600 holds legibility at this size. */ .gsPick { font-family:inherit; font-size:12.5px; font-weight:600; padding:3px 10px; border:1px solid #b9c4ce; background:#fff; color:#14487f; cursor:pointer; border-radius:999px; /* A GenArk db name is a full accession (GCA_018466985.1), far longer than "hg38"; clip it * rather than let one recent assembly stretch the row. The tooltip has the full name. */ max-width:150px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; } .gsPick:hover { border-color:#14487f; } .gsPick.gsPickOn { background:#14487f; color:#fff; border-color:#14487f; } .gsStatus { margin-top:10px; font-size:14px; color:#6b7885; min-height:20px; } `; var st = document.createElement('style'); @@ -5404,30 +5407,32 @@ if (g !== group) { group = g; html += '<div class="gsHead">' + htmlEncode(g) + '</div>'; } html += '<div class="gsRow' + (i === active ? ' gsActive' : '') + '" data-i="' + i + '">' + '<span class="gsName">' + htmlEncode(r.name) + '</span>' + '<span class="gsSpecies">' + htmlEncode(r.species) + '</span>' + '<span class="gsAcc">' + htmlEncode(r.acc) + '</span></div>'; }); } menu.innerHTML = html; } function openCommon() { render('Common genomes', commonList(), 'No common genomes configured.'); + menu.innerHTML = '<div class="gsHint">Start typing to search every available genome</div>' + + menu.innerHTML; menu.classList.add('gsOpen'); } function search(term) { var t = term.trim(); if (!t) { openCommon(); return; } if (t.length < 2) { // One character is not worth a round trip; filter what is already in hand, which is // what the jQuery UI version does too. var hits = commonList().filter(function(d) { return (d.label || '').toLowerCase().indexOf(t.toLowerCase()) >= 0 || (d.genome || '').toLowerCase().indexOf(t.toLowerCase()) >= 0; }); render('Matching assemblies', hits, 'No assembly matches that name.'); menu.classList.add('gsOpen'); @@ -5483,31 +5488,31 @@ // of the recents, which under recent[0] wiped out the lead pill that was there; // since that assembly already has its own pill, the first non-popular recent - and // so the pill - is unchanged. A GenArk assembly stays reachable in one click while // the user flips between hg38 and hg19. // Prepending rather than reordering keeps the popular pills in their familiar places. var recent = (typeof getRecentGenomes === 'function') ? getRecentGenomes() : []; var inList = function(g) { return list.some(function(p) { return (p.db || p.genome) === (g.db || g.genome); }); }; var top = null; for (var ri = 0; ri < recent.length; ri++) { if (!inList(recent[ri])) { top = recent[ri]; break; } } if (top) { list = [top].concat(list); } if (!list.length) { picks.innerHTML = ''; return; } - picks.innerHTML = '<span class="gsPicksLabel">Quick picks:</span>'; + picks.innerHTML = '<span class="gsPicksLabel">Shortcuts:</span>'; list.forEach(function(d) { var b = document.createElement('button'); b.type = 'button'; // The pill shows the short db name; the full description is the tooltip, which is // what keeps the row to one line. b.className = 'gsPick' + (committed && committed.db === d.db ? ' gsPickOn' : ''); b.textContent = d.db || d.genome; b.title = (top && d === top ? 'Most recently used: ' : '') + (d.label || ''); b.addEventListener('click', function() { choose(d); }); picks.appendChild(b); }); } function setActive(i) { if (!rows.length) { return; }