← quik.run
NP@naman-parashar-s-team / Hacker News, livePublic

Hacker News, live

A JS snippet on QuikRun, callable at quik.run/r/hn-live.

JS· node:20· 23 runs· 0 forks· updated 1d ago
Endpointquik.run/r/hn-liveRunFork
Hacker News, live.js
// Hacker News, live - the current HN front page rendered as a server-side React page.
// This is the JSX + SSR showcase: write function components, call renderToString(<Page/>),
// return HTML. React is a BUILT-IN global on QuikRun (the import below is stripped at
// runtime), so there is no npm install and no bundler - just JSX in a single file.
import React from "react";
 
const ACCENT = "#E6FF55";
const INK = "#0B0B0C";
 
// QuickJS has no URL constructor, so pull the host out with a small regex.
function domainOf(url) {
const m = /^https?:\/\/([^/]+)/i.exec(url || "");
return m ? m[1].replace(/^www\./, "") : "news.ycombinator.com";
}
 
const CSS = `
* { box-sizing: border-box; margin: 0; padding: 0; }
body { background: ${INK}; color: #e8e8ea; padding: 40px 16px;
font-family: ui-sans-serif, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; }
.card { max-width: 720px; margin: 0 auto; background: #141416;
border: 1px solid #26262b; border-radius: 18px; overflow: hidden; }
.head { display: flex; align-items: center; gap: 14px; padding: 26px 28px 20px;
border-bottom: 1px solid #26262b; }
.mark { font-weight: 800; font-size: 24px; background: ${ACCENT}; color: ${INK};
width: 40px; height: 40px; display: inline-flex; align-items: center;
justify-content: center; border-radius: 10px; letter-spacing: -0.04em; }
h1 { font-size: 19px; letter-spacing: -0.02em; }
.sub { color: #9a9aa2; font-size: 13px; margin-top: 3px; }
.brandlink { margin-left: auto; color: #86868e; font-size: 12px; font-weight: 600;
text-decoration: none; white-space: nowrap; transition: color .15s ease; }
.brandlink:hover { color: ${ACCENT}; }
.list { list-style: none; }
.row { display: flex; gap: 16px; padding: 15px 28px; align-items: baseline; }
.row + .row { border-top: 1px solid #1e1e22; }
.rank { color: ${ACCENT}; font-weight: 700; width: 22px; flex-shrink: 0;
font-variant-numeric: tabular-nums; }
.body { display: flex; flex-direction: column; gap: 5px; min-width: 0; }
.title { color: #f4f4f6; text-decoration: none; font-size: 15px; line-height: 1.4; }
.title:hover { color: ${ACCENT}; }
.meta { color: #86868e; font-size: 12.5px; font-variant-numeric: tabular-nums; }
.foot { padding: 18px 28px; border-top: 1px solid #26262b; color: #6d6d75;
font-size: 12px; font-variant-numeric: tabular-nums; }
`;
 
function Story({ rank, hit }) {
const url = hit.url || "https://news.ycombinator.com/item?id=" + hit.objectID;
return (
<li className="row">
<span className="rank">{rank}</span>
<span className="body">
<a className="title" href={url}>{hit.title}</a>
<span className="meta">{hit.points} points · {hit.num_comments} comments · {domainOf(url)}</span>
</span>
</li>
);
}
 
function Page({ stories, now }) {
return (
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Hacker News, live</title>
<style dangerouslySetInnerHTML={{ __html: CSS }} />
</head>
<body>
<main className="card">
<header className="head">
<span className="mark">q.</span>
<div>
<h1>Hacker News, live</h1>
<p className="sub">The front page right now, server-rendered on every request</p>
</div>
<a className="brandlink" href="https://quik.run" target="_top" rel="noopener">Built on QuikRun ↗</a>
</header>
<ol className="list">
{stories.map((hit, i) => (
<Story key={hit.objectID} rank={i + 1} hit={hit} />
))}
</ol>
<footer className="foot">rendered {now} UTC · served from quik.run/r/hn-live</footer>
</main>
</body>
</html>
);
}
 
export default async function handler(req) {
const res = await fetch("https://hn.algolia.com/api/v1/search?tags=front_page&hitsPerPage=10");
if (!res.ok) return new Response({ error: "Hacker News API unavailable" }, { status: 503 });
const data = await res.json();
const now = new Date().toISOString().slice(11, 16);
const html = "<!doctype html>" + renderToString(<Page stories={data.hits} now={now} />);
return new Response(html, { status: 200, headers: { "content-type": "text/html; charset=utf-8" } });
}
 
Fork this and make it yours

Describe a change in plain English and QuikRun deploys it to your own URL.

Fork snippet