Skip to content
This repository was archived by the owner on Nov 8, 2022. It is now read-only.

ReScript Support #20

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all 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
1 change: 1 addition & 0 deletions packages/example-rescript/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
VITE_GITHUB_TOKEN=ghp_abcdefghijklmnop
8 changes: 8 additions & 0 deletions packages/example-rescript/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
node_modules/
dist/
__generated__/
*.local
lib/
.bsb.lock
.merlin
*.mjs
14 changes: 14 additions & 0 deletions packages/example-rescript/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# New Vilay App

## Setup

- Install dependencies with your favorite package manager (`npm install`, `yarn`, `pnpm install`, ...)

## Scripts

```sh
npm run relay # Run Relay compiler (add -w for watch mode)
npm run dev # Run development server
npm run build # Build for production
npm run start # Launch production SSR server
```
40 changes: 40 additions & 0 deletions packages/example-rescript/bsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
{
"name": "vilay-example-rescript",
"sources": [
{
"dir": "components",
"subdirs": true
},
{
"dir": "pages",
"subdirs": true
},
{
"dir": "renderer",
"subdirs": true
},
{
"dir": "__generated__",
"subdirs": true
}
],
"package-specs": [
{
"module": "es6",
"in-source": true
}
],
"suffix": ".mjs",
"reason": {
"react-jsx": 3
},
"ppx-flags": [
"rescript-relay/ppx"
],
"bs-dependencies": [
"@rescript/react",
"rescript-relay",
"rescript-vilay",
"rescript-webapi"
]
}
12 changes: 12 additions & 0 deletions packages/example-rescript/components/Button.res
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
@react.component
let make = (~type_=?, ~className=?, ~onClick=?, ~disabled=?, ~children) => {
<button
?type_
?onClick
?disabled
className={`border border-gray-500 rounded-lg px-2 py-1 transition-colors hover:bg-gray-100 ${className->Belt.Option.getWithDefault(
"",
)}`}>
children
</button>
}
25 changes: 25 additions & 0 deletions packages/example-rescript/components/issues/Issue.res
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
open Belt

module Fragment = %relay(`
fragment Issue_issue on Issue {
title
author {
login
}
createdAt
url
}
`)

@react.component
let make = (~issue) => {
let data = Fragment.use(issue)

<div>
<a href={data.url} className="text-lg underline transition-colors hover:text-gray-500">
<h3> {React.string(data.title)} </h3>
</a>
<p> {React.string(data.author->Option.mapWithDefault("", a => a.login))} </p>
<p> {React.string(data.createdAt->Js.Date.fromString->Js.Date.toLocaleString)} </p>
</div>
}
95 changes: 95 additions & 0 deletions packages/example-rescript/components/issues/IssueList.res
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
open Belt

module Fragment = %relay(`
fragment IssueList_repository on Repository
@refetchable(queryName: "IssueListPaginationQuery")
@argumentDefinitions(
filter: { type: "IssueFilters" }
) {
issues(
after: $cursor
first: $first
orderBy: { field: CREATED_AT, direction: DESC }
filterBy: $filter
) @connection(key: "issuesPageQuery_issues") {
edges {
node {
id
...Issue_issue
}
}
pageInfo {
hasNextPage
}
}
}
`)

@react.component
let make = (~repository) => {
let {data, loadNext, isLoadingNext, refetch} = Fragment.usePagination(repository)
let (onlyOpened, setOnlyOpened) = React.useState(() => None)
let (_, startTransition) = ReactExperimental.useTransition()

React.useEffect1(() => {
switch onlyOpened {
| Some(onlyOpened) =>
// `startTransition()` keeps the previous content temporarily while the new content is loading.
startTransition(() => {
refetch(
~variables=Fragment.makeRefetchVariables(
~filter=Some({
states: onlyOpened ? Some([#OPEN]) : None,
assignee: None,
createdBy: None,
labels: None,
mentioned: None,
milestone: None,
since: None,
viewerSubscribed: None,
}),
(),
),
(),
)->ignore
})
| _ => ()
}
None
}, [onlyOpened])

let toggleMsg = switch onlyOpened {
| Some(true) => "ON"
| _ => "OFF"
}

<div className="py-4">
<Button onClick={_ => setOnlyOpened(prev => Some(!Option.getWithDefault(prev, false)))}>
{React.string(`Toggle opened filter: ${toggleMsg}`)}
</Button>
<ul className="list-disc">
{data.issues.edges
->Option.getWithDefault([])
->Array.keepMap(edge =>
switch edge {
| Some({node: Some({id, fragmentRefs})}) =>
Some(
<li key={id} className="ml-4 my-2">
<React.Suspense fallback={React.string(`Issue loading...`)}>
<Issue issue={fragmentRefs} />
</React.Suspense>
</li>,
)
| _ => None
}
)
->React.array}
</ul>
{switch (isLoadingNext, data.issues.pageInfo.hasNextPage) {
| (true, _) => React.string(`Loading more...`)
| (_, true) =>
<Button onClick={_ => loadNext(~count=10, ())->ignore}> {React.string(`Load more`)} </Button>
| _ => React.null
}}
</div>
}
33 changes: 33 additions & 0 deletions packages/example-rescript/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
{
"name": "vilay-example-rescript",
"type": "module",
"private": true,
"scripts": {
"relay": "rescript-relay-compiler",
"dev": "concurrently \"rescript-relay-compiler -w\" \"rescript build -w\" \"vilay dev\"",
"build": "rescript-relay-compiler && rescript && vilay build",
"start": "vilay start"
},
"dependencies": {
"@babel/runtime": "^7.17.9",
"@rescript/react": "^0.10.3",
"babel-plugin-relay": "^13.2.0",
"react": "^18.1.0",
"react-dom": "^18.1.0",
"react-error-boundary": "^3.1.4",
"react-relay": "^13.2.0",
"relay-runtime": "^13.2.0",
"rescript-relay": "1.0.0-beta.21",
"rescript-vilay": "workspace:^*",
"rescript-webapi": "^0.6.1",
"vilay": "^0.0.20"
},
"devDependencies": {
"@unocss/reset": "^0.30.8",
"concurrently": "^7.1.0",
"relay-compiler": "^13.2.0",
"rescript": "^9.1.4",
"unocss": "^0.30.8",
"vite": "^2.9.6"
}
}
64 changes: 64 additions & 0 deletions packages/example-rescript/pages/index.page.res
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
open Belt

module Query = %relay(`
query pagesIndexQuery {
repository(owner: "XiNiHa", name: "vilay") {
name
stargazerCount
issues(first: 0) {
totalCount
}
openedIssues: issues(first: 0, filterBy: { states: OPEN }) {
totalCount
}
}
}
`)

@react.component
let make = (~queryRef) => {
let data = Query.usePreloaded(~queryRef, ())

let listItems = [
<> {React.string(`Name: ${data.repository->Option.mapWithDefault("", r => r.name)}`)} </>,
<>
{React.string(
`Stars: ${data.repository->Option.mapWithDefault(0, r => r.stargazerCount)->Int.toString}`,
)}
</>,
<>
{React.string(
`
Issues: ${data.repository
->Option.mapWithDefault(0, r => r.issues.totalCount)
->Int.toString} (${data.repository
->Option.mapWithDefault(0, r => r.openedIssues.totalCount)
->Int.toString} open)
`,
)}
</>,
]

<>
<h2 className="text-2xl mb-4"> {React.string(`Welcome!`)} </h2>
<p>
{React.string(`
This is the main page for the template, rendered with some of the
actual information about the template repository:
`)}
</p>
<ul className="pl-4">
{listItems
->Array.mapWithIndex((i, item) =>
<li
key={Int.toString(i)}
className="my-2 w-fit list-disc border-b border-black border-dashed hover:bg-blue-50 transition-colors duration-400">
{item}
</li>
)
->React.array}
</ul>
</>
}

let query = PagesIndexQuery_graphql.node
43 changes: 43 additions & 0 deletions packages/example-rescript/pages/repo/@owner/@name/issues.page.res
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// Variables used in this query is constructed using the `getQueryVariables()` on preload.
module Query = %relay(`
query issuesPageQuery(
$owner: String!
$name: String!
$cursor: String
$first: Int!
) {
repository(name: $name, owner: $owner) {
...IssueList_repository
}
}
`)

let default = Vilay.make(
// This overrides the application-wide <head> tag definition in `_default.page.tsx`
~head=Js.Obj.assign(Head.head, {"title": "Issues: Vite SSR app"}),
// If a page has `getQueryVariables` exported, it'll be called to get the variables used for preloading the query.
// If it's not exported, route params will be directly used as variables.
~getQueryVariables=routeParams =>
Query.makeVariables(~first=10, ~owner=routeParams["owner"], ~name=routeParams["name"], ()),
(),
)

// Relay pagination example.
@react.component
let make = (~queryRef) => {
let data = Query.usePreloaded(~queryRef, ())

<>
<h2 className="text-2xl"> {React.string(`Issues`)} </h2>
<p> {React.string(`This page is for demonstrating paginated queries.`)} </p>
{switch data.repository {
| Some({fragmentRefs}) =>
<React.Suspense fallback={React.string("Loading...")}>
<IssueList repository={fragmentRefs} />
</React.Suspense>
| None => React.null
}}
</>
}

let query = IssuesPageQuery_graphql.node
Loading