Skip to content

Commit f233d14

Browse files
authored
feat: added new community content page (#980)
* feat: added new community content page * move to deps * remove jsdom * checkout master package-lock * add note * try jsdom again * remove jsdom and add generate_resources to scripts * lock * kebab-case * more kebab * gray border * more padding * tidy up for tablet
1 parent 6ac474c commit f233d14

File tree

14 files changed

+263
-16
lines changed

14 files changed

+263
-16
lines changed

data/resources.json

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
[{"title":"JavaScript schema library from the Future 🧬","description":"ReScript Schema - The fastest parser in the entire JavaScript ecosystem with a focus on small bundle... Tagged with schema, typescript, rescript, opensource.","image":"https://media2.dev.to/dynamic/image/width=1000,height=500,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn102ksd9w1xo5ysgxbur.png","url":"https://dev.to/dzakh/javascript-schema-library-from-the-future-5420"},{"title":"ReScript: A Better Typed JavaScript? (with Gabriel Nordeborn)","description":"ReScript is a strongly-typed programming language that compiles to JavaScript, and that puts it squarely in competition with TypeScript. So why would a JavaS...","image":"https://i.ytimg.com/vi/yKl2fSdnw7w/maxresdefault.jpg","url":"https://www.youtube.com/watch?v=yKl2fSdnw7w"},{"title":"GitHub - rescript-lang/awesome-rescript: A collection of materials about the ReScript programming language and toolchain.","description":"A collection of materials about the ReScript programming language and toolchain. - rescript-lang/awesome-rescript","image":"https://repository-images.githubusercontent.com/395642331/9d6aaef3-c81c-4156-8f65-45c3dbd011ac","url":"https://github.com/rescript-lang/awesome-rescript"},{"title":"An early look at @rescript/webapi","description":"Here's an early look at the new ReScript Web API bindings I've been working on.For more information, visit https://rescript-lang.github.io/experimental-rescr...","image":"https://i.ytimg.com/vi/MC-dbM-GEuw/maxresdefault.jpg","url":"https://www.youtube.com/watch?v=MC-dbM-GEuw"},{"title":"ReScript has come a long way, maybe it's time to switch from TypeScript?","description":"ReScript, the \"Fast, Simple, Fully Typed JavaScript from the Future\", has been around for awhile now.... Tagged with rescript, javascript, typescript, webdev.","image":"https://media2.dev.to/dynamic/image/width=1000,height=500,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5jrqcbteob11bc7nvwz9.jpg","url":"https://dev.to/jderochervlk/rescript-has-come-a-long-way-maybe-its-time-to-switch-from-typescript-29he"},{"title":"Create a Snake Game in ReScript","description":"Let's create a simple snake game in ReScript without using any framework.Full code here https://github.com/Exegetech/snake-rescript00:00 Getting started03:20...","image":"https://i.ytimg.com/vi/f0gDMjuaCZo/maxresdefault.jpg","url":"https://www.youtube.com/watch?v=f0gDMjuaCZo"},{"title":"ReScript and EdgeDB | Gel Blog","description":"Learn how together ReScript and EdgeDB achieve full type safety with less busy work. This post shows you the benefits and how you can get started with this pairing today!","image":"https://www.geldata.com/_images/_blog/ab9848d310c94bb25e21f219ee74b7f24ca16baa.jpg","url":"https://www.geldata.com/blog/rescript-and-edgedb"},{"title":"Building and consuming REST API in ReScript with rescript-rest and Fastify","description":"In the video, I show how you can use my ReScript Rest library to create an HTTP server with Fastify, generate OpenAPI for it, and then consume it on the clie...","image":"https://i.ytimg.com/vi/37FY6a-zY20/maxresdefault.jpg?sqp=-oaymwEmCIAKENAF8quKqQMa8AEB-AH-CYAC0AWKAgwIABABGEsgXShlMA8=&rs=AOn4CLBrz-ZJf8pcr_1_YZCfiMUwFKqj6A","url":"https://www.youtube.com/watch?v=37FY6a-zY20"},{"title":"When and Where to use ReScript? The ReScript happy path","description":"Are you ever hesitant about adopting ReScript, or have you tried it and been frustrated? I will give you a realistic guide for adopting ReScript in the project. (Hint: Review your project architecture first). Tagged with rescript, typescript, architecture.","image":"https://media2.dev.to/dynamic/image/width=1000,height=500,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fool4835vdaqw8vueb9b5.png","url":"https://dev.to/cometkim/when-and-where-to-use-rescript-the-rescript-happy-path-47ni"},{"title":"From TypeScript To ReScript | Serhii Potapov (greyblake)","description":"A blog about software development.","image":"https://www.greyblake.com/greyblake.jpeg","url":"https://www.greyblake.com/blog/from-typescript-to-rescript/"},{"title":"Getting rid of your dead code in ReScript","description":"Exploring ReScript's tools for eliminating dead code, keeping your repository clean and without... Tagged with rescript.","image":"https://media2.dev.to/dynamic/image/width=1000,height=500,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F12lsasc06v1a355i6rfk.jpeg","url":"https://dev.to/zth/getting-rid-of-your-dead-code-in-rescript-3mba"},{"title":"Rescript React Error boundary usage","description":"Hi I was trying to capture the react errors. I had to write the bindings for the ErrorBoundary and... Tagged with rescript, react.","image":"https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3otvb2z646ytpt1hl2rv.jpg","url":"https://dev.to/srikanthkyatham/rescript-react-error-boundary-usage-3b05"},{"title":"Full-stack ReScript. Architecture Overview","description":"Can ReScript be used to create a full-featured back-end? In this article, I’d try to prove it can and does it with success.\n","image":"","url":"https://fullsteak.dev/posts/fullstack-rescript-architecture-overview"},{"title":"ReScript for React Development","description":"Looking for ReScript for React Development information? In this article, I highlight the development & business advantages of ReScript.","image":"https://scalac.io/wp-content/uploads/2021/08/ReScript-for-React-Development-FB.png","url":"https://scalac.io/blog/rescript-for-react-development/"},{"title":"Rewriting a Project in ReScript","description":"My experience reimplementing a small project in ReScript","image":"","url":"https://yangdanny97.github.io/blog/2021/07/09/Migrating-to-Rescript"},{"title":"Responsive Images and Cumulative Layout Shift","description":"Solving cumulative layout shift issue caused by responsive images in layouts.","image":"https://d20bjcorj7xdk.cloudfront.net/eyJidWNrZXQiOiJpbWFnZXMuYWxleGZlZG9zZWV2LmNvbSIsImtleSI6Im1ldGEtYmxvZy5wbmciLCJlZGl0cyI6eyJyZXNpemUiOnsid2lkdGgiOjEyMDAsImhlaWdodCI6NjMwLCJmaXQiOiJjb3ZlciJ9LCJqcGVnIjp7InF1YWxpdHkiOjkwfX19?signature=d8e6c0ac1ff03d0f5ee04d128b96a7701b998952a38ba96e9a16e4414cd05ed0&version=58cfd6f8abdefeca2195a6a1f1108596","url":"https://alexfedoseev.com/blog/post/responsive-images-and-cumulative-layout-shift"},{"title":"ReScript records, NextJS, undefined and getStaticProps","description":"NextJS, a pretty solid framework for building React based websites and web-applications, offers a nic... Tagged with rescript, javascript, nextjs.","image":"https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3otvb2z646ytpt1hl2rv.jpg","url":"https://dev.to/ryyppy/rescript-records-nextjs-undefined-and-getstaticprops-4890"}]
2+

data/sidebar_community.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
{
22
"Resources": [
33
"overview",
4+
"content",
45
"roadmap",
56
"code-of-conduct",
67
"translations"
78
]
8-
}
9+
}

package.json

+3-2
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,8 @@
6363
"test": "node scripts/test-examples.mjs && node scripts/test-hrefs.mjs",
6464
"reanalyze": "reanalyze -all-cmt .",
6565
"update-index": "npm run generate-llms && node scripts/extract-indices.mjs && node scripts/extract-tocs.mjs && node scripts/extract-syntax.mjs && node scripts/generate_feed.mjs > public/blog/feed.xml",
66-
"generate-llms": "node scripts/generate_llms.mjs"
66+
"generate-llms": "node scripts/generate_llms.mjs",
67+
"generate-resources": "node scripts/generate_resources.mjs"
6768
},
6869
"devDependencies": {
6970
"@mdx-js/react": "^2.3.0",
@@ -78,4 +79,4 @@
7879
"simple-functional-loader": "^1.2.1",
7980
"tailwindcss": "^3.3.3"
8081
}
81-
}
82+
}

pages/community/content.mdx

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
---
2+
title: "Content"
3+
description: "Community Content"
4+
canonical: "/community/content"
5+
---
6+
7+
8+
import CommunityContent from 'src/CommunityContent.mjs';
9+
10+
<CommunityContent />

pages/community/overview.mdx

+1-9
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ description: "Community Resources Overview"
44
canonical: "/community/overview"
55
---
66

7-
# Community
7+
# Community Overview
88

99
## Official Channels
1010

@@ -14,19 +14,11 @@ canonical: "/community/overview"
1414
- [Forum](https://forum.rescript-lang.org)
1515
- [ReScript GitHub Org](https://github.com/rescript-lang/)
1616
- [ReScript YouTube Channel](https://www.youtube.com/@rescriptlang)
17-
- [ReScript Online Meetup on Guild](https://guild.host/rescript-online-meetup)
18-
- [ReScript Online Meetup YouTube Channel](https://www.youtube.com/@ReScriptOnlineMeetup)
1917

2018
News are broadcasted on this site's blog, on Bluesky and X. Some extra, less important news are also posted on the forum's [Announcements category](https://forum.rescript-lang.org/c/announcements/).
2119

2220
**We don't use any other channel to communicate officially**. Any announcement made by users on Reddit, Discord, Medium and others don't necessarily represent our intent.
2321

24-
## Articles
25-
26-
- [Getting rid of your dead code in ReScript](https://dev.to/zth/getting-rid-of-your-dead-code-in-rescript-3mba)
27-
- [Speeding up ReScript compilation using interface files](https://dev.to/zth/speeding-up-rescript-compilation-using-interface-files-4fgn)
28-
- Articles in [awesome-rescript](https://github.com/fhammerschmidt/awesome-rescript#readme)
29-
3022
## Questions
3123

3224
Your questions can go on:

pages/docs/manual/v11.0.0/faq.mdx

+5-1
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,11 @@ Our focus is a solid JS story right now. In the future, if there’s strong dema
4242

4343
**What’s the current state of ReScript?**
4444

45-
Currently, we're actively working on the editor support.
45+
We're working on the v12.0 release (see [v12 milestone](https://github.com/rescript-lang/rescript/milestone/16)).
46+
47+
- Move the [Rescript Core](https://github.com/rescript-lang/rescript-core) standard library into the compiler / remove the OCaml standard library
48+
- A new build system tailored to ReScript's needs ([rewatch](https://github.com/teamwalnut/rewatch)) for better monorepo support and even faster compilation speed
49+
- Make it easier to create libraries for consumption from TypeScript with GenType
4650

4751
**When will we get the `async/await` keywords?**
4852

pages/docs/manual/v12.0.0/faq.mdx

+5-1
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,11 @@ Our focus is a solid JS story right now. In the future, if there’s strong dema
4242

4343
**What’s the current state of ReScript?**
4444

45-
Currently, we're actively working on the editor support.
45+
We're working on the v12.0 release (see [v12 milestone](https://github.com/rescript-lang/rescript/milestone/16)).
46+
47+
- Move the [Rescript Core](https://github.com/rescript-lang/rescript-core) standard library into the compiler / remove the OCaml standard library
48+
- A new build system tailored to ReScript's needs ([rewatch](https://github.com/teamwalnut/rewatch)) for better monorepo support and even faster compilation speed
49+
- Make it easier to create libraries for consumption from TypeScript with GenType
4650

4751
**When will we get the `async/await` keywords?**
4852

scripts/generate_resources.res

+50
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/** This is the list of community content we want to generate. */
2+
/** If you have content you would like to add, please open up a PR adding the link to this list and then run `npm run generate-resources` */
3+
let urls = [
4+
// 2025
5+
"https://dev.to/dzakh/javascript-schema-library-from-the-future-5420",
6+
"https://www.youtube.com/watch?v=yKl2fSdnw7w",
7+
"https://github.com/rescript-lang/awesome-rescript", // regardless of age this seems like it should always be near the top
8+
// 2024
9+
"https://www.youtube.com/watch?v=MC-dbM-GEuw",
10+
"https://dev.to/jderochervlk/rescript-has-come-a-long-way-maybe-its-time-to-switch-from-typescript-29he",
11+
"https://www.youtube.com/watch?v=f0gDMjuaCZo",
12+
"https://www.geldata.com/blog/rescript-and-edgedb",
13+
"https://www.youtube.com/watch?v=37FY6a-zY20",
14+
// 2023
15+
"https://dev.to/cometkim/when-and-where-to-use-rescript-the-rescript-happy-path-47ni",
16+
// 2022
17+
"https://www.greyblake.com/blog/from-typescript-to-rescript/",
18+
"https://dev.to/zth/getting-rid-of-your-dead-code-in-rescript-3mba",
19+
"https://www.youtube.com/watch?v=KDL-kRgilkQ",
20+
"https://dev.to/srikanthkyatham/rescript-react-error-boundary-usage-3b05",
21+
// "https://www.daggala.com/belt_vs_js_array_in_rescript/" I think we should exclude this one since it's related to API we are deprecating
22+
// 2021
23+
"https://fullsteak.dev/posts/fullstack-rescript-architecture-overview",
24+
"https://scalac.io/blog/rescript-for-react-development/",
25+
"https://yangdanny97.github.io/blog/2021/07/09/Migrating-to-Rescript",
26+
"https://alexfedoseev.com/blog/post/responsive-images-and-cumulative-layout-shift",
27+
"https://dev.to/ryyppy/rescript-records-nextjs-undefined-and-getstaticprops-4890",
28+
]
29+
30+
let generate = async () => {
31+
let filePath = "data/resources.json"
32+
let metaData = await MetaTagsApi.getMetaTags(urls)
33+
34+
let fileContent = `${metaData
35+
->Array.map(i =>
36+
{
37+
"title": `${i.title->Option.getOr("")}`,
38+
"description": `${i.description->Option.getOr("")}`,
39+
"image": `${i.image->Option.getOr("")}`,
40+
"url": `${i.url}`,
41+
}
42+
)
43+
->JSON.stringifyAny
44+
->Option.getOr("[]")}
45+
`
46+
47+
Node.Fs.writeFileSync(filePath, fileContent)
48+
}
49+
50+
await generate()

src/CommunityContent.res

+68
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
type link = {
2+
url: string,
3+
title: string,
4+
description: string,
5+
image: string,
6+
}
7+
8+
@module("../data/resources.json")
9+
external resources: array<link> = "default"
10+
11+
let simplifyUrl = url =>
12+
url
13+
->String.replace("https://", "")
14+
->String.replace("http://", "")
15+
->String.split("/")
16+
->Array.at(0)
17+
18+
module LinkCard = {
19+
@react.component
20+
let make = (~link) => {
21+
<div className="rounded-lg hover:text-fire overflow-hidden bg-gray-10 border-2 border-gray-30">
22+
<a href=link.url className="flex flex-col h-full">
23+
<img className="object-cover w-full lg:h-40 max-h-[345px]" src=link.image alt="" />
24+
<div className="p-3 md:p-5 grow">
25+
<h3 className="font-semibold text-16 grow-0 mb-2"> {React.string(link.title)} </h3>
26+
<p className="mb-2 text-14 grow text-gray-80"> {React.string(link.description)} </p>
27+
</div>
28+
<p className="text-14 p-3 md:p-5 grow-0 text-gray-70">
29+
{React.string(link.url->simplifyUrl->Option.getOr(""))}
30+
</p>
31+
</a>
32+
</div>
33+
}
34+
}
35+
36+
module LinkCards = {
37+
@react.component
38+
let make = () => {
39+
<div className="grid lg:grid-cols-2 gap-6">
40+
{resources
41+
->Array.map(link =>
42+
switch link.image {
43+
| "" => {...link, image: "/static/Art-3-rescript-launch.jpg"}
44+
| _ => link
45+
}
46+
)
47+
->Array.map(link => <LinkCard link key=link.title />)
48+
->React.array}
49+
</div>
50+
}
51+
}
52+
53+
@react.component
54+
let make = () => {
55+
<div>
56+
<h1 className="hl-1 mb-6"> {"Community Content"->React.string} </h1>
57+
<p className="md-p md:leading-5 tracking-[-0.015em] text-gray-80 md:text-16 mb-16">
58+
{React.string(
59+
"These articles, videos, and resources are created by the amazing ReScript community.",
60+
)}
61+
<br />
62+
{React.string("If you have a resource you'd like to share, please feel free to submit a PR!")}
63+
</p>
64+
<LinkCards />
65+
</div>
66+
}
67+
68+
let default = make

src/bindings/Jsdom.res

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
type window = {document: Dom.document}
2+
type t = {window: window}
3+
4+
@module("jsdom") @new
5+
external make: string => t = "JSDOM"

src/bindings/Webapi.res

+6
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,11 @@ module Document = {
22
@val external document: Dom.element = "document"
33
@scope("document") @val external createElement: string => Dom.element = "createElement"
44
@scope("document") @val external createTextNode: string => Dom.element = "createTextNode"
5+
@send
6+
external querySelector: (Dom.document, string) => Nullable.t<Dom.element> = "querySelector"
7+
@send
8+
external querySelectorAll: (Dom.document, string) => Js.Array2.array_like<Dom.element> =
9+
"querySelectorAll"
510
}
611

712
module ClassList = {
@@ -17,6 +22,7 @@ module Element = {
1722
@get external classList: Dom.element => ClassList.t = "classList"
1823
@send external getBoundingClientRect: Dom.element => {..} = "getBoundingClientRect"
1924
@send external addEventListener: (Dom.element, string, unit => unit) => unit = "addEventListener"
25+
@send external getAttribute: (Dom.element, string) => Nullable.t<string> = "getAttribute"
2026

2127
@send
2228
external getElementById: (Dom.element, string) => Nullable.t<Dom.element> = "getElementById"

src/common/MetaTagsApi.res

+93
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
type t = {
2+
title: option<string>,
3+
description: option<string>,
4+
image: option<string>,
5+
}
6+
7+
/**
8+
This function uses JSDOM to fetch a webpage and extract the meta tags from it.
9+
JSDOM is required since this runs on Node.
10+
*/
11+
let extractMetaTags = async (url: string) => {
12+
open Webapi
13+
try {
14+
let response = await Fetch.fetch(url)
15+
16+
let html = await response->Fetch.Response.text
17+
let dom = Jsdom.make(html)
18+
let document = dom.window.document
19+
20+
let metaTags =
21+
document
22+
->Document.querySelectorAll("meta")
23+
->Array.fromArrayLike
24+
->Array.reduce(Dict.fromArray([]), (tags, meta) => {
25+
let name = meta->Element.getAttribute("name")->Nullable.toOption
26+
let property = meta->Element.getAttribute("property")->Nullable.toOption
27+
let itemprop = meta->Element.getAttribute("itemprop")->Nullable.toOption
28+
29+
let name = switch (name, property, itemprop) {
30+
| (Some(name), _, _) => Some(name)
31+
| (_, Some(property), _) => Some(property)
32+
| (_, _, Some(itemprop)) => Some(itemprop)
33+
| _ => None
34+
}
35+
36+
let content = meta->Element.getAttribute("content")->Nullable.toOption
37+
38+
switch (name, content) {
39+
| (Some(name), Some(content)) => tags->Dict.set(name, content)
40+
| _ => ()
41+
}
42+
43+
tags
44+
})
45+
46+
let title = metaTags->Dict.get("og:title")
47+
let description = metaTags->Dict.get("og:description")
48+
let image = metaTags->Dict.get("og:image")
49+
50+
Some({
51+
title,
52+
description,
53+
image,
54+
})
55+
} catch {
56+
| _ => {
57+
Console.error(`Error fetching Open Graph details for ${url}`)
58+
None
59+
}
60+
}
61+
}
62+
63+
type tags = {
64+
...t,
65+
url: string,
66+
}
67+
68+
/*
69+
Pass an array of URLs and get back an array of meta tags for each URL.
70+
*/
71+
let getMetaTags = async (urls: array<string>) => {
72+
let metaTags: array<tags> = []
73+
for i in 0 to Array.length(urls) - 1 {
74+
let url = urls[i]
75+
switch url {
76+
| Some(url) => {
77+
let tags = await extractMetaTags(url)
78+
switch tags {
79+
| Some(tags) =>
80+
metaTags->Array.push({
81+
title: tags.title,
82+
description: tags.description,
83+
image: tags.image,
84+
url,
85+
})
86+
| None => ()
87+
}
88+
}
89+
| None => ()
90+
}
91+
}
92+
metaTags
93+
}

src/components/Button.res

+7-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,12 @@ type size = Small | Large
33
/* type theme = Light | Dark */
44

55
@react.component
6-
let make = (~kind: kind=PrimaryRed, ~size: size=Large, ~children) => {
6+
let make = (
7+
~kind: kind=PrimaryRed,
8+
~size: size=Large,
9+
~children,
10+
~onClick: option<JsxEventU.Mouse.t => unit>=?,
11+
) => {
712
let bgColor = switch kind {
813
| PrimaryRed => "bg-fire hover:bg-fire-70 text-white"
914
| PrimaryBlue => "bg-sky hover:bg-sky-70 text-white"
@@ -16,6 +21,7 @@ let make = (~kind: kind=PrimaryRed, ~size: size=Large, ~children) => {
1621
}
1722

1823
<button
24+
?onClick
1925
role="button"
2026
className={`select-none hover:cursor-pointer transition-colors duration-200 body-button focus:outline-none ${bgColor} ${padding}`}>
2127
children

src/components/Button.resi

+6-1
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,9 @@ type kind = PrimaryRed | PrimaryBlue | SecondaryRed
22
type size = Small | Large
33

44
@react.component
5-
let make: (~kind: kind=?, ~size: size=?, ~children: React.element) => React.element
5+
let make: (
6+
~kind: kind=?,
7+
~size: size=?,
8+
~children: React.element,
9+
~onClick: JsxEventU.Mouse.t => unit=?,
10+
) => React.element

0 commit comments

Comments
 (0)