Skip to content

Add community blog and first blog post #946

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
author: josh-derocher-vlk
date: "2025-01-01"
previewImg: /static/blog/compiler_release_11_1.jpg
title: What can I do with ReScript?
description: |
Can I use Vite, or Next.js? Is it only for React? Can I use Node or Deno?
---
7 changes: 7 additions & 0 deletions pages/blog/community.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import BlogRes from "src/Blog.mjs";

export { getStaticProps_Community as getStaticProps } from "src/Blog.mjs";

export default function Blog(props) {
return <BlogRes {...props} />
}
4 changes: 3 additions & 1 deletion pages/community/overview.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,19 @@ canonical: "/community/overview"

- This website
- [Twitter](https://twitter.com/rescriptlang)
- [BlueSky](https://bsky.app/profile/rescript-lang.org)
- [Forum](https://forum.rescript-lang.org)
- [ReScript GitHub Org](https://github.com/rescript-lang/)
- [ReScript Online Meetup on Guild](https://guild.host/rescript-online-meetup)
- [ReScript Online Meetup YouTube Channel](https://www.youtube.com/@ReScriptOnlineMeetup)

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

**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.

## Articles

- [Community Blog](https://rescript-lang.org/blog/community)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you make that link relative?

- [Getting rid of your dead code in ReScript](https://dev.to/zth/getting-rid-of-your-dead-code-in-rescript-3mba)
- [Speeding up ReScript compilation using interface files](https://dev.to/zth/speeding-up-rescript-compilation-using-interface-files-4fgn)
- Articles in [awesome-rescript](https://github.com/fhammerschmidt/awesome-rescript#readme)
Expand Down
26 changes: 20 additions & 6 deletions src/Blog.res
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,14 @@ module Badge = {
}

type category =
| /** Actually only unarchived */ All
| Official
| Community
| Archived

module CategorySelector = {
@react.component
let make = (~selected: category) => {
let tabs = [All, Archived]
let tabs = [Official, Community, Archived]

<div className="text-16 w-full flex items-center justify-between text-gray-60">
{tabs
Expand All @@ -56,7 +57,8 @@ module CategorySelector = {
let isActive = selected == tab
let text = (tab :> string)
let href = switch tab {
| All => "/blog"
| Official => "/blog"
| Community => "/blog/community"
| Archived => "/blog/archived"
}
let className =
Expand Down Expand Up @@ -170,7 +172,10 @@ module FeatureCard = {
<div>
<a
className="hover:text-gray-60"
href={"https://twitter.com/" ++ author.twitter}
href={switch author.social {
| Twitter(handle) => "https://twitter.com/" ++ handle
| BlueSky(handle) => "https://bsky.app/profile/" ++ handle
}}
rel="noopener noreferrer">
{React.string(author.fullname)}
</a>
Expand Down Expand Up @@ -297,17 +302,26 @@ let default = (props: props): React.element => {
let getStaticProps_All: Next.GetStaticProps.t<props, params> = async _ctx => {
let props = {
posts: BlogApi.getLivePosts(),
category: All,
category: Official,
}

{"props": props}
}

let getStaticProps_Archived: Next.GetStaticProps.t<props, params> = async _ctx => {
let props = {
posts: BlogApi.getArchivedPosts(),
posts: BlogApi.getSpecialPosts("archive"),
category: Archived,
}

{"props": props}
}

let getStaticProps_Community: Next.GetStaticProps.t<props, params> = async _ctx => {
let props = {
posts: BlogApi.getSpecialPosts("community"),
category: Community,
}

{"props": props}
}
3 changes: 2 additions & 1 deletion src/Blog.resi
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@ let defaultPreviewImg: string
type params
type props

type category = All | Archived
type category = Official | Community | Archived

let default: props => React.element

let getStaticProps_All: Next.GetStaticProps.t<props, params>
let getStaticProps_Archived: Next.GetStaticProps.t<props, params>
let getStaticProps_Community: Next.GetStaticProps.t<props, params>
7 changes: 5 additions & 2 deletions src/BlogArticle.res
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,10 @@ module AuthorBox = {
<div className="w-10 h-10 bg-berry-40 block rounded-full mr-3"> authorImg </div>
<div className="body-sm">
<a
href={"https://twitter.com/" ++ author.twitter}
href={switch author.social {
| Twitter(handle) => "https://twitter.com/" ++ handle
| BlueSky(handle) => "https://bsky.app/profile/" ++ handle
}}
className="hover:text-gray-80"
rel="noopener noreferrer">
{React.string(author.fullname)}
Expand Down Expand Up @@ -205,7 +208,7 @@ let default = (props: props) => {
let getStaticProps: Next.GetStaticProps.t<props, Params.t> = async ctx => {
open Next.GetStaticProps
let {params} = ctx

Js.Console.log(params)
let path = switch BlogApi.getAllPosts()->Js.Array2.find(({path}) =>
BlogApi.blogPathToSlug(path) == params.slug
) {
Expand Down
35 changes: 26 additions & 9 deletions src/common/BlogApi.res
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ type post = {
}

let blogPathToSlug = path => {
path->Js.String2.replaceByRe(%re(`/^(archive\/)?\d\d\d\d-\d\d-\d\d-(.+)\.mdx$/`), "$2")
path->Js.String2.replaceByRe(%re(`/^(archive|community\/)?\d\d\d\d-\d\d-\d\d-(.+)\.mdx$/`), "$2")
}

let mdxFiles = dir => {
Expand All @@ -49,6 +49,7 @@ let mdxFiles = dir => {
let getAllPosts = () => {
let postsDirectory = Node.Path.join2(Node.Process.cwd(), "_blogposts")
let archivedPostsDirectory = Node.Path.join2(postsDirectory, "archive")
let communityPostsDirectory = Node.Path.join2(postsDirectory, "community")

let nonArchivedPosts = mdxFiles(postsDirectory)->Js.Array2.map(path => {
let {GrayMatter.data: data} =
Expand Down Expand Up @@ -76,7 +77,23 @@ let getAllPosts = () => {
}
})

Js.Array2.concat(nonArchivedPosts, archivedPosts)->Js.Array2.sortInPlaceWith((a, b) => {
let communityPosts = mdxFiles(communityPostsDirectory)->Js.Array2.map(path => {
let {GrayMatter.data: data} =
Node.Path.join2(communityPostsDirectory, path)->Node.Fs.readFileSync->GrayMatter.matter
switch BlogFrontmatter.decode(data) {
| Error(msg) => Js.Exn.raiseError(msg)
| Ok(d) => {
path: Node.Path.join2("community", path),
frontmatter: d,
archived: false,
}
}
})

Js.Array2.concatMany(
nonArchivedPosts,
[archivedPosts, communityPosts],
)->Js.Array2.sortInPlaceWith((a, b) => {
String.compare(Node.Path.basename(b.path), Node.Path.basename(a.path))
})
}
Expand All @@ -102,24 +119,24 @@ let getLivePosts = () => {
})
}

let getArchivedPosts = () => {
let getSpecialPosts = directory => {
let postsDirectory = Node.Path.join2(Node.Process.cwd(), "_blogposts")
let archivedPostsDirectory = Node.Path.join2(postsDirectory, "archive")
let specialPostsDirectory = Node.Path.join2(postsDirectory, directory)

let archivedPosts = mdxFiles(archivedPostsDirectory)->Js.Array2.map(path => {
let specialPosts = mdxFiles(specialPostsDirectory)->Js.Array2.map(path => {
let {GrayMatter.data: data} =
Node.Path.join2(archivedPostsDirectory, path)->Node.Fs.readFileSync->GrayMatter.matter
Node.Path.join2(specialPostsDirectory, path)->Node.Fs.readFileSync->GrayMatter.matter
switch BlogFrontmatter.decode(data) {
| Error(msg) => Js.Exn.raiseError(msg)
| Ok(d) => {
path: Node.Path.join2("archive", path),
path: Node.Path.join2(directory, path),
frontmatter: d,
archived: true,
archived: directory === "archive",
}
}
})

archivedPosts->Js.Array2.sortInPlaceWith((a, b) => {
specialPosts->Js.Array2.sortInPlaceWith((a, b) => {
String.compare(Node.Path.basename(b.path), Node.Path.basename(a.path))
})
}
Expand Down
2 changes: 1 addition & 1 deletion src/common/BlogApi.resi
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ type post = {

let getAllPosts: unit => array<post>
let getLivePosts: unit => array<post>
let getArchivedPosts: unit => array<post>
let getSpecialPosts: string => array<post>
let blogPathToSlug: string => string

module RssFeed: {
Expand Down
27 changes: 18 additions & 9 deletions src/common/BlogFrontmatter.res
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
type social = Twitter(string) | BlueSky(string)

type author = {
username: string,
fullname: string,
role: string,
imgUrl: string,
twitter: string,
social: social,
}

let authors = [
Expand All @@ -12,56 +14,63 @@ let authors = [
fullname: "Hongbo Zhang",
role: "Compiler & Build System",
imgUrl: "https://pbs.twimg.com/profile_images/1369548222314598400/E2y46vrB_400x400.jpg",
twitter: "bobzhang1988",
social: Twitter("bobzhang1988"),
},
{
username: "chenglou",
fullname: "Cheng Lou",
role: "Syntax & Tools",
imgUrl: "https://pbs.twimg.com/profile_images/554199709909131265/Y5qUDaCB_400x400.jpeg",
twitter: "_chenglou",
social: Twitter("_chenglou"),
},
{
username: "maxim",
fullname: "Maxim Valcke",
role: "Syntax Lead",
imgUrl: "https://pbs.twimg.com/profile_images/970271048812974080/Xrr8Ob6J_400x400.jpg",
twitter: "_binary_search",
social: Twitter("_binary_search"),
},
{
username: "ryyppy",
fullname: "Patrick Ecker",
role: "Documentation",
imgUrl: "https://pbs.twimg.com/profile_images/1388426717006544897/B_a7D4GF_400x400.jpg",
twitter: "ryyppy",
social: Twitter("ryyppy"),
},
{
username: "rickyvetter",
fullname: "Ricky Vetter",
role: "ReScript & React",
imgUrl: "https://pbs.twimg.com/profile_images/541111032207273984/DGsZmmfr_400x400.jpeg",
twitter: "rickyvetter",
social: Twitter("rickyvetter"),
},
{
username: "made_by_betty",
fullname: "Bettina Steinbrecher",
role: "Brand / UI / UX",
imgUrl: "https://pbs.twimg.com/profile_images/1366785342704136195/3IGyRhV1_400x400.jpg",
twitter: "made_by_betty",
social: Twitter("made_by_betty"),
},
{
username: "rescript-team",
fullname: "ReScript Team",
role: "Core Development",
imgUrl: "https://pbs.twimg.com/profile_images/1358354824660541440/YMKNWE1V_400x400.png",
twitter: "rescriptlang",
social: Twitter("rescriptlang"),
},
{
username: "rescript-association",
fullname: "ReScript Association",
role: "Foundation",
imgUrl: "https://pbs.twimg.com/profile_images/1045362176117100545/MioTQoTp_400x400.jpg",
twitter: "ReScriptAssoc",
social: Twitter("ReScriptAssoc"),
},
{
username: "josh-derocher-vlk",
fullname: "Josh Derocher-Vlk",
role: "Community Member",
imgUrl: "https://cdn.bsky.app/img/avatar/plain/did:plc:erifxn5qcos2zrxvogse5y5s/bafkreif6v7lrtz24vi5ekumkiwg7n7js55coekszduwhjegfmdopd7tqmi@webp",
social: BlueSky("vlkpack.com"),
},
]

Expand Down