Avatar

@rodrigotello

21 likes75 public vals
Joined July 18, 2022
Computing Interface Designer @ http://Val.Town

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
19
20
21
22
import { email } from "https://esm.town/v/std/email?v=9";
import { valTownInspoList } from "https://esm.town/v/rodrigotello/valTownInspoList";
export const valTownInspirationEmail = async () => {
let subject = "Daily Val Town inspiration";
let valTownInspo =
valTownInspoList[
Math.floor(
Math.random() * valTownInspoList.length,
)
];
let html = `<h1>${valTownInspo.title}</h1>
<p>${valTownInspo.description}</p>
<a href="https://val.town/${valTownInspo.val}"><img src="${valTownInspo.image}" style="max-width:576px"/></a>
<p>
</p>
<p>You're getting this email because you scheduled Val Town daily
inspiration during the onboarding tutorial. <a href="https://www.val.town/settings/intervals">
Unsubscribe here</a>.
</p>`;
await email({ html, subject });
};
1
2
3
4
export async function timeAgo(date: Date) {
const { timeAgo } = await import("https://deno.land/x/time_ago/mod.ts");
return timeAgo(new Date(date));
}
1
2
3
4
export const timeAgoAsConst = (async () => {
const { timeAgo } = await import("https://deno.land/x/time_ago/mod.ts");
return timeAgo(new Date("2023-05-21T05:44:55.000Z"));
})();
1
2
3
4
5
export const hnFollowCSS = `
/* HNFollow: Custom HTML CSS */
a {color:#3b82f6}`;
1
2
3
export function msAgo(ms) {
return new Date(Date.now() - ms);
}
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
import { hnSearch } from "https://esm.town/v/stevekrouse/hnSearch?v=16";
import { hnTagsFromUsernames } from "https://esm.town/v/andreterron/hnTagsFromUsernames?v=2";
export let hnLatestPosts = async ({
authors,
lastSyncTime,
tags,
...params
}: {
authors?: string[];
lastSyncTime?: number | string | Date;
query?: string;
search_by_date?: boolean;
tags?: string;
numericFilters?: string;
page?: number;
restrictSearchableAttributes?: string;
}) => {
let combinedTags = [
authors && (await hnTagsFromUsernames(authors)),
tags,
]
.filter(Boolean)
.join(",");
let results = await hnSearch({
tags: combinedTags,
numericFilters:
lastSyncTime && `created_at_i>${new Date(lastSyncTime).getTime() / 1000}`,
...params,
});
return results?.hits;
};
// Forked from @stevekrouse.hnLatestPosts
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
import { hnFollowCSS } from "https://esm.town/v/rodrigotello/hnFollowCSS";
import { meyerWebCSSReset } from "https://esm.town/v/rodrigotello/meyerWebCSSReset";
import { hnResultToHTML } from "https://esm.town/v/rodrigotello/hnResultToHTML";
export let hnEmail = async ({
posts,
footer,
}: {
posts: any[];
footer?: boolean; // undefined defaults to true
}) => {
let authors = Array.from(new Set(posts.map((p) => p.author))).slice(0, 3);
let subject = `[HN Follow] New from ${authors.join(", ")}`;
let postTexts = await Promise.all(
posts.map(hnResultToHTML)
);
let footer_ = [
`
<div style="background:#f1f5f9; color: #94a3b8; margin-top:40px; padding: 24px; text-align: center">
<div>Email via <a href="https://val.town/v/rodrigotello.hnFollow" style="color: #334155">HNFollowApp</a>. You can unsubscribe by clearing your intervals <a href="https://www.val.town/settings/intervals" style="color: #334155">here</a>.</div>
</div>`,
];
let html = [
`<style>${meyerWebCSSReset}; ${hnFollowCSS}</style>`,
postTexts.join("\n\n"),
...(footer === false ? [] : footer_),
].join("\n\n");
return { subject, html };
};
// Forked from @stevekrouse.hnEmail
1
2
3
4
5
6
7
8
9
10
import { valForm } from "https://esm.town/v/rodrigotello/valForm";
import { multiplicationFunctionTest } from "https://esm.town/v/rodrigotello/multiplicationFunctionTest";
export async function FunctionToHTMLForm(
req: express.Request,
res: express.Response,
) {
let myFunctionValAsHTML = multiplicationFunctionTest; // Insert your function here and it should generate an HTML form
return res.send(`${valForm(myFunctionValAsHTML)}`);
}
1
2
3
4
5
import { parseFigmaURL } from "https://esm.town/v/rodrigotello/parseFigmaURL";
export function GetFigmaFileKey(url: string) {
return parseFigmaURL(url).key;
}