toolbar 30% ratio floor + placeholder-safe search + brand map for .x names

Toolbar drag handle now clamps both bars to at least 30 % of the
.urlsearch budget (URL: 30 %–70 %, search fills the rest). The
existing absolute mins (URL 220 px, search bumped from 140 → 180 px
so the 'Search' placeholder always fits) still apply — the tighter of
absolute vs 30 %-of-container wins at any width. .urlsearch also gets
margin-right: 10 px so the search bar has visible breathing room from
the trailing dock (Downloads / extensions / ⛓ Theseus).

Bookmark brand-case now uses a canonical map for multi-word Silent Mode
names so all-caps sources come out correctly cased: SILENTMODE.X →
SilentMode.X, silentmode.x → SilentMode.X, coinspectrum.x →
CoinSpectrum.X. Single-word brands (Theseus, Sirius, Deviant, Aegis,
Ariadne, Argus, Hermes, Prometheus, Hephaestus, Helios, Atlas,
Katalogos, Game, Poutakidis, Syskypo) are in the same map for
consistency. Unknown names fall back to Title-case (foo.x → Foo.X)
— the ALL-CAPS preserve rule is gone, so GAME.X → Game.X now,
matching the user's ask.
This commit is contained in:
Local Dev 2026-09-09 02:25:12 +02:00
parent dcbe4d55f9
commit c64e81a959
2 changed files with 39 additions and 14 deletions

View file

@ -166,10 +166,16 @@
and vice versa) without moving anything else in the toolbar. When the
window is too narrow for both, the search bar hides (see the
data-responsive rules below); the URL bar keeps working alone. */
.urlsearch { flex: 1 1 auto; min-width: 0; display: flex; align-items: center; gap: 6px; }
/* margin-right creates a bit of breathing room between the search bar
and the trailing dock (Downloads, extensions, ⛓ Theseus) so they
never look like they collide. */
.urlsearch { flex: 1 1 auto; min-width: 0; display: flex; align-items: center; gap: 6px; margin-right: 10px; }
.urlwrap { position: relative; flex: 0 1 var(--urlbar-w, 60%); min-width: 220px; display: flex; align-items: center; gap: 4px; background: var(--surface); border: 1px solid var(--line);
border-radius: 999px; padding: 0 6px 0 4px; }
.searchbox { flex: 1 1 0; min-width: 140px; }
/* Search-box floor bumped so the "Search" placeholder always fits inside
the input — dropping below ~180px in normal font sizes was where the
placeholder text started getting clipped. */
.searchbox { flex: 1 1 0; min-width: 180px; }
/* Single drag handle sitting between the two — a thin 6px column with a
col-resize cursor. Zero-sum semantics: dragging right grows the URL
bar and shrinks the search bar; dragging left does the inverse. */
@ -811,17 +817,24 @@
// that's surrounded by whitespace. The full title still shows on hover
// (tooltip below) so the descriptor isn't actually lost.
//
// Brand-case normalisation for Silent Mode's .x TLD family: user's
// bookmark titles come in whatever case the site set (theseus.x saves
// as "theseus.x", game.x as "GAME.X"). Uniform on the chip: <Name>.X,
// but names that were already all-caps ("GAME") keep their form so
// they don't accidentally lose emphasis to Title-case.
// Brand-case normalisation for Silent Mode's .x TLD family: sites save
// their title in whatever case they set (theseus.x, GAME.X, silentmode.x)
// — the chip renders them uniform as <Name>.X. Titles are Title-case by
// default; multi-word brand names (SilentMode, CoinSpectrum) have their
// canonical form in BRAND_CASE_X so they don't collapse to "Silentmode".
const BRAND_CASE_X = {
silentmode: "SilentMode", coinspectrum: "CoinSpectrum",
theseus: "Theseus", sirius: "Sirius", deviant: "Deviant", aegis: "Aegis",
ariadne: "Ariadne", argus: "Argus", hermes: "Hermes",
prometheus: "Prometheus", hephaestus: "Hephaestus", helios: "Helios",
atlas: "Atlas", katalogos: "Katalogos", game: "Game",
poutakidis: "Poutakidis", syskypo: "Syskypo",
};
function bookmarkBrandCase(label) {
const m = label.match(/^([a-zA-Z][a-zA-Z0-9-]*)\.x$/i);
if (!m) return label;
const name = m[1];
const isAllCaps = name === name.toUpperCase() && /[A-Z]/.test(name);
const cased = isAllCaps ? name : (name.charAt(0).toUpperCase() + name.slice(1).toLowerCase());
const key = m[1].toLowerCase();
const cased = BRAND_CASE_X[key] || (key.charAt(0).toUpperCase() + key.slice(1));
return cased + ".X";
}
function bookmarkShortLabel(title, url) {
@ -1476,7 +1489,14 @@
const handleEl = $("bardrag");
const urlWrapEl = barEl2.querySelector(".urlwrap");
const urlsearchEl = $("urlsearch");
const MIN_URL = 220, MIN_SEARCH = 140, HANDLE_W = 6, GAP = 6;
// Absolute minimums track the CSS min-widths so the drag can't push either
// bar below the size where its content stops fitting. On top of that we
// enforce a 30 % share floor for both bars: the URL bar can never take more
// than 70 % of the combined budget, and the search bar can never be less
// than 30 %. Combined with the CSS min-widths, the tighter of the two rules
// wins at any given container width.
const MIN_URL_PX = 220, MIN_SEARCH_PX = 180, HANDLE_W = 6, GAP = 6;
const MIN_SHARE = 0.30;
let dragging = false, startX = 0, startW = 0, lastW = 0;
handleEl.addEventListener("pointerdown", (e) => {
if (e.button !== 0) return;
@ -1490,8 +1510,13 @@
handleEl.addEventListener("pointermove", (e) => {
if (!dragging) return;
const total = urlsearchEl.getBoundingClientRect().width;
const maxUrl = Math.max(MIN_URL, total - HANDLE_W - GAP * 2 - MIN_SEARCH);
const w = Math.round(Math.max(MIN_URL, Math.min(maxUrl, startW + (e.clientX - startX))));
const minUrl = Math.max(MIN_URL_PX, Math.round(total * MIN_SHARE));
const maxUrl = Math.min(
total - HANDLE_W - GAP * 2 - Math.max(MIN_SEARCH_PX, Math.round(total * MIN_SHARE)),
Math.round(total * (1 - MIN_SHARE))
);
const clampedMax = Math.max(minUrl, maxUrl);
const w = Math.round(Math.max(minUrl, Math.min(clampedMax, startW + (e.clientX - startX))));
lastW = w;
barEl2.style.setProperty("--urlbar-w", w + "px");
if (typeof updateExtCollapse === "function") updateExtCollapse();

View file

@ -1,6 +1,6 @@
{
"name": "theseus-navigator",
"version": "0.3.42",
"version": "0.3.43",
"description": "Theseus Navigator — a browser that follows the thread. By Silent Mode, a Deviant project.",
"author": "Silent Mode",
"main": "main.js",