├── .gitignore ├── README.md ├── bsconfig.json ├── package.json ├── src ├── deck.mdx ├── images │ ├── astrocoders.png │ ├── astrocoders.svg │ ├── download.jpeg │ ├── fnm.svg │ ├── glitch-bust.jpeg │ ├── glitch-contrast.jpg │ ├── glitch-contrast.png │ ├── glitch-unsettling.jpg │ ├── glitched-coffee.jpg │ ├── glitched-faces.mp4 │ ├── perspective.jpg │ ├── reasonml-architechture.svg │ ├── refs.txt │ ├── revery.png │ ├── stinks.jpg │ ├── stonks.jpg │ ├── unbreakable.jpg │ └── vaporwave-glitch.jpg ├── juice │ ├── CodeSurfer.bs.js │ ├── CodeSurfer.re │ ├── CodeSurferHighlighter.js │ ├── GlitchImage.bs.js │ ├── GlitchImage.re │ ├── Hooks.bs.js │ ├── Hooks.re │ ├── Image.bs.js │ ├── Image.re │ ├── Paragraph.bs.js │ ├── Paragraph.re │ ├── SplitLayout.bs.js │ ├── SplitLayout.re │ ├── Title.js │ ├── VideoBackground.bs.js │ └── VideoBackground.re └── snippets │ ├── GraphQLDemo.graphql │ ├── GraphQLDemo.re │ ├── PatternMatchingDemo.bs.js │ ├── PatternMatchingDemo.re │ ├── PatternMatchingDemo.ts │ ├── PatternMatchingDemo2.ts │ ├── PatternMatchingDemo3.ts │ ├── PatternMatchingDemoError.bs.js │ ├── PatternMatchingDemoError.re │ ├── VariantDemo.bs.js │ ├── VariantDemo.re │ ├── VariantDemoSwitch.ts │ └── VariantDemoTypes.ts └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | public 3 | .merlin 4 | lib/ 5 | .bsb.lock 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ReasonML/ES2077 - ReactConf Dev 2 | 3 | mdx-deck presentation. 4 | 5 | Components were done in Reason and JS to demo interop. 6 | 7 | ### References 8 | 9 | https://reasonml.chat 10 | 11 | https://khoanguyen.me/reasonml-toolchain/ 12 | 13 | https://medium.com/astrocoders/render-props-composition-for-reasonml-is-here-b9c004ca9fcb 14 | 15 | https://github.com/astrocoders/lenses-ppx 16 | 17 | https://github.com/revery-ui/revery 18 | 19 | https://github.com/Schniz/fnm/ 20 | 21 | https://github.com/andreas/ocaml-graphql-server 22 | 23 | https://reasonml.github.io/reason-react/ 24 | 25 | https://reasonml.github.io 26 | 27 | https://github.com/mhallin/graphql_ppx 28 | -------------------------------------------------------------------------------- /bsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "deck", 3 | "reason": { 4 | "react-jsx": 3 5 | }, 6 | "sources": { 7 | "dir": "src", 8 | "subdirs": [ 9 | { "dir": "juice" } 10 | ] 11 | }, 12 | "package-specs": [{ 13 | "module": "commonjs", 14 | "in-source": true 15 | }], 16 | "suffix": ".bs.js", 17 | "namespace": true, 18 | "bs-dependencies": [ 19 | "reason-react", 20 | "bs-css" 21 | ], 22 | "refmt": 3 23 | } 24 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "es2077-reactconf", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "mdx-deck src/deck.mdx", 8 | "bs:build": "bsb -make-world", 9 | "build": "yarn bs:build && mdx-deck build src/deck.mdx", 10 | "deck:publish": "yarn build && gh-pages -d public", 11 | "watch": "bsb -make-world -w" 12 | }, 13 | "author": "", 14 | "license": "ISC", 15 | "devDependencies": { 16 | "mdx-deck": "^3.0.9" 17 | }, 18 | "dependencies": { 19 | "aug-attr-spliced": "^0.2.0", 20 | "augmented-ui": "^1.1.0", 21 | "bs-css": "^10.0.1", 22 | "bs-platform": "^5.0.6", 23 | "gh-pages": "^2.1.1", 24 | "mdx-code": "^1.1.3", 25 | "prism-react-renderer": "^0.1.7", 26 | "qrcode.react": "^0.9.3", 27 | "reason-react": "^0.7.0", 28 | "styled-components": "^4.3.2" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/deck.mdx: -------------------------------------------------------------------------------- 1 | import { Image, Head, Notes, Appear, } from 'mdx-deck' 2 | import highlight from '@mdx-deck/themes/syntax-highlighter-prism' 3 | import QRCode from 'qrcode.react' 4 | 5 | import { Title } from './juice/Title' 6 | import Paragraph from './juice/Paragraph.bs' 7 | import SplitLayout from './juice/SplitLayout.bs' 8 | import ImageFit from './juice/Image.bs' 9 | import GlitchImage from './juice/GlitchImage.bs' 10 | import VideoBackground from './juice/VideoBackground.bs' 11 | import CodeSurfer from './juice/CodeSurfer.bs' 12 | 13 | import glitchFacesVideo from './images/glitched-faces.mp4' 14 | 15 | import glitchUnsettlingImage from './images/glitch-unsettling.jpg' 16 | import glitchContrastImage from './images/glitch-contrast.png' 17 | import glitchUnbreakableImage from './images/unbreakable.jpg' 18 | import glitchPerspectiveImage from './images/perspective.jpg' 19 | import glitchBust from './images/glitch-bust.jpeg' 20 | import astrocodersImage from './images/astrocoders.png' 21 | 22 | import fnmImage from './images/fnm.svg' 23 | import reveryImage from './images/revery.png' 24 | 25 | import variantSnippet from '!raw-loader!./snippets/VariantDemo.re' 26 | import variantTypesTsSnippet from '!raw-loader!./snippets/VariantDemoTypes.ts' 27 | import variantSwitchTsSnippet from '!raw-loader!./snippets/VariantDemoSwitch.ts' 28 | 29 | import patternMatchingDemoTS from '!raw-loader!./snippets/PatternMatchingDemo.ts' 30 | import patternMatchingDemoTS2 from '!raw-loader!./snippets/PatternMatchingDemo2.ts' 31 | import patternMatchingDemoTS3 from '!raw-loader!./snippets/PatternMatchingDemo3.ts' 32 | import patternMatchingDemoReason from '!raw-loader!./snippets/PatternMatchingDemo.re' 33 | import patternMatchingDemoReasonError from '!raw-loader!./snippets/PatternMatchingDemoError.re' 34 | import graphQLDemo from '!raw-loader!./snippets/GraphQLDemo.graphql' 35 | import graphQLDemoReason from '!raw-loader!./snippets/GraphQLDemo.re' 36 | 37 | import reasonmlToolchain from './images/reasonml-architechture.svg' 38 | import stinks from './images/stinks.jpg' 39 | import stonks from './images/stonks.jpg' 40 | 41 | export const themes = [ 42 | highlight 43 | ] 44 | 45 | 46 | Unbreakable apps with ECMAScript 2077 47 | 48 | 49 | 50 | 51 | 52 | 53 | ## Incoming from the future 54 | 55 | --- 56 | 57 | 58 | ReasonML 59 | 60 | 61 | --- 62 | 63 | 64 | 65 |
66 |

Gabriel R. Abreu

67 |

Astrocoders

68 |

CTO Founder

69 |

Father

70 |

Bad Jokes Engineer

71 |

Creator of Epitath (hooks prior art)

72 |

and ReForm

73 |
74 |
75 | 76 | --- 77 | 78 | @fakenickels 79 | 80 | 81 | Twitter, GitHub, Reddit, Instagram 82 | 83 | --- 84 | 85 | 86 | 87 |
88 | 89 |
90 | 91 | Slides 92 | 93 |
94 | 95 | --- 96 | 97 | What's ReasonML? 98 | 99 | 107 | 108 | --- 109 | 110 | 111 | 112 | 113 | 114 | # Put types in JS 115 | 116 | 117 | 118 | --- 119 | 120 | 121 | 122 | 123 | # Put JS in types 124 | 125 | 126 | 127 | --- 128 | 129 | 130 | 131 | 132 | How unbreakable? 133 | 134 | 135 | --- 136 | 137 | # Let's get philosophical 138 | 139 | >"Philosophically speaking, a problem is composed of many possible branches/conditions. Mishandling these conditions is the majority of what we call bugs." 140 | 141 | --- 142 | 143 | # Let's get philosophical 144 | 145 | >"A type system doesn't magically eliminate bugs; it points out the unhandled conditions and asks you to cover them" 146 | 147 | --- 148 | 149 | 158 | 159 | --- 160 | 161 | 162 | 163 | 164 |
165 | Contrast 166 | with TypeScript 167 |
168 |
169 | 170 | --- 171 | 172 | # Types 173 | 174 | 182 | 183 | --- 184 | 185 | # Pattern matching? 186 | 187 | 197 | 198 | --- 199 | 200 | # Not your grandma! 201 | 202 |
203 | 204 | Reason's type system is not just a powerful linter. 205 | You use it to model your program from top to bottom. 206 | 207 |
208 | 209 | --- 210 | 211 | # ReasonML ❤️ React 212 | 213 | --- 214 | 215 | # React demo 216 | 217 | 229 | 230 | --- 231 | 232 | # TS version 233 | 234 | 243 | 244 | --- 245 | 246 | # TS version 247 | 248 | 255 | 256 | --- 257 | 258 | # TS version 259 | 260 | 267 | 268 | --- 269 | 270 | # ReasonML 271 | 272 | 280 | 281 | --- 282 | 283 | 284 | 285 | 286 | Statically known types 287 | 288 | 289 | --- 290 | 291 | GraphQL 292 | 293 | --- 294 | 295 | # GraphQL 296 | 297 | 305 | 306 | --- 307 | 308 | # ReasonML 309 | 310 | 323 | 324 | --- 325 | 326 | This is less tests 327 | 328 | --- 329 | 330 | This is less bugs to production 331 | 332 | --- 333 | 334 | This is the future 335 | 336 | --- 337 | 338 | # Shared ecosystem 339 | 340 | - ReasonML brings together the OCaml community and the JS community 341 | - OCaml brings the safety and robustness the web needs 342 | 343 | --- 344 | 345 | # JS Shared ecosystem 346 | 347 | - Install it with `npm i --global bs-platform` 348 | - Or with a starter `bsb -init demo` 349 | - Or with a React starter `bsb -init demo -theme react-hooks` 350 | 351 | --- 352 | 353 | # Native ecosystem 354 | 355 | - Install it with `npm i --global esy pesy` 356 | - Or with a starter `mkdir demo && cd demo && pesy` 357 | 358 | --- 359 | 360 | 361 | 362 | 363 | ReasonML toolchain 364 | 365 | 366 | --- 367 | 368 | 369 | 370 | --- 371 | 372 | # Tools of the ecosystem 373 | 374 | - BuckleScript 375 | - esy.sh 376 | - Revery 377 | 378 | --- 379 | 380 | BuckleScript 381 | 382 |
    383 |
  • Created by Bloomberg as a better alternative to js_of_ocaml
  • 384 | 385 |
  • Powered by the ninja compiler, insane compile time
  • 386 |
  • Readable output
  • 387 |
    388 |
389 | 390 | --- 391 | 392 | esy.sh 393 | 394 |
    395 |
  • Brings npm concepts for OCaml ecosystem and package manager (OPAM)
  • 396 | 397 |
  • Created also by Jordan Walke
  • 398 |
  • Easiness to create pre-compiled and multiplatform programs
  • 399 |
  • Created with esy:
  • 400 |
    401 |
402 | 403 | --- 404 | 405 | 406 | 407 | 408 |
409 | fnm 410 | Fast and simple Node.js version manager, built in native ReasonML 411 |
412 |
413 | 414 | --- 415 | 416 | 417 | 418 |
419 | Revery 420 | Build native, high-performance, cross-platform desktop apps with Reason! 421 |
422 |
423 | 424 | --- 425 | 426 | 427 | 428 | Unsettling 429 | 430 | 431 | --- 432 | 433 | Problems 434 | 435 |
436 |
    437 |
  • Mindset change
  • 438 | 439 |
  • Syntax errors
  • 440 |
  • Docs are sparse sometimes
  • 441 |
  • Community is growing at a fast pace, but you may still not find everything you need
  • 442 |
    443 |
444 |
445 | 446 | --- 447 | 448 | 449 | 450 |
451 | 452 |
453 | 454 |
455 | discord.gg/reasonml 456 | 457 | 458 | I just heard about Reason at ReactConf Brazil! 459 | 460 |
461 | 462 |
463 | 464 | --- 465 | 466 | 467 |
468 | 469 |
470 | 471 |
472 | Astrocoders 473 |
    474 |
  • https://vannamei.com.br
  • 475 |
  • https://astrocoders.com
  • 476 |
  • https://github.com/Astrocoders
  • 477 |
  • https://github.com/Astrocoders/fullstack-challenge
  • 478 |
479 |
480 | 481 |
482 | 483 | --- 484 | 485 | 486 | 487 | 488 |
489 | Thank you! 490 | Obrigado! 491 | 謝謝! 492 |
493 |
494 | 495 | --- 496 | 497 | 498 | 499 | 500 | Questions? 501 | 502 | -------------------------------------------------------------------------------- /src/images/astrocoders.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fakenickels/es2077-reactconf/03ec80b25ca40bf4c3d8d2f66cd415c0b33ba8f1/src/images/astrocoders.png -------------------------------------------------------------------------------- /src/images/astrocoders.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/images/download.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fakenickels/es2077-reactconf/03ec80b25ca40bf4c3d8d2f66cd415c0b33ba8f1/src/images/download.jpeg -------------------------------------------------------------------------------- /src/images/fnm.svg: -------------------------------------------------------------------------------- 1 | cat.nvmrceval`fnmeval`fnmenv`ffnfnmfnm--version1.15.0cateval10.9.0fnminstallVersionv10.9.0wassuccessfullydownloadedfnmuseUsingv10.9.0nodenode-vv10.9.0eevevaeval`eval`feval`fneval`fnmeeval`fnmeneval`fnmenvfnm-fnm--fnm--vfnm--vefnm--verfnm--versfnm--versifnm--versioccacat.cat.ncat.nvcat.nvmcat.nvmrfnmifnminfnminsfnminstfnminstafnmusnnonodnode- -------------------------------------------------------------------------------- /src/images/glitch-bust.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fakenickels/es2077-reactconf/03ec80b25ca40bf4c3d8d2f66cd415c0b33ba8f1/src/images/glitch-bust.jpeg -------------------------------------------------------------------------------- /src/images/glitch-contrast.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fakenickels/es2077-reactconf/03ec80b25ca40bf4c3d8d2f66cd415c0b33ba8f1/src/images/glitch-contrast.jpg -------------------------------------------------------------------------------- /src/images/glitch-contrast.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fakenickels/es2077-reactconf/03ec80b25ca40bf4c3d8d2f66cd415c0b33ba8f1/src/images/glitch-contrast.png -------------------------------------------------------------------------------- /src/images/glitch-unsettling.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fakenickels/es2077-reactconf/03ec80b25ca40bf4c3d8d2f66cd415c0b33ba8f1/src/images/glitch-unsettling.jpg -------------------------------------------------------------------------------- /src/images/glitched-coffee.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fakenickels/es2077-reactconf/03ec80b25ca40bf4c3d8d2f66cd415c0b33ba8f1/src/images/glitched-coffee.jpg -------------------------------------------------------------------------------- /src/images/glitched-faces.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fakenickels/es2077-reactconf/03ec80b25ca40bf4c3d8d2f66cd415c0b33ba8f1/src/images/glitched-faces.mp4 -------------------------------------------------------------------------------- /src/images/perspective.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fakenickels/es2077-reactconf/03ec80b25ca40bf4c3d8d2f66cd415c0b33ba8f1/src/images/perspective.jpg -------------------------------------------------------------------------------- /src/images/reasonml-architechture.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /src/images/refs.txt: -------------------------------------------------------------------------------- 1 | https://www.reddit.com/r/glitch_art/comments/bpbnsb/cool_glitch_art_i_stumbled_upon/ 2 | https://www.reddit.com/r/glitch_art/comments/d8ywvc/džⱦⱦϟ_and_æŵĥĭɣ/ 3 | https://i.imgur.com/tREJVZG.jpg 4 | -------------------------------------------------------------------------------- /src/images/revery.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fakenickels/es2077-reactconf/03ec80b25ca40bf4c3d8d2f66cd415c0b33ba8f1/src/images/revery.png -------------------------------------------------------------------------------- /src/images/stinks.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fakenickels/es2077-reactconf/03ec80b25ca40bf4c3d8d2f66cd415c0b33ba8f1/src/images/stinks.jpg -------------------------------------------------------------------------------- /src/images/stonks.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fakenickels/es2077-reactconf/03ec80b25ca40bf4c3d8d2f66cd415c0b33ba8f1/src/images/stonks.jpg -------------------------------------------------------------------------------- /src/images/unbreakable.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fakenickels/es2077-reactconf/03ec80b25ca40bf4c3d8d2f66cd415c0b33ba8f1/src/images/unbreakable.jpg -------------------------------------------------------------------------------- /src/images/vaporwave-glitch.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fakenickels/es2077-reactconf/03ec80b25ca40bf4c3d8d2f66cd415c0b33ba8f1/src/images/vaporwave-glitch.jpg -------------------------------------------------------------------------------- /src/juice/CodeSurfer.bs.js: -------------------------------------------------------------------------------- 1 | // Generated by BUCKLESCRIPT VERSION 5.0.6, PLEASE EDIT WITH CARE 2 | 'use strict'; 3 | 4 | var Css = require("bs-css/src/Css.js"); 5 | var React = require("react"); 6 | var MdxDeck = require("mdx-deck"); 7 | var Belt_Array = require("bs-platform/lib/js/belt_Array.js"); 8 | var CodeSurferHighlighter = require("./CodeSurferHighlighter"); 9 | 10 | var make = CodeSurferHighlighter.Highlighter; 11 | 12 | var Highlighter = /* module */[/* make */make]; 13 | 14 | function CodeSurfer(Props) { 15 | var code = Props.code; 16 | var language = Props.language; 17 | var highlights = Props.highlights; 18 | var length = highlights.length + 1 | 0; 19 | var currentStep = MdxDeck.useSteps(length); 20 | var noSurfing = currentStep === length || currentStep === 0; 21 | return React.createElement("div", { 22 | className: Css.style(/* :: */[ 23 | Css.height(Css.vh(100)), 24 | /* :: */[ 25 | Css.width(Css.vw(100)), 26 | /* :: */[ 27 | Css.padding(Css.px(30)), 28 | /* :: */[ 29 | Css.backgroundColor(Css.hex("fbfbfb")), 30 | /* :: */[ 31 | Css.fontSize(Css.px(30)), 32 | /* :: */[ 33 | Css.display(/* flex */-1010954439), 34 | /* :: */[ 35 | Css.alignItems(Css.center), 36 | /* :: */[ 37 | Css.justifyContent(Css.center), 38 | /* [] */0 39 | ] 40 | ] 41 | ] 42 | ] 43 | ] 44 | ] 45 | ] 46 | ]) 47 | }, React.createElement(make, { 48 | code: code, 49 | language: language, 50 | noSurfing: noSurfing, 51 | currentHighlights: Belt_Array.get(highlights, currentStep - 1 | 0) 52 | })); 53 | } 54 | 55 | var make$1 = CodeSurfer; 56 | 57 | var $$default = CodeSurfer; 58 | 59 | exports.Highlighter = Highlighter; 60 | exports.make = make$1; 61 | exports.$$default = $$default; 62 | exports.default = $$default; 63 | exports.__esModule = true; 64 | /* make Not a pure module */ 65 | -------------------------------------------------------------------------------- /src/juice/CodeSurfer.re: -------------------------------------------------------------------------------- 1 | type range = (int, int); 2 | 3 | module Highlighter = { 4 | [@bs.module "./CodeSurferHighlighter"] [@react.component] 5 | external make: 6 | ( 7 | ~code: string, 8 | ~language: string, 9 | ~noSurfing: bool, 10 | ~currentHighlights: option(range) 11 | ) => 12 | React.element = 13 | "Highlighter"; 14 | }; 15 | 16 | [@react.component] 17 | let make = (~code, ~language, ~highlights: array(range)) => { 18 | let length = Array.length(highlights) + 1; 19 | let currentStep = Hooks.useSteps(length); 20 | let noSurfing = currentStep == length || currentStep == 0; 21 | 22 |
35 | Belt.Array.get(currentStep - 1)} 40 | /> 41 |
; 42 | }; 43 | 44 | let default = make; 45 | -------------------------------------------------------------------------------- /src/juice/CodeSurferHighlighter.js: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import Highlight, { defaultProps } from "prism-react-renderer"; 3 | import theme from "prism-react-renderer/themes/nightOwlLight" 4 | 5 | export const Highlighter = ({ code, language, currentHighlights = [NaN, NaN], noSurfing }) => 6 | 7 | {({ className, style, tokens, getLineProps, getTokenProps }) => ( 8 |
 9 |         {tokens.map((line, i) => {
10 |           const { style: prismStyle, ...props } = getLineProps({ line, key: i })
11 |           const style = {
12 |             ...prismStyle,
13 |             opacity: noSurfing || (i+1 >= currentHighlights[0] && i+1 <= currentHighlights[1]) ? 1 : 0.5,
14 |             transition: 'opacity ease-out 0.3s'
15 |           }
16 | 
17 |           return (
18 |             
19 | {line.map((token, key) => ( 20 | 21 | ))} 22 |
23 | ) 24 | })} 25 |
26 | )} 27 |
28 | 29 | -------------------------------------------------------------------------------- /src/juice/GlitchImage.bs.js: -------------------------------------------------------------------------------- 1 | // Generated by BUCKLESCRIPT VERSION 5.0.6, PLEASE EDIT WITH CARE 2 | 'use strict'; 3 | 4 | var Css = require("bs-css/src/Css.js"); 5 | var React = require("react"); 6 | var Caml_option = require("bs-platform/lib/js/caml_option.js"); 7 | 8 | function wrapper(src) { 9 | return Css.style(/* :: */[ 10 | Css.width(Css.pct(100)), 11 | /* :: */[ 12 | Css.height(Css.pct(100)), 13 | /* :: */[ 14 | Css.backgroundImage(/* `url */[ 15 | 5843823, 16 | src 17 | ]), 18 | /* :: */[ 19 | Css.backgroundRepeat(Css.noRepeat), 20 | /* :: */[ 21 | Css.backgroundSize(Css.cover), 22 | /* :: */[ 23 | Css.overflow(Css.hidden), 24 | /* :: */[ 25 | Css.position(Css.relative), 26 | /* [] */0 27 | ] 28 | ] 29 | ] 30 | ] 31 | ] 32 | ] 33 | ]); 34 | } 35 | 36 | var glitchAnimation1Horizontal = Css.keyframes(/* :: */[ 37 | /* tuple */[ 38 | 0, 39 | /* :: */[ 40 | Css.unsafe("clip-path", "polygon(0 2%, 100% 2%, 100% 5%, 0 5%)"), 41 | /* [] */0 42 | ] 43 | ], 44 | /* :: */[ 45 | /* tuple */[ 46 | 5, 47 | /* :: */[ 48 | Css.unsafe("clip-path", "polygon(0 15%, 100% 15%, 100% 15%, 0 15%)"), 49 | /* [] */0 50 | ] 51 | ], 52 | /* :: */[ 53 | /* tuple */[ 54 | 10, 55 | /* :: */[ 56 | Css.unsafe("clip-path", "polygon(0 10%, 100% 10%, 100% 20%, 0 20%)"), 57 | /* [] */0 58 | ] 59 | ], 60 | /* :: */[ 61 | /* tuple */[ 62 | 15, 63 | /* :: */[ 64 | Css.unsafe("clip-path", "polygon(0 1%, 100% 1%, 100% 2%, 0 2%)"), 65 | /* [] */0 66 | ] 67 | ], 68 | /* :: */[ 69 | /* tuple */[ 70 | 20, 71 | /* :: */[ 72 | Css.unsafe("clip-path", "polygon(0 33%, 100% 33%, 100% 33%, 0 33%)"), 73 | /* [] */0 74 | ] 75 | ], 76 | /* :: */[ 77 | /* tuple */[ 78 | 25, 79 | /* :: */[ 80 | Css.unsafe("clip-path", "polygon(0 44%, 100% 44%, 100% 44%, 0 44%)"), 81 | /* [] */0 82 | ] 83 | ], 84 | /* :: */[ 85 | /* tuple */[ 86 | 30, 87 | /* :: */[ 88 | Css.unsafe("clip-path", "polygon(0 50%, 100% 50%, 100% 20%, 0 20%)"), 89 | /* [] */0 90 | ] 91 | ], 92 | /* :: */[ 93 | /* tuple */[ 94 | 35, 95 | /* :: */[ 96 | Css.unsafe("clip-path", "polygon(0 70%, 100% 70%, 100% 70%, 0 70%)"), 97 | /* [] */0 98 | ] 99 | ], 100 | /* :: */[ 101 | /* tuple */[ 102 | 40, 103 | /* :: */[ 104 | Css.unsafe("clip-path", "polygon(0 80%, 100% 80%, 100% 80%, 0 80%)"), 105 | /* [] */0 106 | ] 107 | ], 108 | /* :: */[ 109 | /* tuple */[ 110 | 45, 111 | /* :: */[ 112 | Css.unsafe("clip-path", "polygon(0 50%, 100% 50%, 100% 55%, 0 55%)"), 113 | /* [] */0 114 | ] 115 | ], 116 | /* :: */[ 117 | /* tuple */[ 118 | 50, 119 | /* :: */[ 120 | Css.unsafe("clip-path", "polygon(0 70%, 100% 70%, 100% 80%, 0 80%)"), 121 | /* [] */0 122 | ] 123 | ], 124 | /* :: */[ 125 | /* tuple */[ 126 | 51, 127 | /* :: */[ 128 | Css.unsafe("clip-path", "polygon(0 0, 0 0)"), 129 | /* [] */0 130 | ] 131 | ], 132 | /* :: */[ 133 | /* tuple */[ 134 | 100, 135 | /* :: */[ 136 | Css.unsafe("clip-path", "polygon(0 0, 0 0)"), 137 | /* [] */0 138 | ] 139 | ], 140 | /* [] */0 141 | ] 142 | ] 143 | ] 144 | ] 145 | ] 146 | ] 147 | ] 148 | ] 149 | ] 150 | ] 151 | ] 152 | ] 153 | ]); 154 | 155 | function glitch(src, $staropt$star, bgColor, blendMode, $staropt$star$1, param) { 156 | var animDuration = $staropt$star !== undefined ? $staropt$star : 600; 157 | var animationName = $staropt$star$1 !== undefined ? Caml_option.valFromOption($staropt$star$1) : glitchAnimation1Horizontal; 158 | return Css.style(/* :: */[ 159 | Css.position(Css.absolute), 160 | /* :: */[ 161 | Css.top(Css.zero), 162 | /* :: */[ 163 | Css.left(Css.zero), 164 | /* :: */[ 165 | Css.width(Css.pct(110)), 166 | /* :: */[ 167 | Css.height(Css.pct(110)), 168 | /* :: */[ 169 | Css.backgroundImage(Css.url(src)), 170 | /* :: */[ 171 | Css.backgroundRepeat(Css.noRepeat), 172 | /* :: */[ 173 | Css.backgroundColor(bgColor), 174 | /* :: */[ 175 | Css.backgroundPosition(Css.pct(50), Css.zero), 176 | /* :: */[ 177 | Css.backgroundSize(Css.cover), 178 | /* :: */[ 179 | Css.animation(animDuration, undefined, Css.alternateReverse, undefined, undefined, undefined, Css.infinite, animationName), 180 | /* :: */[ 181 | Css.unsafe("backgroundBlendMode", blendMode), 182 | /* [] */0 183 | ] 184 | ] 185 | ] 186 | ] 187 | ] 188 | ] 189 | ] 190 | ] 191 | ] 192 | ] 193 | ] 194 | ]); 195 | } 196 | 197 | var Styles = /* module */[ 198 | /* wrapper */wrapper, 199 | /* glitchAnimation1Horizontal */glitchAnimation1Horizontal, 200 | /* glitch */glitch 201 | ]; 202 | 203 | function GlitchImage(Props) { 204 | var src = Props.src; 205 | var bgColor = /* `hex */[ 206 | 5194459, 207 | "fff" 208 | ]; 209 | var blendMode = "hard-light"; 210 | return React.createElement("div", { 211 | className: wrapper(src) 212 | }, React.createElement("div", { 213 | className: glitch(src, 2300, bgColor, blendMode, undefined, /* () */0) 214 | }), React.createElement("div", { 215 | className: glitch(src, 2400, /* `hex */[ 216 | 5194459, 217 | "000" 218 | ], blendMode, undefined, /* () */0) 219 | }), React.createElement("div", { 220 | className: glitch(src, 2500, bgColor, blendMode, undefined, /* () */0) 221 | }), React.createElement("div", { 222 | className: glitch(src, 2000, /* `hex */[ 223 | 5194459, 224 | "000" 225 | ], "overlay", undefined, /* () */0) 226 | })); 227 | } 228 | 229 | var make = GlitchImage; 230 | 231 | var $$default = GlitchImage; 232 | 233 | exports.Styles = Styles; 234 | exports.make = make; 235 | exports.$$default = $$default; 236 | exports.default = $$default; 237 | exports.__esModule = true; 238 | /* glitchAnimation1Horizontal Not a pure module */ 239 | -------------------------------------------------------------------------------- /src/juice/GlitchImage.re: -------------------------------------------------------------------------------- 1 | /* Reference https://tympanus.net/Tutorials/CSSGlitchEffect/index.html */ 2 | 3 | module Styles = { 4 | open Css; 5 | 6 | let wrapper = (~src) => style([ 7 | width(pct(100.)), 8 | height(pct(100.)), 9 | backgroundImage(`url(src)), 10 | backgroundRepeat(noRepeat), 11 | backgroundSize(cover), 12 | overflow(hidden), 13 | position(relative), 14 | ]); 15 | 16 | let glitchAnimation1Horizontal = keyframes([ 17 | (0, [ 18 | unsafe("clip-path", "polygon(0 2%, 100% 2%, 100% 5%, 0 5%)"), 19 | ]), 20 | (5, [ 21 | unsafe("clip-path", "polygon(0 15%, 100% 15%, 100% 15%, 0 15%)"), 22 | ]), 23 | (10, [ 24 | unsafe("clip-path", "polygon(0 10%, 100% 10%, 100% 20%, 0 20%)"), 25 | ]), 26 | (15, [ 27 | unsafe("clip-path", "polygon(0 1%, 100% 1%, 100% 2%, 0 2%)"), 28 | ]), 29 | (20, [ 30 | unsafe("clip-path", "polygon(0 33%, 100% 33%, 100% 33%, 0 33%)"), 31 | ]), 32 | (25, [ 33 | unsafe("clip-path", "polygon(0 44%, 100% 44%, 100% 44%, 0 44%)"), 34 | ]), 35 | (30, [ 36 | unsafe("clip-path", "polygon(0 50%, 100% 50%, 100% 20%, 0 20%)"), 37 | ]), 38 | (35, [ 39 | unsafe("clip-path", "polygon(0 70%, 100% 70%, 100% 70%, 0 70%)"), 40 | ]), 41 | (40, [ 42 | unsafe("clip-path", "polygon(0 80%, 100% 80%, 100% 80%, 0 80%)"), 43 | ]), 44 | (45, [ 45 | unsafe("clip-path", "polygon(0 50%, 100% 50%, 100% 55%, 0 55%)"), 46 | ]), 47 | (50, [ 48 | unsafe("clip-path", "polygon(0 70%, 100% 70%, 100% 80%, 0 80%)"), 49 | ]), 50 | (51, [ 51 | unsafe("clip-path", "polygon(0 0, 0 0)"), 52 | ]), 53 | (100, [ 54 | unsafe("clip-path", "polygon(0 0, 0 0)"), 55 | ]), 56 | ]) 57 | 58 | let glitch = (~src, ~animDuration=600, ~bgColor, ~blendMode, ~animationName=glitchAnimation1Horizontal, ()) => style([ 59 | position(absolute), 60 | top(zero), 61 | left(zero), 62 | width(pct(110.)), 63 | height(pct(110.)), 64 | backgroundImage(url(src)), 65 | backgroundRepeat(noRepeat), 66 | backgroundColor(bgColor), 67 | backgroundPosition(pct(50.), zero), 68 | backgroundSize(cover), 69 | animation(~duration=animDuration, ~direction=alternateReverse, ~iterationCount=infinite, animationName), 70 | unsafe("backgroundBlendMode", blendMode) 71 | ]) 72 | }; 73 | 74 | 75 | [@react.component] 76 | let make = (~src) => { 77 | let bgColor = `hex("fff"); 78 | let blendMode = "hard-light"; 79 | let baseDuration = 1500; 80 | 81 |
82 |
83 |
84 |
85 |
86 |
87 | } 88 | 89 | let default = make 90 | -------------------------------------------------------------------------------- /src/juice/Hooks.bs.js: -------------------------------------------------------------------------------- 1 | // Generated by BUCKLESCRIPT VERSION 5.0.6, PLEASE EDIT WITH CARE 2 | /* This output is empty. Its source's type definitions, externals and/or unused code got optimized away. */ 3 | -------------------------------------------------------------------------------- /src/juice/Hooks.re: -------------------------------------------------------------------------------- 1 | [@bs.module "mdx-deck"] external useSteps : int => int = "useSteps"; 2 | -------------------------------------------------------------------------------- /src/juice/Image.bs.js: -------------------------------------------------------------------------------- 1 | // Generated by BUCKLESCRIPT VERSION 5.0.6, PLEASE EDIT WITH CARE 2 | 'use strict'; 3 | 4 | var Css = require("bs-css/src/Css.js"); 5 | var React = require("react"); 6 | 7 | function $$Image(Props) { 8 | var src = Props.src; 9 | return React.createElement("img", { 10 | className: Css.style(/* :: */[ 11 | Css.maxWidth(Css.pct(100)), 12 | /* [] */0 13 | ]), 14 | src: src 15 | }); 16 | } 17 | 18 | var make = $$Image; 19 | 20 | var $$default = $$Image; 21 | 22 | exports.make = make; 23 | exports.$$default = $$default; 24 | exports.default = $$default; 25 | exports.__esModule = true; 26 | /* Css Not a pure module */ 27 | -------------------------------------------------------------------------------- /src/juice/Image.re: -------------------------------------------------------------------------------- 1 | [@react.component] 2 | let make = (~src) => { 3 | 4 | } 5 | 6 | let default = make 7 | -------------------------------------------------------------------------------- /src/juice/Paragraph.bs.js: -------------------------------------------------------------------------------- 1 | // Generated by BUCKLESCRIPT VERSION 5.0.6, PLEASE EDIT WITH CARE 2 | 'use strict'; 3 | 4 | var Css = require("bs-css/src/Css.js"); 5 | var React = require("react"); 6 | 7 | function Paragraph(Props) { 8 | var children = Props.children; 9 | return React.createElement("p", { 10 | className: Css.style(/* :: */[ 11 | Css.padding(Css.px(30)), 12 | /* :: */[ 13 | Css.textAlign(Css.center), 14 | /* [] */0 15 | ] 16 | ]) 17 | }, children); 18 | } 19 | 20 | var make = Paragraph; 21 | 22 | var $$default = Paragraph; 23 | 24 | exports.make = make; 25 | exports.$$default = $$default; 26 | exports.default = $$default; 27 | exports.__esModule = true; 28 | /* Css Not a pure module */ 29 | -------------------------------------------------------------------------------- /src/juice/Paragraph.re: -------------------------------------------------------------------------------- 1 | [@react.component] 2 | let make = (~children) => 3 |

4 | children 5 |

6 | 7 | let default = make; 8 | -------------------------------------------------------------------------------- /src/juice/SplitLayout.bs.js: -------------------------------------------------------------------------------- 1 | // Generated by BUCKLESCRIPT VERSION 5.0.6, PLEASE EDIT WITH CARE 2 | 'use strict'; 3 | 4 | var Css = require("bs-css/src/Css.js"); 5 | var React = require("react"); 6 | 7 | var wrapper = Css.style(/* :: */[ 8 | Css.width(Css.pct(100)), 9 | /* :: */[ 10 | Css.height(Css.pct(100)), 11 | /* :: */[ 12 | Css.display(Css.grid), 13 | /* :: */[ 14 | Css.gridTemplateColumns(/* :: */[ 15 | Css.fr(1), 16 | /* :: */[ 17 | Css.fr(1), 18 | /* [] */0 19 | ] 20 | ]), 21 | /* :: */[ 22 | Css.gridColumnGap(Css.px(15)), 23 | /* :: */[ 24 | Css.alignItems(Css.center), 25 | /* [] */0 26 | ] 27 | ] 28 | ] 29 | ] 30 | ] 31 | ]); 32 | 33 | var Styles = /* module */[/* wrapper */wrapper]; 34 | 35 | function SplitLayout(Props) { 36 | var children = Props.children; 37 | return React.createElement("div", { 38 | className: wrapper 39 | }, children); 40 | } 41 | 42 | var make = SplitLayout; 43 | 44 | var $$default = SplitLayout; 45 | 46 | exports.Styles = Styles; 47 | exports.make = make; 48 | exports.$$default = $$default; 49 | exports.default = $$default; 50 | exports.__esModule = true; 51 | /* wrapper Not a pure module */ 52 | -------------------------------------------------------------------------------- /src/juice/SplitLayout.re: -------------------------------------------------------------------------------- 1 | module Styles = { 2 | open Css; 3 | 4 | let wrapper = style([ 5 | width(pct(100.)), 6 | height(pct(100.)), 7 | display(grid), 8 | gridTemplateColumns([fr(1.), fr(1.)]), 9 | gridColumnGap(px(15)), 10 | alignItems(center) 11 | ]) 12 | }; 13 | 14 | 15 | [@react.component] 16 | let make = (~children) => { 17 |
18 | children 19 |
20 | } 21 | 22 | let default = make 23 | -------------------------------------------------------------------------------- /src/juice/Title.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import styled, {css, keyframes} from 'styled-components' 3 | 4 | // inspired from https://css-tricks.com/glitch-effect-text-images-svg/ 5 | 6 | // const skewDistortion = `transform: skew(${Math.random() * 20 * (Math.random() > 0.5 ? -1 : 1)}deg)` 7 | const noiseAnimationSteps = 20; 8 | const noiseAnimation = keyframes` 9 | ${ 10 | Array.from({length: noiseAnimationSteps}).map((_, index) => { 11 | const top = (Math.random() * 100); 12 | const bottom= Math.random() * (101 - top); 13 | return ` 14 | ${Math.floor( index * 1/20 * 100 )}% { 15 | clip-path: inset(${top}% 0 ${bottom}% 0); 16 | } 17 | `}).join('') 18 | } 19 | ` 20 | 21 | const glitchColor1 = 'red' 22 | const glitchColor2 = 'yellow' 23 | const backgroundColor = 'white' 24 | const textColor = 'black' 25 | 26 | const Wrapper = styled.div` 27 | background-color: ${backgroundColor}; 28 | padding-left: 30px; 29 | padding-right: 30px; 30 | ` 31 | 32 | const Glitch = styled.h2.attrs(({children}) => ({ 33 | 'data-text': children, 34 | }))` 35 | text-align: center; 36 | position: relative; 37 | color: ${textColor}; 38 | background-color: ${backgroundColor}; 39 | font-style: italic; 40 | font-size: ${props => props.variant === "featured" ? "10rem" : "auto" } 41 | 42 | &::after, &::before { 43 | content: attr(data-text); 44 | position: absolute; 45 | top: 0; 46 | left: 0; 47 | width: 100%; 48 | height: 100%; 49 | } 50 | 51 | &::before { 52 | left: 2px; 53 | text-shadow: -2px 0 ${glitchColor1}; 54 | animation: ${noiseAnimation} 4s infinite linear alternate-reverse; 55 | background-color: ${backgroundColor}; 56 | color: ${textColor}; 57 | } 58 | 59 | &::after { 60 | ${props => (props.glitchText1 ? css`content: "${props => props.glitchText1}";` : null )} 61 | left: -2px; 62 | text-shadow: 2px 0 ${glitchColor2}; 63 | background-color: ${backgroundColor}; 64 | color: ${textColor}; 65 | animation: ${noiseAnimation} 4s infinite linear alternate-reverse; 66 | } 67 | ` 68 | 69 | export const Title = ({ children, ...props }) => { 70 | return ( 71 | 72 | {children} 73 | 74 | ) 75 | } 76 | -------------------------------------------------------------------------------- /src/juice/VideoBackground.bs.js: -------------------------------------------------------------------------------- 1 | // Generated by BUCKLESCRIPT VERSION 5.0.6, PLEASE EDIT WITH CARE 2 | 'use strict'; 3 | 4 | var Css = require("bs-css/src/Css.js"); 5 | var React = require("react"); 6 | 7 | var wrapper = Css.style(/* :: */[ 8 | Css.height(Css.pct(100)), 9 | /* :: */[ 10 | Css.width(Css.pct(100)), 11 | /* [] */0 12 | ] 13 | ]); 14 | 15 | var Styles = /* module */[/* wrapper */wrapper]; 16 | 17 | function VideoBackground(Props) { 18 | var src = Props.src; 19 | return React.createElement("video", { 20 | className: wrapper, 21 | autoPlay: true, 22 | loop: true, 23 | muted: true 24 | }, React.createElement("source", { 25 | src: src, 26 | type: "video/mp4" 27 | })); 28 | } 29 | 30 | var make = VideoBackground; 31 | 32 | var $$default = VideoBackground; 33 | 34 | exports.Styles = Styles; 35 | exports.make = make; 36 | exports.$$default = $$default; 37 | exports.default = $$default; 38 | exports.__esModule = true; 39 | /* wrapper Not a pure module */ 40 | -------------------------------------------------------------------------------- /src/juice/VideoBackground.re: -------------------------------------------------------------------------------- 1 | module Styles = { 2 | open Css; 3 | 4 | let wrapper = style([ 5 | height(pct(100.)), 6 | width(pct(100.)) 7 | ]) 8 | } 9 | 10 | [@react.component] 11 | let make = (~src) => { 12 | 15 | }; 16 | 17 | let default = make 18 | -------------------------------------------------------------------------------- /src/snippets/GraphQLDemo.graphql: -------------------------------------------------------------------------------- 1 | enum UserRoleEnum { ADMIN, OPERATOR } 2 | 3 | type User { 4 | name: String! 5 | role: UserRoleEnum! 6 | } 7 | 8 | type Query { 9 | me: User 10 | } 11 | -------------------------------------------------------------------------------- /src/snippets/GraphQLDemo.re: -------------------------------------------------------------------------------- 1 | module UserQuery = [%graphql {| 2 | query UserQuery { 3 | currentUser { 4 | name 5 | role 6 | } 7 | } 8 | |}]; 9 | 10 | [@react.component] 11 | let make = () => { 12 | let (result, _) = ReasonApolloHooks.useQuery(UserQuery.make()); 13 | 14 | switch(result) { 15 | | Loading =>

{React.string("Loading...")}

16 | | Data(data) => 17 | switch(data##currentUser) { 18 | | Some(user) => 19 | switch(user##role) { 20 | | `ADMIN =>

{React.string("Hello admin")}

21 | | `OPERATOR =>

{React.string("Hello operator")}

22 | } 23 | | None =>

{React.string("Not logged in")}

24 | } 25 | | Error(_) 26 | | NoData(_) =>

{React.string("Something went wrong")}

27 | } 28 | }; 29 | -------------------------------------------------------------------------------- /src/snippets/PatternMatchingDemo.bs.js: -------------------------------------------------------------------------------- 1 | // Generated by BUCKLESCRIPT VERSION 5.0.6, PLEASE EDIT WITH CARE 2 | 'use strict'; 3 | 4 | var React = require("react"); 5 | var Belt_Array = require("bs-platform/lib/js/belt_Array.js"); 6 | 7 | function PatternMatchingDemo(Props) { 8 | var result = Props.result; 9 | var status = Props.status; 10 | if (status) { 11 | return React.createElement("p", undefined, "Unavailable."); 12 | } else if (typeof result === "number") { 13 | return React.createElement("p", undefined, "Loading..."); 14 | } else if (result.tag) { 15 | var list = result[0]; 16 | if (list.length !== 0) { 17 | return React.createElement("ul", undefined, Belt_Array.map(list, (function (item) { 18 | return React.createElement("li", undefined, item); 19 | }))); 20 | } else { 21 | return React.createElement("p", undefined, "List is empty!"); 22 | } 23 | } else { 24 | return React.createElement("p", undefined, "Something went wrong: " + result[0]); 25 | } 26 | } 27 | 28 | var make = PatternMatchingDemo; 29 | 30 | exports.make = make; 31 | /* react Not a pure module */ 32 | -------------------------------------------------------------------------------- /src/snippets/PatternMatchingDemo.re: -------------------------------------------------------------------------------- 1 | type result = | Loading | Error(string) | Data(array(string)); 2 | type status = | Enabled | Disabled; 3 | 4 | [@react.component] 5 | let make = (~result, ~status) => { 6 | switch(status, result) { 7 | | (Enabled, Loading) =>

{React.string("Loading...")}

8 | | (Enabled, Error(error)) =>

{React.string("Something went wrong: " ++ error)}

9 | | (Enabled, Data([||])) =>

{React.string("List is empty!")}

10 | | (Enabled, Data(list)) => 11 |
    {list->Belt.Array.map(item =>
  • {React.string(item)}
  • )->React.array}
12 | | (Disabled, _) =>

{React.string("Unavailable.")}

13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/snippets/PatternMatchingDemo.ts: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | 3 | interface Result { 4 | loading: boolean; 5 | error: string | null; 6 | data: string[] | null; 7 | } 8 | 9 | interface Props { 10 | result: Result; 11 | enabled: boolean; 12 | } 13 | 14 | export const List = ({ result, enabled }: Props) => { 15 | if(enabled) return

Unavailable

16 | else { 17 | if(result.loading) return

Loading

18 | if(result.data.length == []) return

List is empty!

19 | if(result.data) return ( 20 |
    {result.data.map(item =>
  • {item}
  • )}
21 | ) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/snippets/PatternMatchingDemo2.ts: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | 3 | interface Result { 4 | loading: boolean; 5 | error: string | null; 6 | data: string[] | null; 7 | } 8 | 9 | interface Props { 10 | result: Result; 11 | enabled: boolean; 12 | } 13 | 14 | export const List = ({ result, enabled }: Props) => { 15 | if(enabled) return

Unavailable

16 | else { 17 | if(result.loading) return

Loading

18 | if(result.data || result.data.length === 0) return

List is empty!

19 | if(result.data) return ( 20 |
    {result.data.map(item =>
  • {item}
  • )}
21 | ) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/snippets/PatternMatchingDemo3.ts: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | 3 | interface Result { 4 | loading: boolean; 5 | error: string | null; 6 | data: string[] | null; 7 | } 8 | 9 | interface Props { 10 | result: Result; 11 | enabled: boolean; 12 | } 13 | 14 | export const List = ({ result, enabled }: Props) => { 15 | if(!enabled) return

Unavailable

16 | else { 17 | if(result.error) return

{error}

18 | if(result.loading) return

Loading...

19 | if(result.data || result.data.length === 0) return

List is empty!

20 | if(result.data) return ( 21 |
    {result.data.map(item =>
  • {item}
  • )}
22 | ) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/snippets/PatternMatchingDemoError.bs.js: -------------------------------------------------------------------------------- 1 | // Generated by BUCKLESCRIPT VERSION 5.0.6, PLEASE EDIT WITH CARE 2 | 'use strict'; 3 | 4 | var React = require("react"); 5 | var Belt_Array = require("bs-platform/lib/js/belt_Array.js"); 6 | var Caml_builtin_exceptions = require("bs-platform/lib/js/caml_builtin_exceptions.js"); 7 | 8 | function PatternMatchingDemoError(Props) { 9 | var result = Props.result; 10 | var status = Props.status; 11 | if (status) { 12 | return React.createElement("p", undefined, "Unavailable."); 13 | } else if (typeof result === "number") { 14 | return React.createElement("p", undefined, "Loading..."); 15 | } else if (result.tag) { 16 | var list = result[0]; 17 | if (list.length !== 0) { 18 | return React.createElement("ul", undefined, Belt_Array.map(list, (function (item) { 19 | return React.createElement("li", undefined, item); 20 | }))); 21 | } else { 22 | return React.createElement("p", undefined, "List is empty!"); 23 | } 24 | } else { 25 | throw [ 26 | Caml_builtin_exceptions.match_failure, 27 | /* tuple */[ 28 | "_none_", 29 | 1, 30 | -1 31 | ] 32 | ]; 33 | } 34 | } 35 | 36 | var make = PatternMatchingDemoError; 37 | 38 | exports.make = make; 39 | /* react Not a pure module */ 40 | -------------------------------------------------------------------------------- /src/snippets/PatternMatchingDemoError.re: -------------------------------------------------------------------------------- 1 | type result = | Loading | Error(string) | Data(array(string)); 2 | type status = | Enabled | Disabled; 3 | 4 | [@react.component] 5 | let make = (~result, ~status) => { 6 | /* You forgot to handle a possible case here, for example: (Enabled, Error _) */ 7 | switch(status, result) { 8 | | (Enabled, Loading) =>

{React.string("Loading...")}

9 | | (Enabled, Data([||])) =>

{React.string("List is empty!")}

10 | | (Enabled, Data(list)) => 11 |
    {list->Belt.Array.map(item =>
  • {React.string(item)}
  • )->React.array}
12 | | (Disabled, _) =>

{React.string("Unavailable.")}

13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/snippets/VariantDemo.bs.js: -------------------------------------------------------------------------------- 1 | // Generated by BUCKLESCRIPT VERSION 5.0.6, PLEASE EDIT WITH CARE 2 | 'use strict'; 3 | 4 | 5 | function greeting(person) { 6 | if (typeof person === "number") { 7 | if (person !== 0) { 8 | return "Hello Director."; 9 | } else { 10 | return "Hey Professor!"; 11 | } 12 | } else { 13 | var anyOtherName = person[0]; 14 | if (anyOtherName === "Richard") { 15 | return "Still here Ricky?"; 16 | } else { 17 | return "Hey, " + (anyOtherName + "."); 18 | } 19 | } 20 | } 21 | 22 | exports.greeting = greeting; 23 | /* No side effect */ 24 | -------------------------------------------------------------------------------- /src/snippets/VariantDemo.re: -------------------------------------------------------------------------------- 1 | type schoolPerson = Teacher | Director | Student(string); 2 | 3 | let greeting = person => 4 | switch (person) { 5 | | Teacher => "Hey Professor!" 6 | | Director => "Hello Director." 7 | | Student("Richard") => "Still here Ricky?" 8 | | Student(anyOtherName) => "Hey, " ++ anyOtherName ++ "." 9 | }; 10 | -------------------------------------------------------------------------------- /src/snippets/VariantDemoSwitch.ts: -------------------------------------------------------------------------------- 1 | let greeting = (person: Person) => { 2 | switch (person.kind) { 3 | case SchoolPersonEnum.Teacher: 4 | return "Hey Professor!" 5 | case SchoolPersonEnum.Director: 6 | return "Hello Director." 7 | case SchoolPersonEnum.Student: 8 | if(person.name === "Richard") return "Still here Ricky?" 9 | else return `Hey, ${person.name}.` 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/snippets/VariantDemoTypes.ts: -------------------------------------------------------------------------------- 1 | enum SchoolPersonEnum { 2 | Teacher, 3 | Director, 4 | Student 5 | } 6 | 7 | interface Person { 8 | kind: SchoolPersonEnum 9 | name?: string; 10 | } 11 | --------------------------------------------------------------------------------