Public
Edited
Aug 6, 2023
Paused
Importers
1 star
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
linkNewTab()
Insert cell
/**
* Create an html link that opens in a new tab
* - text: the display text
* - link: hyperlink url
*/
function linkNewTab(
text = "Example",
link = "https://www.example.com/"
) {
return htl.html`<a href="${link}" target="_blank">${text}</a>`;
}
Insert cell
Insert cell
croissant()
Insert cell
/**
* Make an html link to a Stripe page for donation using a croissant
*/
function croissant() {
return linkNewTab("Give a Croissant 🥐", "https://buy.stripe.com/00g031g9x0kYgkUaEF");
}
Insert cell
Insert cell
nounCredit()
Insert cell
nounCredit("Octopus")
Insert cell
/**
* Make link to Noun Project for citations
* - defaults to profile page for url
* - can specify a noun name if using a specific icon
*/
function nounCredit(name=null, url = "https://thenounproject.com/zachbogart/") {
if (!name) {
return linkNewTab(`Nouns by Zach Bogart 🖤`, url)
} else {
return linkNewTab(`${name} by Zach Bogart from Noun Project 🖤`, url)
}
}
Insert cell
Insert cell
/**
* Fetches public GitHub repository data from the GitHub API.
* @param {string} repo - The GitHub repository slug in the format 'user/repo'.
* @returns {Promise<Object>} - A Promise that resolves with the repository data as a JSON object, or an object with an error message if there was an error.
*/
async function publicGitHubRepo(repo) {
const baseApiUrl = "https://api.github.com/repos/";

// Split on slash, only valid chars
let userRepo = repo.split("/");
if (userRepo.length !== 2) return {message: "Invalid user/repo slug"};
userRepo = userRepo.map((d) => d.replace(/^[^a-z0-9-_]+/gi, ""));
const cleanedRepoSlug = userRepo.join("/");

// make url
const apiUrl = baseApiUrl + cleanedRepoSlug;

// try getting back github object
let dataObject = "";
try {
dataObject = await fetch(apiUrl).then((response) => response.json());
} catch (error) {
return {message: `Error fetching api url: '${apiUrl}'`};
}

return dataObject;
}
Insert cell
Insert cell
/**
* Get back the huh-data repo object
*/
function getHuhRepo() {
return publicGitHubRepo("zachbogart/huh-data");
}
Insert cell
Insert cell
/**
* Get an issue for a GitHub repo
* - uses publicGitHubRepo() to get the repo object
* - Pass in issue number to get back issue object
*/
async function getIssue(repo, issue_number) {
// get the issue object
let issue;
let issueUrl;
try {
issueUrl = String(
await publicGitHubRepo(repo).then((res) => res.issues_url)
);
issueUrl = issueUrl.replace("{/number}", `/${issue_number}`);
issue = fetch(issueUrl).then((response) => response.json());
} catch (error) {
return { message: "Unable to fetch issue url" };
}
return issue;
}
Insert cell
Insert cell
/**
* Get an issue from the huh-data repo
*/
async function getHuhIssue(issue_number) {
return getIssue("zachbogart/huh-data", issue_number);
}
Insert cell
Insert cell
/**
* Display an GitHub issue banner, displays info on related GitHub Issue
* - Issue title, state, labels, and more
* - Pass a github issue object
*/
async function issueBanner(issueObj) {
// check for number
if (!issueObj.number) return "Unable to get issue: no issue number"
// create banner based on state
let banner = "";
if (issueObj.state == "open") {
banner = box("hsl(139,51%,85%)"); // open issue
} else {
banner = box("hsl(261,69%,89%)"); // closed issue
}

// define banner
let bodySubstringLength = 400;
let issueBanner = banner(md`
**#${issueObj.number}: ${issueObj.title}** (${issueObj.state})

${issueObj.html_url}

*Opened by @${issueObj.user.login} on ${issueObj.created_at.split("T")[0]}*

**Labels**: *${issueObj.labels.map((d) => d.name).join(", ")}*

**Blurb**: ${
issueObj.body && issueObj.body.length > bodySubstringLength
? issueObj.body.substring(0, bodySubstringLength) + "..." + `\n\n**(truncated; see [full issue on GitHub](${issueObj.html_url}))**`
: issueObj.body
}
`);

return issueBanner;
}
Insert cell
Insert cell
/**
* Given a repo and an issue number, return an issue banner
*/
async function getIssueBanner(repo, issue_number) {
// Split on slash, only valid chars
let userRepo = repo.split("/");
if (userRepo.length !== 2) return { message: "Invalid user/repo slug" };
userRepo = userRepo.map((d) => d.replace(/^[^a-z0-9-_]+/gi, ""));
const cleanedRepoSlug = userRepo.join("/");

//API rate limit exceeded
// make banner
const banner = box("hsl(25,86%,89%)");
// make issue url
const link =
"https://github.com/" + cleanedRepoSlug + "/issues";
const emergencyBanner = banner(md`
**Problem fetching github issue**

${link}

Something went wrong. Some possibilities:
- You may have given a bad issue number
- You may have been rate-limited by the API`);

// if you've been rate limited, return emergency banner
if (await isGitHubAPiRateLimited()) return emergencyBanner

// go get issue and make banner
let x = "";
try {
x = getIssue(cleanedRepoSlug, issue_number);
} catch (error) {
return emergencyBanner
}

if ((await x).hasOwnProperty("message")) {
return emergencyBanner;
}

return issueBanner(await x);
}
Insert cell
Insert cell
testBanner("Hello World!")
Insert cell
testBanner = banner()
Insert cell
Insert cell
Insert cell
/**
* Extend banner wrapper, make banner to display
* for notebooks that are works in progress
*/
bannerWorkInProgress = banner(`hsl(57, 80%, 90%)`)(md`🛠 This notebook is a **Work in Progress**. It's actively under construction or might need more work.`)
Insert cell
Insert cell
/**
* Extend banner wrapper, make banner to display
* for notebooks that are works in progress
*/
bannerWorkItOut = banner(`hsl(200, 80.4%, 90%)`)(md`🦋 This notebook **tests something out**. Its for experimentation or for developing an idea.`)
Insert cell
Insert cell
Insert cell
Insert cell
async function isGitHubAPiRateLimited() {
return fetch("https://api.github.com/rate_limit")
.then(res => res.json())
.then(obj => obj.resources.core.remaining <= 0)
}
Insert cell
Insert cell
Insert cell
huh = ({
croissant: croissant,
linkNewTab: linkNewTab,
publicGitHubRepo: publicGitHubRepo,
getHuhRepo: getHuhRepo,
getHuhIssue: getHuhIssue,
getIssue: getIssue,
issueBanner: issueBanner,
getIssueBanner: getIssueBanner,
nounCredit: nounCredit,
banner: banner,
bannerWorkInProgress: bannerWorkInProgress,
bannerWorkItOut: bannerWorkItOut,
footer: footer
})
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more