Skip to content

Commit 740f5ad

Browse files
authored
Merge pull request #54 from ghostwright/feat/ui-vocabulary-and-base-template
feat: Phantom UI vocabulary, base template, and name customization
2 parents 527fa30 + 2c6aa5f commit 740f5ad

31 files changed

Lines changed: 4174 additions & 1109 deletions

public/_agent-name.js

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
// Canonical agent-name customization IIFE for Phantom static pages.
2+
//
3+
// Loaded once per page with <script src="/ui/_agent-name.js"></script>.
4+
// Replaces [data-agent-name], [data-agent-name-initial], [data-agent-name-lower]
5+
// nodes with the deployed agent name and substitutes {{AGENT_NAME_CAPITALIZED}}
6+
// in any <title data-agent-name-title> template.
7+
//
8+
// Mirrors the server-side capitalizeAgentName contract: empty/whitespace name
9+
// falls back to "Phantom" so the brand never reads as blank. Paints an
10+
// optimistic value from localStorage (or "Phantom") on load, then swaps when
11+
// /health resolves so warm loads have no flash and cold loads see "Phantom"
12+
// instead of a stray &nbsp; until the fetch resolves.
13+
(function () {
14+
function cap(name) {
15+
if (!name) return "Phantom";
16+
var trimmed = String(name).trim();
17+
if (!trimmed) return "Phantom";
18+
return trimmed
19+
.split(/([-_])/)
20+
.map(function (part) {
21+
if (part === "-" || part === "_") return part;
22+
if (!part.length) return part;
23+
return part.charAt(0).toUpperCase() + part.slice(1).toLowerCase();
24+
})
25+
.join("");
26+
}
27+
28+
var titleEl = document.querySelector("title[data-agent-name-title]");
29+
var titleTemplate = titleEl ? titleEl.getAttribute("data-agent-name-title-template") : "";
30+
if (titleEl && !titleTemplate) {
31+
var initial = titleEl.textContent || "";
32+
if (initial.indexOf("{{AGENT_NAME_CAPITALIZED}}") !== -1) {
33+
titleTemplate = initial;
34+
titleEl.setAttribute("data-agent-name-title-template", initial);
35+
}
36+
}
37+
38+
function apply(name) {
39+
var display = cap(name);
40+
var initial = display.charAt(0).toUpperCase();
41+
var lower = display.toLowerCase();
42+
document.querySelectorAll("[data-agent-name]").forEach(function (el) {
43+
el.textContent = display;
44+
});
45+
document.querySelectorAll("[data-agent-name-initial]").forEach(function (el) {
46+
el.textContent = initial;
47+
});
48+
document.querySelectorAll("[data-agent-name-lower]").forEach(function (el) {
49+
el.textContent = lower;
50+
});
51+
if (titleEl && titleTemplate) {
52+
titleEl.textContent = titleTemplate.split("{{AGENT_NAME_CAPITALIZED}}").join(display);
53+
}
54+
try {
55+
if (name) {
56+
localStorage.setItem("phantom-agent-name", name);
57+
}
58+
} catch (e) {}
59+
}
60+
61+
var cached = "";
62+
try {
63+
cached = localStorage.getItem("phantom-agent-name") || "";
64+
} catch (e) {}
65+
apply(cached || "Phantom");
66+
67+
fetch("/health", { credentials: "same-origin" })
68+
.then(function (r) {
69+
return r.ok ? r.json() : null;
70+
})
71+
.then(function (d) {
72+
if (d && d.agent) apply(d.agent);
73+
})
74+
.catch(function () {});
75+
})();

0 commit comments

Comments
 (0)