diff --git a/apps/docs/app/routes/LandingPage.res b/apps/docs/app/routes/LandingPage.res
index aab1d4bbc..288608963 100644
--- a/apps/docs/app/routes/LandingPage.res
+++ b/apps/docs/app/routes/LandingPage.res
@@ -1,689 +1,5 @@
-module Intro = {
- @react.component
- let make = () => {
-
- // We only need this font on the homepage, so we load it here instead of globally to save some bandwidth for users who navigate to other pages directly
-
-
-
- {React.string("JavaScript Made Simple for Humans and AI")}
-
-
- {React.string(`Types > Vibes`)}
-
-
- {React.string(`ReScript is a strongly typed language that compiles to clean,
- efficient JavaScript that humans and AI tools can read and understand.`)}
-
-
- {React.string(`Its fast compiler and static type system keep feedback loops tight,
- so you can move quickly with AI assistance while maintaining
- confidence as your codebase grows.`)}
-
- // Keep the CTA link block-level so the moved top/bottom margins still affect layout after removing its wrapper.
-
-
-
-
-
- }
-}
-
-module PlaygroundHero = {
- type example = {
- res: string,
- js: string,
- }
-
- let examples = [
- {
- res: `module Button = {
- @react.component
- let make = (~count) => {
- let times = switch count {
- | 1 => "once"
- | 2 => "twice"
- | n => n->Int.toString ++ " times"
- }
- let text = \`Click me $\{times\}\`
-
-
- }
-}`,
- js: `import * as JsxRuntime from "react/jsx-runtime";
-
-function Playground$Button(props) {
- let count = props.count;
- let times = count !== 1 ? (
- count !== 2 ? count.toString() + " times" : "twice"
- ) : "once";
- let text = "Click me " + times;
- return JsxRuntime.jsx("button", {
- children: text
- });
-}
-
-let Button = {
- make: Playground$Button
-};
-
-export {
- Button,
-}`,
- },
- ]
-
- @react.component
- let make = () => {
- let (example, _setExample) = React.useState(_ => examples->Array.getUnsafe(0))
-
- //Playground Section & Background
-
-
- // `mx-auto` preserves the removed centering wrapper's max-width behavior for the playground frame.
- // Playground widget
-
-
- /* ---Link to Playground--- */
-
- {React.string("Edit this example in Playground")}
-
- //
-
-
-
-
-
-
-
-
-
-
- }
-}
-
-module QuickInstall = {
- module CopyButton = {
- let copyToClipboard: string => bool = %raw(`
- function(str) {
- try {
- const el = document.createElement('textarea');
- el.value = str;
- el.setAttribute('readonly', '');
- el.style.position = 'absolute';
- el.style.left = '-9999px';
- document.body.appendChild(el);
- const selected =
- document.getSelection().rangeCount > 0 ? document.getSelection().getRangeAt(0) : false;
- el.select();
- document.execCommand('copy');
- document.body.removeChild(el);
- if (selected) {
- document.getSelection().removeAllRanges();
- document.getSelection().addRange(selected);
- }
- return true;
- } catch(e) {
- return false;
- }
- }
- `)
-
- type state =
- | Init
- | Copied
- | Failed
-
- @react.component
- let make = (~code) => {
- let (state, setState) = React.useState(_ => Init)
-
- let buttonRef = React.useRef(Nullable.null)
-
- let onClick = evt => {
- ReactEvent.Mouse.preventDefault(evt)
- if copyToClipboard(code) {
- setState(_ => Copied)
- } else {
- setState(_ => Failed)
- }
- }
-
- React.useEffect(() => {
- switch state {
- | Copied =>
- let buttonEl = Nullable.toOption(buttonRef.current)->Option.getOrThrow
-
- // Note on this imperative DOM nonsense:
- // For Tailwind transitions to behave correctly, we need to first paint the DOM element in the tree,
- // and in the next tick, add the opacity-100 class, so the transition animation actually takes place.
- // If we don't do that, the banner will essentially pop up without any animation
- let bannerEl = WebAPI.Document.createElement(document, "div")
- bannerEl.className = "foobar opacity-0 absolute top-0 mt-4 -mr-1 px-2 rounded right-0
- bg-turtle text-gray-80-tr body-sm
- transition-all duration-500 ease-in-out "
- let textNode = WebAPI.Document.createTextNode(document, "Copied!")
-
- WebAPI.Element.appendChild(bannerEl, textNode)->ignore
- WebAPI.Element.appendChild(buttonEl, bannerEl)->ignore
-
- let nextFrameId = WebAPI.Window.requestAnimationFrame(window, _ => {
- WebAPI.DOMTokenList.toggle(bannerEl.classList, ~token="opacity-0")->ignore
- WebAPI.DOMTokenList.toggle(bannerEl.classList, ~token="opacity-100")->ignore
- })
-
- let timeoutId = setTimeout(~handler=() => {
- buttonEl->WebAPI.Element.removeChild(bannerEl)->ignore
- setState(_ => Init)
- }, ~timeout=2000)
-
- Some(
- () => {
- cancelAnimationFrame(nextFrameId)
- clearTimeout(timeoutId)
- },
- )
- | _ => None
- }
- }, [state])
-
-
- }
- }
-
- module Instructions = {
- let copyBox = text => {
-
- {React.string(text)}
-
-
- }
- @react.component
- let make = (~className: string="") => {
-
-
{React.string("Quick Install")}
-
- {React.string(
- "You can quickly add ReScript to your existing JavaScript codebase via npm / yarn:",
- )}
-
- {copyBox("npm install rescript")}
-
- {React.string("Or generate a new project from the official template with npx:")}
-
- {copyBox("npx create-rescript-app")}
-
- }
- }
-
- @react.component
- let make = () => {
-
-
- //---Textblock on the left side---
- // Keep the width clamp on the paragraph itself now that the wrapper is gone.
-
-
- {React.string(`Leverage the full power`)}
-
- {React.string(` of JavaScript in a robustly typed language without the fear of \`any\` types.`)}
-
- //spacing between columns
-
-
- {React.string(`ReScript is used to ship and maintain mission-critical products with good UI and UX.`)}
-
- // The alignment classes move onto the instructions root so the column still hugs the lower edge without an extra wrapper.
-
-
-
-
- }
-}
-
-// Main unique selling points
-module MainUSP = {
- module Item = {
- type polygonDirection = Up | Down
-
- @react.component
- let make = (
- ~caption: string,
- ~title: React.element,
- ~media: React.element=React.string("Placeholder"),
- ~polygonDirection: polygonDirection=Down,
- ~paragraph: React.element,
- ) => {
- let polyPointsLg = switch polygonDirection {
- | Down => "80,0 85,100 100,100 100,0"
- | Up => "85,0 80,100 100,100 100,0"
- }
-
- let polyPointsMobile = switch polygonDirection {
- | Down => "0,100 100,100 100,70 0,80"
- | Up => "0,100 100,100 100,78 0,72"
- }
-
- let polyColor = switch polygonDirection {
- | Up => "text-fire"
- | Down => "text-fire-30"
- }
-
-
- // Content
-
-
-
{React.string(caption)}
-
title
-
paragraph
-
- //image (right)
-
-
- media
-
-
-
-
- // Mobile SVG
-
- // Tablet / Desktop SVG
-
-
- }
- }
-
- let item1 =
-
-
- }
- paragraph={<>
-
- {React.string(`ReScript cares about a consistent and fast
- feedback loop for any codebase size. Refactor code, pull complex changes,
- or switch to feature branches as you please. No sluggish CI builds, stale
- caches, wrong type hints, or memory hungry language servers that slow you
- down.`)}
-
-
- // ReactRouter.Link.to)}>
- //
- //
-
- >}
- />
-
- let item2 =
-
- {React.string("Type Better")}
- }
- media={}
- polygonDirection=Up
- paragraph={React.string(`Every ReScript app is fully typed and provides
- reliable type information for any given value in your program. We
- prioritize simpler types over complex types for the sake of
- clarity and easy debugability. No \`any\`, no magic types, no surprise
- \`undefined\`.
- `)}
- />
-
- let item3 =
-
- {React.string("The familiar JS ecosystem")}
- {React.string(" at your fingertips")}
- >}
- media={}
- paragraph={React.string(`Use any library from JavaScript, export ReScript
- libraries to JavaScript, automatically generate TypeScript types. It's
- like you've never left the good parts of JavaScript at all.`)}
- />
-
- @react.component
- let make = () => {
-
- item1
- item2
- item3
-
- }
-}
-
-module OtherSellingPoints = {
- @react.component
- let make = () => {
-
- //defines the grid
-
- //Large Item
-
-
-
- {React.string(`A community of programmers who value getting things done`)}
-
-
- {React.string(`No language can be popular without a solid
- community. A great type system isn't useful if library authors
- abuse it. Performance doesn't show if all the libraries are slow.
- Join the ReScript community — A group of companies and individuals
- who deeply care about simplicity, speed and practicality.`)}
-
- // The forum link becomes inline-block so the moved top margin still participates in the card flow.
-
-
-
-
- // 2 small items
- // Item 2
-
-
-
- {React.string(`Tooling that just works out of the box`)}
-
-
- {React.string(`A builtin pretty printer, memory friendly
- VSCode & Vim plugins, a stable type system and compiler that doesn't require lots
- of extra configuration. ReScript brings all the tools you need to
- build reliable JavaScript, Node and ReactJS applications.`)}
-
-
- // Item 3
-
-
-
- {React.string(`Easy to adopt — without any lock-in`)}
-
-
- {React.string(`ReScript was made with gradual adoption in mind. If
- you ever want to go back to plain JavaScript, just remove all
- source files and keep its clean JavaScript output. Tell
- your coworkers that your project will keep functioning with or
- without ReScript!`)}
-
-
- //
-
-
- }
-}
-
-module TrustedBy = {
- @react.component
- let make = () => {
- let ourUsersSourcePath = "apps/docs/src/data/OurUsers.res"
-
-
-
-
- }
-}
-
@react.component
-let make = (~components=MarkdownComponents.default) => {
+let make = () => {
<>
{
confidence as your codebase grows.`}
keywords=["ReScript", "rescriptlang", "JavaScript", "JS", "TypeScript"]
/>
- // Keep the inherited typography and stacking context on the absolute shell while removing the inert wrapper chain around the page content.
- // Enable this when v13 is released
- //
- // {React.string("ReScript 12 is out! Read the ")}
- //
- // {React.string("announcement blog post")}
- //
- // {React.string(".")}
- //
-
+
-
-
-
-
-
-
+
+
+
+
+
+
diff --git a/apps/docs/app/routes/LandingPage.resi b/apps/docs/app/routes/LandingPage.resi
index 65f28d025..1ca44ce26 100644
--- a/apps/docs/app/routes/LandingPage.resi
+++ b/apps/docs/app/routes/LandingPage.resi
@@ -1,2 +1,2 @@
@react.component
-let make: (~components: MarkdownComponents.t=?) => React.element
+let make: unit => React.element
diff --git a/apps/docs/app/routes/LandingPageCuratedResources.res b/apps/docs/app/routes/LandingPageCuratedResources.res
new file mode 100644
index 000000000..dd50b0ad7
--- /dev/null
+++ b/apps/docs/app/routes/LandingPageCuratedResources.res
@@ -0,0 +1,147 @@
+type card = {
+ imgSrc: string,
+ title: string,
+ descr: string,
+ href: string,
+}
+
+type templateKind = NextJs | ViteJs | NodeJs
+
+type template = {
+ imgSrc: string,
+ kind: templateKind,
+ descr: string,
+ href: string,
+}
+
+let cards = [
+ {
+ imgSrc: "/ic_manual@2x.avif",
+ title: "Language Manual",
+ descr: "Look up the basics: Reference for all our language features",
+ href: "/docs/manual/introduction",
+ },
+ {
+ imgSrc: "/ic_rescript_react@2x.avif",
+ title: "ReScript + React",
+ descr: "First Class bindings for ReactJS used by production users all over the world.",
+ href: "/docs/react/introduction",
+ },
+ {
+ imgSrc: "/ic_manual@2x.avif",
+ title: "Gradually Adopt ReScript",
+ descr: "Learn how to start using ReScript in your current projects. Try before you buy!",
+ href: "/docs/manual/installation#integrate-into-an-existing-js-project",
+ },
+ {
+ imgSrc: "/ic_gentype@2x.avif",
+ title: "TypeScript Integration",
+ descr: "Learn how to integrate ReScript in your existing TypeScript codebases.",
+ href: "/docs/manual/typescript-integration",
+ },
+]
+
+let templates = [
+ {
+ imgSrc: "/nextjs_starter_logo.svg",
+ kind: NextJs,
+ descr: "Get started with our NextJS starter template.",
+ href: "https://github.com/rescript-lang/create-rescript-app/blob/master/templates/rescript-template-nextjs/README.md",
+ },
+ {
+ imgSrc: "/vitejs_starter_logo.svg",
+ kind: ViteJs,
+ descr: "Get started with ViteJS and ReScript.",
+ href: "https://github.com/rescript-lang/create-rescript-app/blob/master/templates/rescript-template-vite/README.md",
+ },
+ {
+ imgSrc: "/nodejs_starter_logo.svg",
+ kind: NodeJs,
+ descr: "Get started with ReScript targeting the Node platform.",
+ href: "/",
+ },
+]
+
+let renderTemplateTitle = kind => {
+ switch kind {
+ | NextJs =>
+ <>
+ {React.string("ReScript & ")}
+ {React.string("NextJS")}
+ >
+ | ViteJs =>
+ <>
+ {React.string("ReScript & ")}
+ {React.string("ViteJS")}
+ >
+ | NodeJs =>
+ <>
+ {React.string("ReScript & ")}
+
+ {React.string("NodeJS")}
+
+ >
+ }
+}
+
+@react.component
+let make = () => {
+
+
+
+ {React.string("Get up and running with ReScript")}
+
+
+}
diff --git a/apps/docs/app/routes/LandingPageCuratedResources.resi b/apps/docs/app/routes/LandingPageCuratedResources.resi
new file mode 100644
index 000000000..1ca44ce26
--- /dev/null
+++ b/apps/docs/app/routes/LandingPageCuratedResources.resi
@@ -0,0 +1,2 @@
+@react.component
+let make: unit => React.element
diff --git a/apps/docs/app/routes/LandingPageIntro.res b/apps/docs/app/routes/LandingPageIntro.res
new file mode 100644
index 000000000..1575d3e36
--- /dev/null
+++ b/apps/docs/app/routes/LandingPageIntro.res
@@ -0,0 +1,32 @@
+@react.component
+let make = () => {
+
+ // This font is only needed on the homepage.
+
+
+
+ {React.string("JavaScript Made Simple for Humans and AI")}
+
+
+ {React.string(`Types > Vibes`)}
+
+
+ {React.string(`ReScript is a strongly typed language that compiles to clean,
+ efficient JavaScript that humans and AI tools can read and understand.`)}
+
+
+ {React.string(`Its fast compiler and static type system keep feedback loops tight,
+ so you can move quickly with AI assistance while maintaining
+ confidence as your codebase grows.`)}
+
+
+
+
+
+
+}
diff --git a/apps/docs/app/routes/LandingPageIntro.resi b/apps/docs/app/routes/LandingPageIntro.resi
new file mode 100644
index 000000000..1ca44ce26
--- /dev/null
+++ b/apps/docs/app/routes/LandingPageIntro.resi
@@ -0,0 +1,2 @@
+@react.component
+let make: unit => React.element
diff --git a/apps/docs/app/routes/LandingPageMainSellingPoints.res b/apps/docs/app/routes/LandingPageMainSellingPoints.res
new file mode 100644
index 000000000..230a9e8b2
--- /dev/null
+++ b/apps/docs/app/routes/LandingPageMainSellingPoints.res
@@ -0,0 +1,122 @@
+module Item = {
+ type polygonDirection = Up | Down
+
+ @react.component
+ let make = (
+ ~caption: string,
+ ~title: React.element,
+ ~media: React.element=React.string("Placeholder"),
+ ~polygonDirection: polygonDirection=Down,
+ ~paragraph: React.element,
+ ) => {
+ let polyPointsLg = switch polygonDirection {
+ | Down => "80,0 85,100 100,100 100,0"
+ | Up => "85,0 80,100 100,100 100,0"
+ }
+ let polyPointsMobile = switch polygonDirection {
+ | Down => "0,100 100,100 100,70 0,80"
+ | Up => "0,100 100,100 100,78 0,72"
+ }
+ let polyColor = switch polygonDirection {
+ | Up => "text-fire"
+ | Down => "text-fire-30"
+ }
+
+
+ {React.string(`ReScript cares about a consistent and fast
+ feedback loop for any codebase size. Refactor code, pull complex changes,
+ or switch to feature branches as you please. No sluggish CI builds, stale
+ caches, wrong type hints, or memory hungry language servers that slow you
+ down.`)}
+
+
+ >}
+ />
+
+ {React.string("Type Better")}
+ }
+ media={}
+ polygonDirection=Up
+ paragraph={React.string(`Every ReScript app is fully typed and provides
+ reliable type information for any given value in your program. We
+ prioritize simpler types over complex types for the sake of
+ clarity and easy debugability. No \`any\`, no magic types, no surprise
+ \`undefined\`.
+ `)}
+ />
+
+ {React.string("The familiar JS ecosystem")}
+ {React.string(" at your fingertips")}
+ >}
+ media={}
+ paragraph={React.string(`Use any library from JavaScript, export ReScript
+ libraries to JavaScript, automatically generate TypeScript types. It's
+ like you've never left the good parts of JavaScript at all.`)}
+ />
+
+}
diff --git a/apps/docs/app/routes/LandingPageMainSellingPoints.resi b/apps/docs/app/routes/LandingPageMainSellingPoints.resi
new file mode 100644
index 000000000..1ca44ce26
--- /dev/null
+++ b/apps/docs/app/routes/LandingPageMainSellingPoints.resi
@@ -0,0 +1,2 @@
+@react.component
+let make: unit => React.element
diff --git a/apps/docs/app/routes/LandingPageOtherSellingPoints.res b/apps/docs/app/routes/LandingPageOtherSellingPoints.res
new file mode 100644
index 000000000..cd36192dc
--- /dev/null
+++ b/apps/docs/app/routes/LandingPageOtherSellingPoints.res
@@ -0,0 +1,61 @@
+@react.component
+let make = () => {
+
+
+
+
+
+ {React.string(`A community of programmers who value getting things done`)}
+
+
+ {React.string(`No language can be popular without a solid
+ community. A great type system isn't useful if library authors
+ abuse it. Performance doesn't show if all the libraries are slow.
+ Join the ReScript community — A group of companies and individuals
+ who deeply care about simplicity, speed and practicality.`)}
+
+ {React.string(`Tooling that just works out of the box`)}
+
+
+ {React.string(`A builtin pretty printer, memory friendly
+ VSCode & Vim plugins, a stable type system and compiler that doesn't require lots
+ of extra configuration. ReScript brings all the tools you need to
+ build reliable JavaScript, Node and ReactJS applications.`)}
+
+
+
+
+
+ {React.string(`Easy to adopt — without any lock-in`)}
+
+
+ {React.string(`ReScript was made with gradual adoption in mind. If
+ you ever want to go back to plain JavaScript, just remove all
+ source files and keep its clean JavaScript output. Tell
+ your coworkers that your project will keep functioning with or
+ without ReScript!`)}
+
+
+
+
+}
diff --git a/apps/docs/app/routes/LandingPageOtherSellingPoints.resi b/apps/docs/app/routes/LandingPageOtherSellingPoints.resi
new file mode 100644
index 000000000..1ca44ce26
--- /dev/null
+++ b/apps/docs/app/routes/LandingPageOtherSellingPoints.resi
@@ -0,0 +1,2 @@
+@react.component
+let make: unit => React.element
diff --git a/apps/docs/app/routes/LandingPagePlayground.res b/apps/docs/app/routes/LandingPagePlayground.res
new file mode 100644
index 000000000..a4211005b
--- /dev/null
+++ b/apps/docs/app/routes/LandingPagePlayground.res
@@ -0,0 +1,88 @@
+type example = {
+ res: string,
+ js: string,
+}
+
+let example = {
+ res: `module Button = {
+ @react.component
+ let make = (~count) => {
+ let times = switch count {
+ | 1 => "once"
+ | 2 => "twice"
+ | n => n->Int.toString ++ " times"
+ }
+ let text = \`Click me $\{times\}\`
+
+
+ }
+}`,
+ js: `import * as JsxRuntime from "react/jsx-runtime";
+
+function Playground$Button(props) {
+ let count = props.count;
+ let times = count !== 1 ? (
+ count !== 2 ? count.toString() + " times" : "twice"
+ ) : "once";
+ let text = "Click me " + times;
+ return JsxRuntime.jsx("button", {
+ children: text
+ });
+}
+
+let Button = {
+ make: Playground$Button
+};
+
+export {
+ Button,
+}`,
+}
+
+@react.component
+let make = () => {
+
+