PageSourceSearch

https://cerver.ai/nav.js?v=16

js cerver.ai collected 2026-10-05 11:54:25 UTC 13,087 bytes, 183 lines download raw bytes

1/* cerver shared top nav — the single source of truth for the header on
2 * EVERY page (landing included). A page drops in:
3 *     <div id="cerver-nav" data-active="examples"></div>
4 *     <script src="/nav.js" defer></script>
5 * Self-contained (own scoped styles), so it renders identically no matter
6 * what CSS the page loads. Edit this one file → every page updates. */
7(function () {
8  var mount = document.getElementById("cerver-nav");
9  if (!mount) return;
10  var active = mount.getAttribute("data-active") || "";
11
12  // Menus, left → right. `mega` = multi-column panel; otherwise a simple
13  // single-column dropdown. `keys` decides when the trigger shows active.
14  var MENUS = [
15    { label: "/products", keys: ["products"], mega: [
16      { head: "CLI", items: [
17        { t: "cerver run", s: "One-shot agent, single prompt", href: "/docs#quickstart" },
18        { t: "cerver chat", s: "Multi-turn, resumable", href: "/docs#quickstart" },
19        { t: "cerver compare", s: "Same prompt, side by side", href: "/docs#quickstart" },
20        { t: "cerver computes", s: "Manage your machines", href: "/docs#compute-setup" } ] },
21      { head: "API", items: [
22        { t: "Sessions", s: "Create, run, peek, terminate", href: "/docs#session-example" },
23        { t: "Computes", s: "List, attach, switch", href: "/docs#compute-setup" },
24        { t: "Projects", s: "Namespaces for keys + billing", href: "/docs#endpoints" },
25        { t: "Auth", s: "Device-code login, key minting", href: "/docs#secrets" } ] },
26      { head: "Platform", items: [
27        { t: "Dashboard", s: "Sessions, usage, billing", href: "/dashboard" },
28        { t: "Projects & Envs", s: "Per-project config + secrets", href: "/dashboard/projects" },
29        { t: "Vaults", s: "Any vault — Infisical, Doppler, or paste keys", href: "/products#vaults" },
30        { t: "Routing policies", s: "Your algorithm for model choice", href: "/policies" } ] },
31      { head: "Chat", badge: "soon", items: [
32        { t: "Headless chat", s: "Embed without UI work", href: "/chat" },
33        { t: "Multi-tenant", s: "Per-user sessions, scoped", href: "/chat#multi-tenant" },
34        { t: "Hot-swap", s: "Switch model + compute live", href: "/chat#cross-model" },
35        { t: "Cross-model", s: "One widget, any model", href: "/chat#cross-model" } ] } ] },
36    { label: "/use-cases", keys: ["developers", "agents", "app-backend", "teams", "finops"], items: [
37      { t: "Developers", s: "Ship faster, always on the best agent", href: "/use-cases/developers", key: "developers" },
38      { t: "AI agents", s: "Memory, compute & a model they can swap", href: "/use-cases/agents", key: "agents" },
39      { t: "App backend", s: "Drop AI sessions in — forget the plumbing", href: "/use-cases/app-backend", key: "app-backend" },
40      { t: "Teams", s: "Real model flexibility for every employee", href: "/use-cases/teams", key: "teams" },
41      { t: "FinOps", s: "Query every session, cut the waste", href: "/use-cases/finops", key: "finops" } ] },
42    { label: "/how-to", keys: ["docs", "examples"], items: [
43      { t: "Docs", s: "API + CLI reference", href: "/docs", key: "docs" },
44      { t: "Examples", s: "Apps built on Cerver", href: "/examples", key: "examples" } ] },
45    { label: "/more", keys: ["pricing", "blog", "quickstart", "platform", "architecture"], items: [
46      { t: "Quickstart", s: "Add AI to your app in two calls", href: "/quickstart", key: "quickstart" },
47      { t: "Platform demo", s: "Many products, one platform — live", href: "/platform", key: "platform" },
48      { t: "Architecture", s: "Vaults, computes, failover — live", href: "/architecture", key: "architecture" },
49      { t: "Pricing", s: "Plans + cost calculator", href: "/pricing", key: "pricing" },
50      { t: "Blog", s: "Notes on AI spend", href: "/blog", key: "blog" },
51      { t: "Report", s: "The State of AI-Coding Spend 2026", href: "/report", key: "report" },
52      { t: "Benchmarks", s: "Models priced by the job — cost & time to done", href: "/trials/", key: "benchmarks" } ] },
53  ];
54  var CTA = { label: "Get started", href: "/login" };
55
56  var css = ''
57    + '#cerver-nav{display:block}'
58    + '#cerver-nav .cnav{position:relative;border-bottom:1px solid #d9d3c2;background:#f4f1e8;font-family:"IBM Plex Mono",ui-monospace,SFMono-Regular,Menlo,monospace}'
59    + '#cerver-nav .cnav-wrap{max-width:1140px;margin:0 auto;padding:0 22px;height:62px;display:flex !important;align-items:center;justify-content:space-between}'
60    + '#cerver-nav .cnav-brand{display:inline-flex;align-items:center;gap:9px;font-weight:600;font-size:15px;color:#1b1a16;text-decoration:none}'
61    + '#cerver-nav .cnav-brand svg{display:block;color:#df7536}'
62    + '#cerver-nav .cnav-links{display:flex !important;align-items:center;gap:22px}'
63    + '#cerver-nav .cnav-links>
63a:not(.cnav-cta),#cerver-nav .cnav-ddt{font-size:13px;color:#6c685c;text-decoration:none;background:none;border:0;cursor:pointer;font-family:inherit;display:inline-flex;align-items:center;gap:5px;padding:0}'
64    + '#cerver-nav .cnav-dd{position:relative;display:inline-flex;align-items:center}'
65    + '#cerver-nav .cnav-ddt{padding:3px 8px;border-radius:0;transition:background .12s ease,color .12s ease}'
66    + '#cerver-nav .cnav-ddt.on{color:#1b1a16}'
67    // Negative (inverted) highlight on hover / forced-open: ink fill, cream text.
68    + '#cerver-nav .cnav-dd:hover .cnav-ddt,#cerver-nav .cnav-dd.cnav-force .cnav-ddt{background:#1b1a16;color:#f4f1e8}'
69    + '#cerver-nav .cnav-caret{font-size:8px}'
70    + '#cerver-nav .cnav-dd::after{content:"";position:absolute;top:100%;left:-14px;right:-14px;height:14px}'
71    + '#cerver-nav .cnav-pan{position:absolute;top:100%;left:50%;transform:translateX(-50%);margin-top:12px;min-width:250px;background:#fbf9f3;border:1px solid #d9d3c2;border-radius:0;padding:7px;box-shadow:0 16px 38px rgba(0,0,0,.13);display:none;z-index:80}'
72    + '#cerver-nav .cnav-dd.mega{position:static}'
73    + '#cerver-nav .cnav-mega{position:absolute;top:100%;right:22px;margin-top:11px;width:min(880px,calc(100vw - 44px));background:#fbf9f3;border:1px solid #d9d3c2;border-radius:0;padding:20px;box-shadow:0 18px 44px rgba(0,0,0,.13);display:none;z-index:80;grid-template-columns:repeat(4,1fr);gap:20px}'
74    + '#cerver-nav .cnav-mega::before{content:"";position:absolute;bottom:100%;left:0;right:0;height:13px}'
75    + '#cerver-nav .cnav-dd:hover .cnav-pan{display:block}'
76    + '#cerver-nav .cnav-dd:hover .cnav-mega{display:grid}'
77    // Force-open hook so anything on the page (e.g. a hero link) can pop a
78    // dropdown open via window.cerverNav.open(label).
79    + '#cerver-nav .cnav-dd.cnav-force .cnav-pan{display:block}'
80    + '#cerver-nav .cnav-dd.cnav-force .cnav-mega{display:grid}'
81    + '#cerver-nav .cnav-col-h{font-size:10px;text-transform:uppercase;letter-spacing:.08em;color:#6c685c;border-bottom:1px solid #d9d3c2;padding-bottom:8px;margin-bottom:9px;display:flex;gap:6px;align-items:center}'
82    + '#cerver-nav .cnav-badge{font-size:8px;font-weight:700;text-transform:uppercase;color:#df7536;background:rgba(223,117,54,.12);padding:2px 5px;border-radius:0}'
83    + '#cerver-nav .cnav-it{display:block;text-decoration:none;padding:7px 10px;border-radius:0}'
84    + '#cerver-nav .cnav-it:hover{background:#eae5d7}'
85    + '#cerver-nav .cnav-it .t{display:block;font-size:13px;font-weight:600;color:#df7536}'
86    + '#cerver-nav .cnav-it .s{display:block;font-size:11px;color:#6c685c;line-height:1.3;margin-top:1px}'
87    + '#cerver-nav .cnav-cta{font-size:13px;color:#f4f1e8 !important;background:#1b1a16;border-radius:0;padding:7px 13px;font-weight:600;text-decoration:none}'
88    + '#cerver-nav .cnav-cta:hover{color:#1b1a16 !important;background:#df7536}'
89    + '#cerver-nav .cnav-burger{display:none;background:none;border:0;cursor:pointer;font-size:20px;color:#1b1a16;line-height:1;padding:4px}'
90    + '#cerver-nav .cnav-sheet{display:none;border-bottom:1px solid #d9d3c2;background:#f4f1e8;padding:4px 22px 20px;max-height:80vh;overflow:auto}'
91    + '#cerver-nav .cnav-acc{display:flex;justify-content:space-between;align-items:center;width:100%;padding:15px 0;font-size:15px;font-weight:600;color:#1b1a16;background:none;border:0;border-top:1px solid #eae5d7;cursor:pointer;font-family:inherit;text-align:left}'
92    + '#cerver-nav .cnav-accx{color:#df7536;font-size:18px;line-height:1}'
93    + '#cerver-nav .cnav-acc-b{display:none;padding:2px 0 12px 2px}'
94    + '#cerver-nav .cnav-acc-b.open{display:block}'
95    + '#cerver-nav .cnav-acc-b .sub{font-size:10px;text-transform:uppercase;letter-spacing:.08em;color:#9c988a;padding:10px 0 2px}'
96    + '#cerver-nav .cnav-acc-b a{display:block;padding:8px 0;font-size:14px;color:#6c685c;text-decoration:none}'
97    + '#cerver-nav .cnav-sheet-cta{display:block;text-align:center;margin:16px 0 2px;background:#1b1a16;color:#f4f1e8;border-radius:0;padding:13px;font-size:14px;font-weight:600;text-decoration:none}'
98    + '@media(max-width:860px){#cerver-nav .cnav-links{display:none !important}#cerver-nav .cnav-burger{display:block !important}#cerver-nav .cnav-sheet.open{display:block}}';
99
100  // Topbar mark — matches the favicon (server-box monogram) with straight,
101  // sharp lines: a square frame + two bars joined by a left spine.
102  var mark = '<svg width="16" height="16" viewBox="0 0 16 16" aria-hidden="true">'
103    + '<rect x="1.5" y="1.5" width="13" height="13" fill="none" stroke="currentColor" stroke-width="1.5"/>'
104    + '<rect x="4.4" y="4.4" width="7.2" height="2.1" fill="currentColor"/>'
105    + '<rect x="4.4" y="9.5" width="7.2" height="2.1" fill="currentColor"/>'
106    + '<rect x="4.4" y="4.4" width="2.1" height="7.2" fill="currentColor"/></svg>';
107
108  function item(i) {
109    return '<a class="cnav-it" href="' + i.href + '"><span class="t">' + i.t
110      + '</span><span class="s">' + i.s + "</span></a>";
111  }
112  function menu(m) {
113    var on = m.keys.indexOf(active) !== -1 ? " on" : "";
114    var trigger = '<button class="cnav-ddt' + on + '" type="button">' + m.label
115      + '</button>';
116    if (m.mega) {
117      var cols = m.mega.map(function (c) {
118        var head = '<div class="cnav-col-h">' + c.head
119          + (c.badge ? ' <span class="cnav-badge">' + c.badge + "</span>" : "") + "</div>";
120        return "<div>" + head + c.items.map(item).join("") + "</div>";
121      }).join("");
122      return '<div class="cnav-dd mega">' + trigger + '<div class="cnav-mega">' + cols + "</div></div>";
123    }
124    return '<div class="cnav-dd">' + trigger + '<div class="cnav-pan">' + m.items.map(item).join("") + "</div></div>";
125  }
126
127  var desktop = MENUS.map(menu).join("")
128    + '<a class="cnav-cta" href="' + CTA.href + '">' + CTA.label + "</a>";
129
130  var sheet = MENUS.map(function (m) {
131    var body;
132    if (m.mega) {
133      body = m.mega.map(function (c) {
134        return '<div class="sub">' + c.head + "</div>"
135          + c.items.map(function (i) { return '<a href="' + i.href + '">' + i.t + "</a>"; }).join("");
136      }).join("");
137    } else {
138      body = m.items.map(function (i) { return '<a href="' + i.href + '">' + i.t + "</a>"; }).join("");
139    }
140    return '<button class="cnav-acc" type="button">' + m.label + '<span class="cnav-accx">+</span></button>'
141      + '<div class="cnav-acc-b">' + body + "</div>";
142  }).join("") + '<a class="cnav-sheet-cta" href="' + CTA.href + '">' + CTA.label + "</a>";
143
144  mount.innerHTML = "<style>" + css + "</style>"
145    + '<header class="cnav"><div class="cnav-wrap">'
146    +   '<a class="cnav-brand" href="/" aria-label="Cerver — home">' + mark + "Cerver</a>"
147    +   '<nav class="cnav-links" aria-label="Primary">' + desktop + "</nav>"
148    +   '<button class="cnav-burger" type="button" aria-label="Menu" aria-expanded="false">☰</button>'
149    + '</div><div class="cnav-sheet">' + sheet + "</div></header>";
150
151  var burger = mount.querySelector(".cnav-burger");
152  var sheetEl = mount.querySelector(".cnav-sheet");
153  if (burger && sheetEl) {
154    burger.addEventListener("click", function () {
155      var open = sheetEl.classList.toggle("open");
156      burger.setAttribute("aria-expanded", open ? "true" : "false");
157    });
158  }
159  // Mobile accordions: tap a section header to expand its links.
160  mount.querySelectorAll(".cnav-acc").forEach(function (btn) {
161    btn.addEventListener("click", function () {
162      var body = btn.nextElementSibling;
163      var open = body.classList.toggle("open");
164      var x = btn.querySelector(".cnav-accx");
165      if (x) x.textContent = open ? "−" : "+";
166    });
167  });
168
169  // Let the rest of the page open a dropdown by its label (case-insensitive,
170  // prefix match) — e.g. a hero link that previews the Use cases menu on hover.
171  function forceDd(label, on) {
172    var want = String(label || "").trim().toLowerCase();
173    mount.querySelectorAll(".cnav-dd").forEach(function (dd) {
174      var t = dd.querySelector(".cnav-ddt");
175      if (t && t.textContent.trim().toLowerCase().indexOf(want) === 0)
176        dd.classList.toggle("cnav-force", !!on);
177    });
178  }
179  window.cerverNav = {
180    open: function (label) { forceDd(label, true); },
181    close: function (label) { forceDd(label, false); },
182  };
183})();

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.