docs(site): vertical pipeline on mobile, click tooltips, consistent chrome
All checks were successful
docs / build-and-deploy (push) Successful in 2s
All checks were successful
docs / build-and-deploy (push) Successful in 2s
- Pipeline diagram stacks vertically with downward arrows on mobile (row on >=720px) instead of the awkward wrap. - Tooltip cards now open on CLICK (works on touch too), the card itself is clickable and opens the symbol's page in a NEW TAB, and an outside click or Escape closes it. Replaces the hover-only behavior. - Reference pages get their own nav — Home / API Reference / Source ↗ — instead of the landing-only Features/Examples/Get started anchors, and now include the Source link. - Unify the container width (1120px) across the landing and all reference pages so the header and content align between them. - Reword extern/@export FFI docs from "C-ABI" to "native" for consistency with the site's no-C wording. Verified in-browser at 375px and 1280px: vertical pipeline, click→card→new-tab, outside-click close, correct reference nav, aligned container; 158 examples still compile. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
c93eca80af
commit
31f1019a69
7 changed files with 62 additions and 41 deletions
|
|
@ -4,7 +4,7 @@
|
|||
--mint:#7cf5c4; --coral:#ff5d73; --violet:#c792ea; --blue:#82aaff; --amber:#f6c177;
|
||||
--c-bg:#0b0f20; --c-comment:#5b6788; --c-key:#ff7eb6; --c-type:#7cf5c4;
|
||||
--c-str:#f6c177; --c-num:#a6b8ff; --c-annot:#c792ea; --c-fn:#82aaff; --c-punc:#9aa6cc; --c-arg:#f6c177;
|
||||
--radius:14px; --max:900px; --hdr:60px;
|
||||
--radius:14px; --max:1120px; --hdr:60px;
|
||||
}
|
||||
*{box-sizing:border-box}
|
||||
html{scroll-behavior:smooth;-webkit-text-size-adjust:100%}
|
||||
|
|
@ -131,13 +131,15 @@
|
|||
|
||||
/* ---- hover card (hover-capable devices only; JS also gates it) ---- */
|
||||
.hovercard{position:fixed;z-index:100;max-width:min(340px,calc(100vw - 24px));background:var(--panel2);
|
||||
border:1px solid var(--line2);border-radius:12px;padding:12px 14px;box-shadow:0 20px 50px -18px rgba(0,0,0,.8);pointer-events:none}
|
||||
border:1px solid var(--line2);border-radius:12px;padding:12px 14px;box-shadow:0 20px 50px -18px rgba(0,0,0,.8);
|
||||
pointer-events:auto;cursor:pointer}
|
||||
.hovercard:hover{border-color:var(--mint)}
|
||||
.hc-top{display:flex;align-items:center;gap:9px;margin-bottom:8px}
|
||||
.hc-name{font-family:"JetBrains Mono",monospace;color:var(--head);font-weight:700;font-size:14px;overflow-wrap:anywhere}
|
||||
.hc-sig{display:block;color:var(--c-fn);background:var(--c-bg);border:1px solid var(--line);border-radius:7px;
|
||||
padding:6px 9px;font-size:12px;margin-bottom:8px;white-space:pre-wrap;overflow-wrap:anywhere}
|
||||
.hc-tip{color:var(--text);font-size:13.5px;line-height:1.5}
|
||||
.hc-foot{color:var(--muted);font-size:11.5px;margin-top:9px;letter-spacing:.3px}
|
||||
.hc-foot{color:var(--mint);font-size:11.5px;margin-top:9px;letter-spacing:.3px}
|
||||
|
||||
/* ---- target flash ---- */
|
||||
@keyframes ludicflash{0%{background:rgba(124,245,196,.28);box-shadow:0 0 0 3px rgba(124,245,196,.28)}
|
||||
|
|
|
|||
|
|
@ -107,13 +107,26 @@
|
|||
document.querySelectorAll('pre[data-lang="ludic"]').forEach(pre => { pre.innerHTML = highlight(pre.textContent); });
|
||||
}
|
||||
|
||||
/* ---- hover cards ------------------------------------------------------- */
|
||||
let cardEl = null, cardTimer = null;
|
||||
/* ---- tooltip cards: click a token to open; click the card to open the ---
|
||||
---- page in a new tab; click outside (or Escape) to close ------------- */
|
||||
let cardEl = null, cardAnchor = null;
|
||||
function ensureCard(){
|
||||
if (cardEl) return cardEl;
|
||||
cardEl = document.createElement("div"); cardEl.className = "hovercard"; cardEl.hidden = true;
|
||||
cardEl.addEventListener("click", () => {
|
||||
const h = cardEl.dataset.href; if (h) window.open(h, "_blank", "noopener");
|
||||
});
|
||||
document.body.appendChild(cardEl); return cardEl;
|
||||
}
|
||||
function positionCard(a){
|
||||
const el = cardEl, r = a.getBoundingClientRect();
|
||||
const cw = el.offsetWidth, ch = el.offsetHeight;
|
||||
let left = r.left, top = r.bottom + 8;
|
||||
if (left + cw > window.innerWidth - 12) left = window.innerWidth - cw - 12;
|
||||
if (left < 12) left = 12;
|
||||
if (top + ch > window.innerHeight - 12) top = r.top - ch - 8;
|
||||
el.style.left = Math.max(12,left) + "px"; el.style.top = Math.max(12,top) + "px";
|
||||
}
|
||||
function showCard(a){
|
||||
const id = a.getAttribute("data-id"); if (!id) return;
|
||||
const c = CARDS[id]; if (!c) return;
|
||||
|
|
@ -122,30 +135,25 @@
|
|||
+ (c.kind||"").replace("namespace-method","method") + '</span><span class="hc-name">'+esc(c.name||"")+'</span></div>'
|
||||
+ (c.sig ? '<code class="hc-sig">'+esc(c.sig)+'</code>' : "")
|
||||
+ '<div class="hc-tip">'+esc(c.tip||"")+'</div>'
|
||||
+ '<div class="hc-foot">'+esc(c.section||"")+' · click to open</div>';
|
||||
el.hidden = false;
|
||||
const r = a.getBoundingClientRect();
|
||||
const cw = el.offsetWidth, ch = el.offsetHeight;
|
||||
let left = r.left, top = r.bottom + 8;
|
||||
if (left + cw > window.innerWidth - 12) left = window.innerWidth - cw - 12;
|
||||
if (left < 12) left = 12;
|
||||
if (top + ch > window.innerHeight - 12) top = r.top - ch - 8;
|
||||
el.style.left = Math.max(12,left) + "px"; el.style.top = Math.max(12,top) + "px";
|
||||
+ '<div class="hc-foot">'+esc(c.section||"")+' · open in new tab ↗</div>';
|
||||
el.dataset.href = a.getAttribute("href") || "";
|
||||
el.hidden = false; cardAnchor = a; positionCard(a);
|
||||
}
|
||||
function hideCard(){ if (cardEl) cardEl.hidden = true; }
|
||||
function hideCard(){ if (cardEl){ cardEl.hidden = true; cardAnchor = null; } }
|
||||
function installCards(){
|
||||
// hover cards are a pointer affordance; skip on touch so a tap just navigates
|
||||
if (!(window.matchMedia && window.matchMedia("(hover: hover)").matches)) return;
|
||||
document.addEventListener("mouseover", e => {
|
||||
document.addEventListener("click", e => {
|
||||
const a = e.target.closest && e.target.closest("a.tok[data-id]");
|
||||
if (!a) return;
|
||||
clearTimeout(cardTimer); cardTimer = setTimeout(()=>showCard(a), 130);
|
||||
if (a){ e.preventDefault(); showCard(a); return; } // token -> open card
|
||||
if (cardEl && !cardEl.hidden && !(e.target.closest && e.target.closest(".hovercard"))) hideCard(); // outside -> close
|
||||
});
|
||||
document.addEventListener("mouseout", e => {
|
||||
const a = e.target.closest && e.target.closest("a.tok[data-id]");
|
||||
if (a){ clearTimeout(cardTimer); hideCard(); }
|
||||
});
|
||||
window.addEventListener("scroll", hideCard, {passive:true});
|
||||
document.addEventListener("keydown", e => { if (e.key === "Escape") hideCard(); });
|
||||
window.addEventListener("resize", hideCard);
|
||||
window.addEventListener("scroll", () => {
|
||||
if (cardEl && !cardEl.hidden && cardAnchor){
|
||||
const r = cardAnchor.getBoundingClientRect();
|
||||
if (r.bottom < 0 || r.top > window.innerHeight) hideCard(); else positionCard(cardAnchor);
|
||||
}
|
||||
}, {passive:true});
|
||||
}
|
||||
|
||||
/* ---- flash the scrolled-to target ------------------------------------- */
|
||||
|
|
|
|||
|
|
@ -79,12 +79,12 @@
|
|||
pre a.tok:hover{background:rgba(124,245,196,.14);outline:1px solid rgba(124,245,196,.35)}
|
||||
|
||||
/* ---------- pipeline ---------- */
|
||||
.pipeline{display:flex;align-items:center;justify-content:center;gap:4px;flex-wrap:wrap;
|
||||
margin:8px 0 0;padding:16px;border:1px dashed var(--line2);border-radius:var(--radius);background:rgba(18,23,43,.4)}
|
||||
.stage{font-family:"JetBrains Mono",monospace;font-size:12.5px;font-weight:500;color:var(--head);
|
||||
background:var(--panel);border:1px solid var(--line2);padding:7px 11px;border-radius:9px;white-space:nowrap}
|
||||
.pipeline{display:flex;flex-direction:column;align-items:center;gap:8px;
|
||||
margin:8px 0 0;padding:18px 16px;border:1px dashed var(--line2);border-radius:var(--radius);background:rgba(18,23,43,.4)}
|
||||
.stage{font-family:"JetBrains Mono",monospace;font-size:13px;font-weight:500;color:var(--head);text-align:center;
|
||||
background:var(--panel);border:1px solid var(--line2);padding:9px 13px;border-radius:9px;white-space:nowrap}
|
||||
.stage.hl{color:var(--mint);border-color:rgba(124,245,196,.35)}
|
||||
.arrow{color:var(--muted);padding:0 6px;font-size:14px}
|
||||
.arrow{color:var(--muted);font-size:16px;line-height:1;transform:rotate(90deg)}
|
||||
|
||||
/* ---------- sections ---------- */
|
||||
section{padding:48px 0}
|
||||
|
|
@ -156,13 +156,15 @@
|
|||
|
||||
/* hover-card + kind badges (shared with the reference; hover-devices only) */
|
||||
.hovercard{position:fixed;z-index:100;max-width:min(340px,calc(100vw - 24px));background:var(--panel2);
|
||||
border:1px solid var(--line2);border-radius:12px;padding:12px 14px;box-shadow:0 20px 50px -18px rgba(0,0,0,.8);pointer-events:none}
|
||||
border:1px solid var(--line2);border-radius:12px;padding:12px 14px;box-shadow:0 20px 50px -18px rgba(0,0,0,.8);
|
||||
pointer-events:auto;cursor:pointer}
|
||||
.hovercard:hover{border-color:var(--mint)}
|
||||
.hc-top{display:flex;align-items:center;gap:9px;margin-bottom:8px}
|
||||
.hc-name{font-family:"JetBrains Mono",monospace;color:var(--head);font-weight:700;font-size:14px;overflow-wrap:anywhere}
|
||||
.hc-sig{display:block;color:var(--c-fn);background:var(--c-bg);border:1px solid var(--line);border-radius:7px;
|
||||
padding:6px 9px;font-size:12px;margin-bottom:8px;white-space:pre-wrap;overflow-wrap:anywhere}
|
||||
.hc-tip{color:var(--text);font-size:13.5px;line-height:1.5}
|
||||
.hc-foot{color:var(--muted);font-size:11.5px;margin-top:9px;letter-spacing:.3px}
|
||||
.hc-foot{color:var(--mint);font-size:11.5px;margin-top:9px;letter-spacing:.3px}
|
||||
.kind-badge{font-size:11px;font-weight:600;letter-spacing:1px;text-transform:uppercase;padding:3px 7px;
|
||||
border-radius:6px;border:1px solid var(--line2);color:var(--muted);background:var(--panel)}
|
||||
.kind-keyword{color:var(--c-key)}.kind-type{color:var(--c-type)}.kind-phase{color:var(--blue)}
|
||||
|
|
@ -183,6 +185,9 @@
|
|||
.nav-links .nav-cta{padding:8px 15px;border-radius:9px;border:1px solid var(--line2);
|
||||
background:var(--panel);color:var(--head)!important}
|
||||
.nav-links .nav-cta:hover{border-color:var(--mint)}
|
||||
.pipeline{flex-direction:row;flex-wrap:wrap;justify-content:center;gap:4px}
|
||||
.stage{font-size:12.5px;padding:8px 12px}
|
||||
.arrow{transform:none;padding:0 6px;font-size:14px}
|
||||
}
|
||||
@media (min-width:900px){
|
||||
.hero{padding:72px 0 52px}
|
||||
|
|
|
|||
|
|
@ -161,10 +161,10 @@ NS_TIP = {"Screen": "The 2D drawing surface.", "Color": "The named color palette
|
|||
# ---------------------------------------------------------------------------
|
||||
# shared chrome
|
||||
# ---------------------------------------------------------------------------
|
||||
def nav_html(cfg, active=None):
|
||||
def nav_html(cfg, links=None, cta_href="api.html"):
|
||||
out = []
|
||||
for n in cfg["nav_links"]:
|
||||
cls = 'class="nav-cta" ' if n.get("href") == "api.html" else ""
|
||||
for n in (links if links is not None else cfg["nav_links"]):
|
||||
cls = 'class="nav-cta" ' if n.get("href") == cta_href else ""
|
||||
out.append('<a %shref="%s">%s</a>' % (cls, n["href"], esc(n["label"])))
|
||||
return "".join(out)
|
||||
|
||||
|
|
@ -186,10 +186,12 @@ def head_html(title, desc, css_file):
|
|||
</head>""", {"TITLE": esc(title), "DESC": escattr(desc), "CSS": css})
|
||||
|
||||
def topbar(cfg):
|
||||
refnav = nav_html(cfg, links=cfg.get("ref_nav_links", cfg["nav_links"]), cta_href=None) \
|
||||
+ '<a class="nav-cta" href="%s">Source ↗</a>' % cfg["repo_url"]
|
||||
return ('<header class="nav"><div class="wrap nav-in">'
|
||||
'<a class="brand" href="index.html"><span class="logo">L</span> %s</a>'
|
||||
'<button class="nav-toggle" aria-label="Toggle menu" aria-expanded="false">☰</button>'
|
||||
'<nav class="nav-links">%s</nav></div></header>') % (esc(cfg["brand"]), nav_html(cfg))
|
||||
'<nav class="nav-links">%s</nav></div></header>') % (esc(cfg["brand"]), refnav)
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# per-item page
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue