Skip to content

Commit e25b255

Browse files
authored
Add ClockReactHooks recipe (#190)
* Add ClockReactHooks recipe Partially addresses #157 * Rename component Time → Clock * Use tau
1 parent 7599b0d commit e25b255

File tree

7 files changed

+146
-0
lines changed

7 files changed

+146
-0
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ Running a web-compatible recipe:
9696
| | :heavy_check_mark: | [CardsReactHooks](recipes/CardsReactHooks) | A React port of the ["Random - Cards" Elm Example](https://elm-lang.org/examples/cards). |
9797
| | :heavy_check_mark: | [CatGifsHalogenHooks](recipes/CatGifsHalogenHooks) | A Halogen port of the ["HTTP - Cat GIFs" Elm Example](https://elm-lang.org/examples/cat-gifs). |
9898
| | :heavy_check_mark: | [CatGifsReactHooks](recipes/CatGifsReactHooks) | A React port of the ["HTTP - Cat GIFs" Elm Example](https://elm-lang.org/examples/cat-gifs). |
99+
| | :heavy_check_mark: | [ClockReactHooks](recipes/ClockReactHooks) | A React port of the ["User Interface - Clock" Elm Example](https://elm-lang.org/examples/clock). |
99100
| | :heavy_check_mark: | [ComponentsHalogenHooks](recipes/ComponentsHalogenHooks) | Demonstrates how to nest one Halogen-Hooks-based component inside another and send/receive queries between the two. |
100101
| | :heavy_check_mark: | [ComponentsInputHalogenHooks](recipes/ComponentsInputHalogenHooks) | Each time a parent re-renders, it will pass a new input value into the child, and the child will update accordingly. |
101102
| | :heavy_check_mark: | [ComponentsMultiTypeHalogenHooks](recipes/ComponentsMultiTypeHalogenHooks) | Demonstrates a component that can communicate with its children that have differing types. |

recipes/ClockReactHooks/.gitignore

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
/bower_components/
2+
/node_modules/
3+
/.pulp-cache/
4+
/output/
5+
/generated-docs/
6+
/.psc-package/
7+
/.psc*
8+
/.purs*
9+
/.psa*
10+
/.spago
11+
/.cache/
12+
/dist/
13+
/web-dist/
14+
/prod-dist/
15+
/prod/

recipes/ClockReactHooks/README.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# ClockReactHooks
2+
3+
A React port of the ["User Interface - Clock" Elm Example](https://elm-lang.org/examples/clock).
4+
5+
## Expected Behavior:
6+
7+
### Browser
8+
9+
The browser will render a clock showing the current local time.
10+
11+
## Dependencies Used:
12+
13+
[react](https://www.npmjs.com/package/react)
14+
[react-dom](https://www.npmjs.com/package/react-dom)

recipes/ClockReactHooks/spago.dhall

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
{ name = "ClockReactHooks"
2+
, dependencies =
3+
[ "console"
4+
, "effect"
5+
, "js-date"
6+
, "js-timers"
7+
, "psci-support"
8+
, "react-basic-hooks"
9+
, "react-basic-dom"
10+
]
11+
, packages = ../../packages.dhall
12+
, sources = [ "recipes/ClockReactHooks/src/**/*.purs" ]
13+
}

recipes/ClockReactHooks/src/Main.purs

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
module ClockReactHooks.Main where
2+
3+
import Prelude
4+
import Data.JSDate (JSDate)
5+
import Data.JSDate as JSDate
6+
import Data.Maybe (Maybe(..))
7+
import Data.Newtype (class Newtype)
8+
import Effect (Effect)
9+
import Effect.Exception (throw)
10+
import Effect.Timer (clearInterval, setInterval)
11+
import Math (cos, sin, tau)
12+
import React.Basic.DOM (render)
13+
import React.Basic.DOM.SVG as SVG
14+
import React.Basic.Hooks (Component, Hook, JSX, UseEffect, UseState, coerceHook, component, useEffectOnce, useState', (/\))
15+
import React.Basic.Hooks as React
16+
import Web.DOM.NonElementParentNode (getElementById)
17+
import Web.HTML (window)
18+
import Web.HTML.HTMLDocument (toNonElementParentNode)
19+
import Web.HTML.Window (document)
20+
21+
type Time
22+
= { hours :: Number, minutes :: Number, seconds :: Number }
23+
24+
main :: Effect Unit
25+
main = do
26+
container <- getElementById "root" =<< map toNonElementParentNode (document =<< window)
27+
case container of
28+
Nothing -> throw "Root element not found."
29+
Just c -> do
30+
clock <- mkClock
31+
render (clock {}) c
32+
33+
mkClock :: Component {}
34+
mkClock = do
35+
now <- JSDate.now >>= getTime
36+
component "Clock" \_ -> React.do
37+
{ hours, minutes, seconds } <- useCurrentTime now
38+
pure
39+
$ SVG.svg
40+
{ viewBox: "0 0 400 400"
41+
, width: "400"
42+
, height: "400"
43+
, children:
44+
[ SVG.circle { cx: "200", cy: "200", r: "120", fill: "#1293D8" }
45+
, hand 6 60.0 (hours / 12.0)
46+
, hand 6 90.0 (minutes / 60.0)
47+
, hand 3 90.0 (seconds / 60.0)
48+
]
49+
}
50+
51+
hand :: Int -> Number -> Number -> JSX
52+
hand width length turns =
53+
let
54+
t = tau * (turns - 0.25)
55+
56+
x = 200.0 + length * cos t
57+
58+
y = 200.0 + length * sin t
59+
in
60+
SVG.line
61+
{ x1: "200"
62+
, y1: "200"
63+
, x2: show x
64+
, y2: show y
65+
, stroke: "white"
66+
, strokeWidth: show width
67+
, strokeLinecap: "round"
68+
}
69+
70+
newtype UseCurrentTime hooks
71+
= UseCurrentTime (UseEffect Unit (UseState Time hooks))
72+
73+
derive instance ntUseCurrentTime :: Newtype (UseCurrentTime hooks) _
74+
75+
useCurrentTime :: Time -> Hook UseCurrentTime Time
76+
useCurrentTime initialTime =
77+
coerceHook React.do
78+
currentTime /\ setCurrentTime <- useState' initialTime
79+
useEffectOnce do
80+
intervalId <- setInterval 1000 (JSDate.now >>= getTime >>= setCurrentTime)
81+
pure (clearInterval intervalId)
82+
pure currentTime
83+
84+
getTime :: JSDate -> Effect Time
85+
getTime date = ado
86+
hours <- JSDate.getHours date
87+
minutes <- JSDate.getMinutes date
88+
seconds <- JSDate.getSeconds date
89+
in { hours, minutes, seconds }
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<meta charset="UTF-8" />
5+
<title>ClockReactHooks</title>
6+
</head>
7+
8+
<body>
9+
<div id="root"></div>
10+
<script src="./index.js"></script>
11+
</body>
12+
</html>

recipes/ClockReactHooks/web/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
"use strict";
2+
require("../../../output/ClockReactHooks.Main/index.js").main();

0 commit comments

Comments
 (0)