Back to APIs list

Hacker News API examples & templates

Use these vals as a playground to view and fork Hacker News API examples and templates on Val Town. Run any example below or find templates that can be used as a pre-built solution.

Send the top 5 HackerNews post to your email every day at a given Datetime.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import { email } from "https://esm.town/v/std/email?v=9";
export default async function(interval: Interval) {
const ntfyURL = `https://ntfy.sh/${Deno.env.get("NTFY_ID")}`;
const hnTopStoriesURL = "https://hacker-news.firebaseio.com/v0/topstories.json";
const hnStoryURL = "https://hacker-news.firebaseio.com/v0/item/";
const topStories = await fetch(hnTopStoriesURL).then((res) => res.json());
const firstFive = topStories.slice(0, 5);
const stories = await Promise.all(
firstFive.map((id: number) => fetch(`${hnStoryURL}${id}.json`).then((res) => res.json())),
);
let html;
const subject = `HackerNews Daily Resume`;
html = `<div>`;
html += "<h1>Hacker News Resume</h1>";
for (const story of stories) {
html += `<p>- <a href="${story.url}">${story.title}</a></p>`;
}
html += "</div>";
await email({
html,
subject,
});
}

Code Search is Easy

Earlier this week, Tom MacWright posted Code Search is Hard. He describes the research he his doing to improve the code search experience of Val Town. It was a great read, and you might have seen it trending on Hacker News.

As Val Town's most active user (behind Steve Krouse, one of the founders of Val Town), I for sure agree with Tom that search feature of Val Town needs improvements. But while reading his post, I immediately thought of a different approach to the problem. And a few hours later, Val Town Search was born.

image.png

Do things that don't scale

How does this new shiny search engine work? Well, it's quite simple.

  1. I wrote a Deno script that fetches all vals from the Val Town API.
  2. I pushed the data to a Github Repository
  3. I added a Github Action that runs the script every hour to refresh the data.
  4. I created a simple frontend on top of the Github Search API that allows you to search the data. It's hosted on Val Town (obviously).

That was it. I didn't have to build a complex search engine, I just used the tools that were available to me.

Is this a scalable solution for Val Town? Probably not.
Am I abusing the Github API? Maybe.
Does it work better than the current search feature of Val Town? Absolutely!

image.png

I hope that the val.town engineers will come up with a search feature that will put my little project to shame. But for now, you won't find a better way to search for vals than Val Town Search.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import codeOnValTown from "https://esm.town/v/andreterron/codeOnValTown?v=50";
import { extractValInfo } from "https://esm.town/v/pomdtr/extractValInfo";
import { serveReadme } from "https://esm.town/v/pomdtr/serve_readme";
const val = extractValInfo(import.meta.url);
let handler = serveReadme({
val,
title: "Code search is easy",
});
handler = codeOnValTown(
handler,
{
val: {
handle: val.author,
name: val.name,
},
},
);
export default handler;

Code Search is Easy

Earlier this week, Tom MacWright posted Code Search is Hard. He describes the research he his doing to improve the code search experience of Val Town. It was a great read, and you might have seen it trending on Hacker News.

As Val Town's most active user (behind Steve Krouse, one of the founders of Val Town), I for sure agree with Tom that search feature needs improvements. But while reading his post, I immediately thought of a different approach to the problem. And a few hours later, Val Town Search was born.

image.png

Do things that don't scale

How does this new shiny search engine work? Well, it's quite simple.

  1. I wrote a Deno script that fetches all vals from the Val Town API.
  2. I pushed the data to a Github Repository
  3. I added a Github Action that runs the script every hour to refresh the data.
  4. I created a simple frontend on top of the Github Search API that allows you to search the data. It's hosted on Val Town (obviously).

That was it. I didn't have to build a complex search engine, I just used the tools that were available to me.

Is this a scalable solution for Val Town? Probably not.
Am I abusing the Github API? Maybe.
Does it work better than the current search feature of Val Town? Absolutely!

image.png

I hope that the val.town engineers will come up with a search feature that will put my little project to shame. But for now, you won't find a better way to search for vals than Val Town Search.

PS: This post was written / is served from Val Town

1
2
3
4
5
6
7
8
9
import codeOnValTown from "https://esm.town/v/andreterron/codeOnValTown?v=50";
import { extractValInfo } from "https://esm.town/v/pomdtr/extractValInfo";
import { serveReadme } from "https://esm.town/v/pomdtr/serve_readme";
const val = extractValInfo(import.meta.url);
export default serveReadme({
val,
title: "Code search is easy",
});

Code Search is Easy

Earlier this week, Tom MacWright posted Code Search is Hard. He describes the research he his doing to improve the code search experience of Val Town. It was a great read, and you might have seen it trending on Hacker News.

As Val Town's most active user (behind Steve Krouse, one of the founders of Val Town), I for sure agree with Tom that search feature of Val Town needs improvements. But while reading his post, I immediately thought of a different approach to the problem. And a few hours later, Val Town Search was born.

image.png

Do things that don't scale

How does this new shiny search engine work? Well, it's quite simple.

  1. I wrote a Deno script that fetches all vals from the Val Town API.
  2. I pushed the data to a Github Repository
  3. I added a Github Action that runs the script every hour to refresh the data.
  4. I created a simple frontend on top of the Github Search API that allows you to search the data. It's hosted on Val Town (obviously).

That was it. I didn't have to build a complex search engine, I just used the tools that were available to me.

Is this a scalable solution for Val Town? Probably not.
Am I abusing the Github API? Maybe.
Does it work better than the current search feature of Val Town? Absolutely!

image.png

I hope that the val.town engineers will come up with a search feature that will put my little project to shame. But for now, you won't find a better way to search for vals than Val Town Search.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import codeOnValTown from "https://esm.town/v/andreterron/codeOnValTown?v=50";
import { extractValInfo } from "https://esm.town/v/pomdtr/extractValInfo";
import { serveReadme } from "https://esm.town/v/pomdtr/serve_readme";
const val = extractValInfo(import.meta.url);
let handler = serveReadme({
val,
title: "Code search is easy",
});
handler = codeOnValTown(
handler,
{
val: {
handle: val.author,
name: val.name,
},
},
);
export default handler;

petemillspaugh.com clippings: #1 – January 2024

Process for sending out a newsletter:

  1. Publish newsletter on the Web
  2. Fork this val and update subject, webUrl, targetSendDate
  3. Uncomment call to insertIntoNewslettersTable
  4. Add to @petermillspaugh/newsletters list Val
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
/** @jsxImportSource https://esm.sh/preact */
import { sqlite } from "https://esm.town/v/std/sqlite?v=4";
export function getJanuary2024Newsletter() {
const subject = "#1 — January 2024";
const webUrl = "https://petemillspaugh.com/january-2024";
const targetSendDate = "2024-02-01 23:40:00";
const jsx = (
<main>
<h1>{subject}</h1>
<p>Hello!</p>
<p>
This is the first clipping from my digital garden. I’m still thinking through what I want these to be, but my
rough idea is an email newsletter that I send every month or two (ish) with a selection of stuff I’ve written
since the last clipping. I planted a note riffing on{" "}
<a href="https://petemillspaugh.com/newsletters">what I want clippings to be</a>, and I’m also writing about
{" "}
<a href="https://petemillspaugh.com/cultivating-emails">
my custom email setup using Val Town
</a>, if you’re curious.
</p>
<p>
There are relatively few of you subscribed, so thanks for being an early reader! Please do{" "}
<a href="mailto:pete@petemillspaugh.com">reply</a> if you feel like it to lmk what you think.
</p>
<h2>Planting my digital garden</h2>
<p>
This clipping will be a bit longer than most because I’m rounding up January 2024 and also looking back on what
I planted in 2023.
</p>
<p>
In the fall I redesigned my personal website as a digital garden. I cover this on my{" "}
<a href="https://petemillspaugh.com/about">about</a>{" "}
page, so I’ll save words here. To learn about digital gardening <em>generally</em>, you can skip right to{" "}
<a href="https://maggieappleton.com/garden-history">Maggie Appleton’s wonderful essay</a>{" "}
on the ethos and history of digital gardens.
</p>
<p>
I wrote about all sorts of stuff last year. Most of it relates to the Web in some way, but there are some bits
about effective learning and career ambitions mixed in. It’s the first time I’ve consistently written in public,
which feels good. I still write plenty for myself—the ratio of private to public writing I do is probably like 4
to 1. Here are some of my personal favorites from 2023:
</p>
<ul>
<li>
<a href="https://petemillspaugh.com/edison-bulb">
<strong>Edison bulb night mode</strong>
</a>. My coworker <a href="https://www.dannyguo.com/">Danny</a> linked this in a{" "}
<a href="https://news.ycombinator.com/item?id=38135892">post</a>{" "}
on Hacker News, which generated some helpful feedback and sent me over the Vercel analytics free tier (feeding
my vanity, ofc)
</li>
<li>
<a href="https://petemillspaugh.com/silly-tlds">
<strong>Silly TLDs</strong>
</a>. This is a short, fun one. It’s the thing I’ve written that friends outside of tech seem most interested
in / leads to the most fun conversations
</li>
<li>
<a href="https://petemillspaugh.com/my-next-next-next-job">
<strong>My next, next, next job</strong>
</a>. I initially wrote this as a private thought exercise then published it after a nudge from some friends
who I’d shared it with
</li>
<li>
<a href="https://petemillspaugh.com/weeks-of-your-life">
<strong>Weeks of your life</strong>
</a>. I built{" "}
<a href="https://weeksofyour.life">weeksofyour.life</a>—an interactive visualization of your life in
weeks—during a couple free days over the holidays. I posted it on{" "}
<a href="https://news.ycombinator.com/item?id=38753911">Show HN</a>, which spurred some heady philosophical
discussions about the meaning of life and also handy tips around performance (and again—vanity food)
</li>
<li>
<a href="https://petemillspaugh.com/map-in-the-woods">
<strong>Downloading a 30MB map in the woods</strong>
</a>. This was my first stab at a format I came up with called "Brainstorms" where I scribble down a thought
stream of questions on a topic I’m curious about (sans Internet), then return later to research
</li>
<li>
<a href="https://petemillspaugh.com/nextjs-search-with-pagefind">
<strong>Add search to your Next.js static site with Pagefind</strong>
</a>. This project was type 2 fun, and I’m really glad I stuck with it. The Pagefind creator{" "}
<a href="https://pagefind.app/docs/resources/#using-pagefind-with-a-specific-ssg">added</a>{" "}
my show ’n tell to the Pagefind docs, which felt good
</li>
<li>
<a href="https://petemillspaugh.com/think-small">
<strong>Think small</strong>
</a>. Of all the things I’ve written, this is what pops into my head most day to day, probably because it’s so
widely applicable
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
#!/usr/bin/env -S deno run -A
import Parser from "npm:rss-parser";
import { formatDistance } from "npm:date-fns";
import * as sunbeam from "https://deno.land/x/sunbeam/mod.ts";
const manifest = {
title: "Hacker News",
description: "Browse Hacker News",
commands: [
{
name: "browse",
title: "Show a feed",
mode: "filter",
params: [{ name: "topic", label: "Topic", type: "text" }],
},
],
} as const satisfies sunbeam.Manifest;
if (Deno.args.length == 0) {
console.log(JSON.stringify(manifest));
Deno.exit(0);
}
const payload: sunbeam.Payload<typeof manifest> = JSON.parse(Deno.args[0]);
if (payload.command == "browse") {
const { topic } = payload.params;
const feed = await new Parser().parseURL(
`https://hnrss.org/${topic}?description=0&count=25`
);
const page: sunbeam.List = {
items: feed.items.map((item) => ({
title: item.title || "",
subtitle: item.categories?.join(", ") || "",
accessories: item.isoDate
? [
formatDistance(new Date(item.isoDate), new Date(), {
addSuffix: true,
}),
]
: [],
actions: [
{
title: "Open in browser",
type: "open",
open: {
url: item.link || "",
},
},
{
title: "Open Comments in Browser",
type: "open",
open: {
url: item.guid || "",
},
},
{
title: "Copy Link",
type: "copy",
key: "c",
copy: {
text: item.link || "",
exit: true,
},
},
],
})),
};
console.log(JSON.stringify(page));
} else {
console.error("Unknown command");
Deno.exit(1);
}
// #sunbeam
1
2
// set at Thu Nov 30 2023 14:22:53 GMT+0000 (Coordinated Universal Time)
export let topHNThreadByHour = ["Top thread on Hackernews for 3:00 is: Vespa.ai is spinning out of Yahoo as a separate company","Top thread on Hackernews for 4:00 is: President Speaking: Spoofing Alerts in 4G LTE Networks (2019) [pdf]","Top thread on Hacke
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import { fetch } from "https://esm.town/v/std/fetch";
import { fetchJSON } from "https://esm.town/v/stevekrouse/fetchJSON";
// Get the title of the top story on Hacker News
export async function hnTopStory() {
const topStories: Number[] = await fetch(
"https://hacker-news.firebaseio.com/v0/topstories.json?print=pretty"
).then((res) => res.json());
const id = topStories[0];
const story: {
title: string;
url: string;
time: number;
type: string;
score: number;
by: string;
} = await fetchJSON(
`https://hacker-news.firebaseio.com/v0/item/${id}.json`
);
return story.title;
}
// forked from @healeycodes.hnTopStories
// Forked from @jamiedubs.hnTopStories
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import { fetch } from "https://esm.town/v/std/fetch";
import { fetchJSON } from "https://esm.town/v/stevekrouse/fetchJSON?v=41";
// Get the title of the top story on Hacker News
export async function hnTopTenStories() {
const topStories: Number[] = await fetch(
"https://hacker-news.firebaseio.com/v0/beststories.json?print=pretty",
).then((res) => res.json());
const top10Stories = await Promise.all(
topStories.slice(0, 10).map(async (id) => {
return await fetchJSON(
`https://hacker-news.firebaseio.com/v0/item/${id}.json`,
);
}),
);
return top10Stories;
}
// forked from @healeycodes.hnTopStories
// Forked from @jamiedubs.hnTopStories
// Forked from @stevekrouse.hnTopStory
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import { fetchJSON } from "https://esm.town/v/stevekrouse/fetchJSON";
import { searchParams } from "https://esm.town/v/stevekrouse/searchParams";
/* Search Hacker News via Agolia
Look for the valid params: https://hn.algolia.com/api */
export let hnSearch = async ({
search_by_date,
...params
}: {
search_by_date?: boolean,
query?: string,
tags?: string,
numericFilters?: string,
page?: number,
}) => {
let type = search_by_date ? "search_by_date" : "search";
let cleaned_params = await searchParams(params);
let data = await fetchJSON(
`http://hn.algolia.com/api/v1/${type}?${cleaned_params}`
);
if (!data.hits && data.message) {
throw new Error("Error in @stevekrouse.hnSearch: " + data.message);
} else {
return data;
}
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
import { getUrlHostname } from "https://esm.town/v/iakovos/getUrlHostname";
export function renderTopStories(stories: {
id: number;
title: string;
url: string;
time: number;
type: string;
score: number;
by: string;
descendants: number; // Number of comments
}[]): string {
const html = `
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Hacker News</title>
</head>
<body style="font-family: Helvetica, sans-serif; background-color: #f4f4f4; padding: 20px;">
<div style="max-width: 600px; background-color: #ffffff; margin: 0 auto; padding: 20px; border-radius: 10px; box-shadow: 0 0 10px rgba(0,0,0,0.1);">
<h1 style="text-align: center; border-bottom: 1px solid #e4e4e4; padding-bottom: 5px; margin-bottom: 20px; font-size: 2em; color: #222;">Hacker News</h1>
<ul style="list-style-type: none; padding: 0;">
${
stories.map((story) => `
<li style="padding: 10px 0; border-bottom: 1px solid #e4e4e4;">
<a href="${story.url}" target="_blank" style="text-decoration: none; font-weight: bold; color: #0056b3; font-size: 1.3em;">${story.title}</a>
<div style="margin: 2px 0; color: #888;">
<strong>Score:</strong> ${story.score} |
<strong>By:</strong> ${story.by} |
<a href="https://news.ycombinator.com/item?id=${story.id}" target="_blank" style="color: #888; text-decoration: none;">${story.descendants} comments</a> |
<a href="${story.url}" target="_blank" style="color: #888; text-decoration: none;">${
getUrlHostname(story.url)
}</a>
</div>
</li>
`).join("")
}
</ul>
</div>
</body>
</html>
`;
return html;
}

Val Town inspiration & use cases list

List [as object] used in Val Town's use cases and inspiration. Check it out at in /examples/use-cases and /docs/tutorial/4

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
// set by rodrigotello.updateInspoList at 2023-06-29T18:53:25.934Z
export let valTownInspoList = [{
"title": "What can I make in Val Town?",
"description":
"The data for this page was created by using Val Town as a CMS",
"val": "@rodrigotello.valTownInspoList",
image:
"https://air-prod.imgix.net/abff23bf-fc18-485f-a6b5-4a1c8b7f91ec.jpg?w=1200&h=2000&auto=compress&ixlib=react-9.5.4",
}, {
"title": "NASA photo of the day.",
"description": "Returns NASA's Astronomy Picture of the Day (APOD)",
"val": "@rodrigotello.nasaAPOD",
"image":
"https://air-prod.imgix.net/11ab8b2e-c052-4574-8341-96d5d74040cc.jpg?w=1200&h=2000&auto=compress&ixlib=react-9.5.4",
}, {
"title": "hnFollow",
"description":
"Get email notifications any time an author you follow posts in Hacker News.",
"val": "@rodrigotello.hnFollow",
"image":
"https://air-prod.imgix.net/61e08fed-c77e-4a7b-9ae5-1efabb349574.jpg?w=1200&h=2000&auto=compress&ixlib=react-9.5.4",
}, {
"title": "GitHub events",
"description": "Get a GithHub users' public events",
"val": "@stevekrouse.githubEvents",
image:
"https://air-prod.imgix.net/3545d2cb-7cae-49d9-98b7-832428d2af34.jpg?w=1200&h=2000&auto=compress&ixlib=react-9.5.4",
}, {
"title": "Twitter alerts",
"description": "Track Twitter mentions and be alerted via email",
"val": "@stevekrouse.twitterAlert",
image:
"https://air-prod.imgix.net/4c81af31-0832-4c72-8afb-34ef23fa03c9.jpg?w=1200&h=2000&auto=compress&ixlib=react-9.5.4",
}, {
"title": "Air quality",
"description":
"Get email alerts when the air quality is bad. Val created with much help from @russbiggs (Director of Technology at OpenAQ)",
"val": "@stevekrouse.aqi",
image:
"https://air-prod.imgix.net/1a21321c-2bb7-4aa8-8c26-eb58cf1787a2.jpg?w=1200&h=2000&auto=compress&ixlib=react-9.5.4",
}, {
"title": "Annoy friends in Bluesky",
"description":
"ChatGPT powered bot for the sole purpose of annoying friends on Bluesky.",
"val": "@ajax.annoy",
image:
"https://air-prod.imgix.net/d21d3c1f-99e9-4356-85ed-bc6d7746c867.jpg?w=1200&h=2000&auto=compress&ixlib=react-9.5.4",
}, {
"title": "Venue calendar",
"description": "Get a venue calendar through Resy",
"val": "@rlesser.Resy_getVenueCalendar",
image:
"https://air-prod.imgix.net/cab68838-bc60-48a2-8b00-50f203ac303d.jpg?w=1200&h=2000&auto=compress&ixlib=react-9.5.4",
}, {
"title": "Bitcoin price alert",
"description": "Get an email when Bitcoin price changes more than 20%",
"val": "@stevekrouse.btcPriceAlert",
image:
"https://air-prod.imgix.net/0d6605d2-b3ab-4bcb-9cf4-06580c5007ee.jpg?w=1200&h=2000&auto=compress&ixlib=react-9.5.4",
}, {
"title": "RSS Notification",
"description":
"Your own RSS feed. Just create a list of the blogs you want to follow.",
"val": "@stevekrouse.pollRSSFeeds",
image:
"https://air-prod.imgix.net/9ad2b03e-ea41-4402-b18d-50df75f29d5e.jpg?w=1200&h=2000&auto=compress&ixlib=react-9.5.4",
}, {
"title": "Uptime monitor",
"description": "Check if your website (or any website) is down.",
"val": "@healeycodes.isMyWebsiteDown",
image:
"https://air-prod.imgix.net/c662747c-92cd-4e3a-ac91-1209f7cf6fb5.jpg?w=1200&h=2000&auto=compress&ixlib=react-9.5.4",
}, {
"title": "Stale PRs",
"description": "Get emails with the open PRs that have't had any activity.",
"val": "@ramkarthik.staleGithubPRsEmail",
image:
"https://air-prod.imgix.net/640fc428-31a1-44b3-a9ac-4af8474fa867.jpg?w=1200&h=2000&auto=compress&ixlib=react-9.5.4",
}, {
"title": "Wholefoods RSS",
"description": "Track when your favorite products are back in stock.",
"val": "@Glench.wholeFoodsRSS",
image:
"https://air-prod.imgix.net/2ab8f2e0-3146-4c92-a4de-f0e49ef9e456.jpg?w=600&h=2000&auto=compress&ixlib=react-9.5.4",
}, {
"title": "Discord Welcome Bot",
"description":
'Create a Discord welcome bot using scheduled vals. You can <a href="https://docs.val.town/create-a-discord-welcome-bot">read the full tutorial here</a>.',
"val": "@vtdocs.discordWelcomeBotCron",
image:
"https://air-prod.imgix.net/9286aea4-98c3-4c6e-aa45-537932a51dfb.jpg?w=600&h=2000&auto=compress&ixlib=react-9.5.4",
}, {
"title": "Slack app",
"description":
"Evaluate anything from Slack via Val Town and get results back right in Slack.",
"val": "@nate.slackapp",
image:
"https://air-prod.imgix.net/70698db9-7715-4092-bbc1-be51ad08ff28.jpg?w=1200&h=2000&auto=compress&ixlib=react-9.5.4",
}, {
"title": "Spotify Discover Weekly Archive",
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import { hnPrefixURL } from "https://esm.town/v/stevekrouse/hnPrefixURL?v=1";
export let hnStoryToHTML = ({
author,
title,
url,
points,
num_comments,
objectID,
}) => `
<div>
<div><div style="display:inline-block">🔗 <a href="${url}" style="color:#3b82f6; font-size:1.2em; style="display:inline-block"><h1 style="display:inline-block"> ${title} </h1></a></div></div>
<div style="color:gray; display:inline-block; margin-right:32px"><span>posted by </span><span><a href="https://news.ycombinator.com/user?id=${author}" style="color: gray">${author}</a></span></div>
<div style="color:gray; display:inline-block; margin-right:32px"><a href="${hnPrefixURL}${objectID}" style="color:gray">Hacker News URL</a></div>
<div style="color:gray; display:inline-block; margin-right:32px">${points} upvotes, <a href="${hnPrefixURL}${objectID}" style="color:gray">${num_comments} comments</a></div>
<div style="height:24px"></div>
</div>`;
// Forked from @stevekrouse.hnStoryToText
1
Next