fix(theseus/bookmarks): brand-case .x TLD labels (theseus.x → Theseus.X)

Bookmark chip labels now normalise the .x TLD family to <Name>.X on
render:
  theseus.x      -> Theseus.X
  deviant.x      -> Deviant.X
  Sirius.x       -> Sirius.X
  foo-bar.x      -> Foo-bar.X
Names that were already ALL-CAPS keep their form so the visual weight
carries through:
  GAME.X         -> GAME.X (unchanged)
  SILENTMODE.X   -> SILENTMODE.X (unchanged)
Non-.x titles are untouched (CoinSpectrum, navigate.st, etc.). The
transformation runs after the descriptor trim, so titles like
'theseus.x — the browser…' also come out 'Theseus.X'.
This commit is contained in:
Local Dev 2026-09-09 02:17:27 +02:00
parent 8649bb97ea
commit dcbe4d55f9
2 changed files with 17 additions and 3 deletions

View file

@ -810,11 +810,25 @@
// leading brand token, so trim at the first em-dash / en-dash / hyphen // leading brand token, so trim at the first em-dash / en-dash / hyphen
// that's surrounded by whitespace. The full title still shows on hover // that's surrounded by whitespace. The full title still shows on hover
// (tooltip below) so the descriptor isn't actually lost. // (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.
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());
return cased + ".X";
}
function bookmarkShortLabel(title, url) { function bookmarkShortLabel(title, url) {
const src = (title || url || "").trim(); const src = (title || url || "").trim();
if (!src) return ""; if (!src) return "";
const cut = src.split(/\s+[—–-]\s+/, 1)[0]; const cut = (src.split(/\s+[—–-]\s+/, 1)[0] || src);
return cut || src; return bookmarkBrandCase(cut);
} }
function renderBookmarks() { function renderBookmarks() {
const box = $("bookmarks"); const box = $("bookmarks");

View file

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