mirror of
https://github.com/planetrenox/time.planetrenox.com.git
synced 2026-10-29 04:34:52 +00:00
Add API explorer section to the page
Lists every /api endpoint, fetches the picked one live with highlighted output and a copy-curl button; nav API link now scrolls to it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
Live **PRT (Planet Renox Time)**, milliseconds since `1998-03-14T03:00:00.000Z`, in every [ortus](https://github.com/planetrenox/ortus) unit (`ms s m h d w`), over a dot map of Earth lit by the real-time sun.
|
Live **PRT (Planet Renox Time)**, milliseconds since `1998-03-14T03:00:00.000Z`, in every [ortus](https://github.com/planetrenox/ortus) unit (`ms s m h d w`), over a dot map of Earth lit by the real-time sun.
|
||||||
|
|
||||||
Also on the page: PRT day/week progress, upcoming round-number milestones, next equinox/solstice, a subsolar marker with hover readout (lat/lon, sun altitude, solar time), and a Date ⇄ PRT converter.
|
Also on the page: PRT day/week progress, upcoming round-number milestones, next equinox/solstice, a subsolar marker with hover readout (lat/lon, sun altitude, solar time), a Date ⇄ PRT converter, and a live API explorer.
|
||||||
|
|
||||||
## API
|
## API
|
||||||
|
|
||||||
|
|||||||
@@ -204,3 +204,32 @@ $('cin').value = '1970-01-01T00:00:00.000' // Unix epoch, shows PRT going negati
|
|||||||
$('cin').oninput = $('cz').onchange = conv
|
$('cin').oninput = $('cz').onchange = conv
|
||||||
$('pin').oninput = $('pu').onchange = pconv
|
$('pin').oninput = $('pu').onchange = pconv
|
||||||
conv(), pconv()
|
conv(), pconv()
|
||||||
|
|
||||||
|
// API explorer
|
||||||
|
const EPS = [
|
||||||
|
['/api/now', '/api/now', 'Current PRT in every unit, JSON'],
|
||||||
|
['/api/now/d', '/api/now/{unit}', 'One unit, plain text'],
|
||||||
|
['/api/from/2010-06-01', '/api/from/{date}', 'PRT at an ISO date or Unix ms'],
|
||||||
|
['/api/to/1000000000000', '/api/to/{n}/{unit?}', 'Date at a PRT value, unit defaults to ms'],
|
||||||
|
['/api', '/api', 'Epoch, units, endpoint list'],
|
||||||
|
]
|
||||||
|
$('eps').innerHTML = EPS.map(([p, s, d]) => `<li><button data-ep="${p}"><code>${s.replace(/\{[^}]+\}/g, '<em>$&</em>')}</code><span>${d}</span></button></li>`).join('')
|
||||||
|
const esc = s => s.replace(/&/g, '&').replace(/</g, '<')
|
||||||
|
const hl = s => esc(s).replace(/("[^"]*")(\s*:)?|(-?\d+(?:\.\d+)?(?:e[+-]?\d+)?)/gi, (m, q, k, n) => q ? (k ? `<b>${q}</b>${k}` : `<em>${q}</em>`) : `<i>${n}</i>`)
|
||||||
|
let ep = EPS[0][0]
|
||||||
|
const tryEp = async p => {
|
||||||
|
ep = p
|
||||||
|
document.querySelectorAll('[data-ep]').forEach(b => b.classList.toggle('on', b.dataset.ep == p))
|
||||||
|
$('rq').innerHTML = `GET ${esc(p)}`
|
||||||
|
try {
|
||||||
|
const r = await fetch(p), t = await r.text()
|
||||||
|
if (ep != p) return
|
||||||
|
let o
|
||||||
|
try { o = JSON.stringify(JSON.parse(t), null, 2) } catch { o = t.trim() }
|
||||||
|
$('rq').innerHTML = `GET ${esc(p)} <b>${r.status}</b>`
|
||||||
|
$('rs').innerHTML = hl(o)
|
||||||
|
} catch (e) { ep == p && ($('rs').innerHTML = `<span class="err">${esc(e.message)}</span>`) }
|
||||||
|
}
|
||||||
|
$('eps').addEventListener('click', e => { const b = e.target.closest('[data-ep]'); b && tryEp(b.dataset.ep) })
|
||||||
|
$('curl').addEventListener('click', () => navigator.clipboard?.writeText(`curl ${location.origin}${ep}`).then(() => toast('Copied curl')))
|
||||||
|
new IntersectionObserver((es, io) => es[0].isIntersecting && (io.disconnect(), tryEp(EPS[0][0]))).observe($('api'))
|
||||||
|
|||||||
+12
-1
@@ -22,7 +22,7 @@
|
|||||||
<body>
|
<body>
|
||||||
<header class="top wrap">
|
<header class="top wrap">
|
||||||
<a class="brand" href="/"><span class="orb"></span>PRT</a>
|
<a class="brand" href="/"><span class="orb"></span>PRT</a>
|
||||||
<nav><a href="/api">API</a><a href="https://www.npmjs.com/package/ortus">ortus ↗</a><a href="https://github.com/planetrenox/ortus">GitHub ↗</a></nav>
|
<nav><a href="#api">API</a><a href="https://www.npmjs.com/package/ortus">ortus ↗</a><a href="https://github.com/planetrenox/ortus">GitHub ↗</a></nav>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<main class="wrap" role="timer">
|
<main class="wrap" role="timer">
|
||||||
@@ -62,6 +62,17 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</article>
|
</article>
|
||||||
|
<article class="card wide" id="api">
|
||||||
|
<h2>API</h2>
|
||||||
|
<p class="m">Free JSON over HTTPS. No key, CORS open. Pick an endpoint to try it live.</p>
|
||||||
|
<div class="api">
|
||||||
|
<ul id="eps"></ul>
|
||||||
|
<div class="res">
|
||||||
|
<div class="rq"><code id="rq"></code><button id="curl">copy curl</button></div>
|
||||||
|
<pre id="rs"></pre>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</article>
|
||||||
</section>
|
</section>
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
|
|||||||
@@ -99,6 +99,24 @@ dt { color: var(--cyan); text-align: right }
|
|||||||
dd { overflow-wrap: anywhere }
|
dd { overflow-wrap: anywhere }
|
||||||
.err { color: #ff9db0 }
|
.err { color: #ff9db0 }
|
||||||
|
|
||||||
|
.api { display: grid; grid-template-columns: minmax(0, 5fr) minmax(0, 6fr); gap: 24px; margin-top: 16px }
|
||||||
|
#eps { list-style: none; padding: 0; display: flex; flex-direction: column; gap: 6px }
|
||||||
|
#eps button { width: 100%; display: flex; flex-direction: column; gap: 3px; padding: 10px 14px; text-align: left; border: 1px solid transparent; border-radius: 10px; background: none; cursor: pointer; transition: background .2s, border-color .2s }
|
||||||
|
#eps button:hover { background: rgba(60, 120, 255, .08) }
|
||||||
|
#eps .on { border-color: rgba(127, 214, 255, .35); background: rgba(60, 120, 255, .1) }
|
||||||
|
#eps code { font: 14px var(--mono) }
|
||||||
|
#eps code em { font-style: normal; color: var(--cyan) }
|
||||||
|
#eps span { font-size: 13px; color: var(--mute) }
|
||||||
|
.res { display: flex; flex-direction: column; min-width: 0; border: 1px solid var(--line); border-radius: 12px; background: rgba(2, 8, 22, .7); overflow: hidden }
|
||||||
|
.rq { display: flex; align-items: center; justify-content: space-between; gap: 10px; padding: 8px 8px 8px 14px; border-bottom: 1px solid var(--line); font: 13px var(--mono); color: var(--mute) }
|
||||||
|
.rq code { overflow: hidden; text-overflow: ellipsis; white-space: nowrap }
|
||||||
|
.rq code b { font-weight: 400; color: var(--cyan) }
|
||||||
|
.rq button { flex-shrink: 0; padding: 5px 10px; border: 1px solid var(--line); border-radius: 8px; background: none; font: 12px var(--mono); color: var(--cyan); cursor: copy }
|
||||||
|
#rs { flex: 1; min-height: 230px; margin: 0; padding: 14px; overflow: auto; font: 13px/1.65 var(--mono); color: var(--ink) }
|
||||||
|
#rs b { font-weight: 400; color: #8fb4ff }
|
||||||
|
#rs em { font-style: normal; color: #cfe9ff }
|
||||||
|
#rs i { font-style: normal; color: var(--cyan) }
|
||||||
|
|
||||||
footer { display: flex; align-items: center; justify-content: space-between; gap: 20px; padding: 34px 0 44px; color: var(--dim); font-size: 13px }
|
footer { display: flex; align-items: center; justify-content: space-between; gap: 20px; padding: 34px 0 44px; color: var(--dim); font-size: 13px }
|
||||||
.npm { flex-shrink: 0; white-space: nowrap; padding: 8px 14px; border-radius: 10px; border: 1px solid var(--line); background: rgba(4, 12, 32, .6); font: 13px var(--mono); color: var(--cyan); cursor: copy }
|
.npm { flex-shrink: 0; white-space: nowrap; padding: 8px 14px; border-radius: 10px; border: 1px solid var(--line); background: rgba(4, 12, 32, .6); font: 13px var(--mono); color: var(--cyan); cursor: copy }
|
||||||
#toast { position: fixed; left: 50%; bottom: 26px; transform: translateX(-50%); padding: 9px 16px; border-radius: 10px; background: rgba(10, 30, 80, .92); border: 1px solid rgba(127, 214, 255, .35); font: 13px var(--mono); box-shadow: 0 10px 40px rgba(0, 0, 0, .5) }
|
#toast { position: fixed; left: 50%; bottom: 26px; transform: translateX(-50%); padding: 9px 16px; border-radius: 10px; background: rgba(10, 30, 80, .92); border: 1px solid rgba(127, 214, 255, .35); font: 13px var(--mono); box-shadow: 0 10px 40px rgba(0, 0, 0, .5) }
|
||||||
@@ -115,9 +133,10 @@ footer { display: flex; align-items: center; justify-content: space-between; gap
|
|||||||
.units { grid-template-columns: repeat(2, minmax(0, 1fr)); margin-top: 36px }
|
.units { grid-template-columns: repeat(2, minmax(0, 1fr)); margin-top: 36px }
|
||||||
.unit, .unit:nth-child(n+4) { grid-column: auto }
|
.unit, .unit:nth-child(n+4) { grid-column: auto }
|
||||||
.unit:last-child { grid-column: span 2 }
|
.unit:last-child { grid-column: span 2 }
|
||||||
.grid, .cv, #miles { grid-template-columns: minmax(0, 1fr) }
|
.grid, .cv, #miles, .api { grid-template-columns: minmax(0, 1fr) }
|
||||||
.wide { grid-column: auto }
|
.wide { grid-column: auto }
|
||||||
.v { font-size: 16px }
|
.v { font-size: 16px }
|
||||||
|
#rs { min-height: 120px }
|
||||||
.map { margin: 22px -20px 0 }
|
.map { margin: 22px -20px 0 }
|
||||||
footer { flex-direction: column; align-items: flex-start }
|
footer { flex-direction: column; align-items: flex-start }
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user