git.iko.soy/rowtype-yoga/psfp
on 21e940e help sign in
rowtype-yoga/psfp/src/Button/Component.purs
145 lines 4.4 kB history raw
1module Button.Component where
3import Prelude
5import Data.Foldable (intercalate)
6import Data.Monoid (guard)
7import Effect (Effect)
8import Prim.Row (class Lacks, class Union)
9import React.Basic (JSX)
10import React.Basic.DOM (Props_button, css, unsafeCreateDOMComponent)
11import React.Basic.Hooks (ReactComponent, component, element)
12import React.Basic.Hooks as React
13import Record (union)
14import Theme.Styles (classNames, makeStyles)
15import Theme.Types (CSSTheme)
17data ButtonType
18 = PlainButton
19 | HighlightedButton
20 | DisabledButton
22derive instance eqButtonType ∷ Eq ButtonType
24mkButton ∷
25 ∀ attrs attrs_.
26 Union attrs attrs_ Props_button =>
27 Lacks "children" attrs =>
28 Lacks "className" attrs =>
29 Lacks "ref" attrs =>
30 Lacks "key" attrs =>
31 Effect
32 ( ReactComponent
33 { children ∷ Array JSX
34 , buttonType ∷ ButtonType
35 , buttonProps ∷ Record attrs
36 }
37 )
38mkButton = do
39 useStyles <-
40 makeStyles \(theme ∷ CSSTheme) ->
41 { "@keyframes gradientBG":
42 css
43 { "0%": css { backgroundPosition: "0% 50%" }
44 , "50%": css { backgroundPosition: "100% 50%" }
45 , "100%": css { backgroundPosition: "0% 50%" }
46 }
47 , btn:
48 css
49 { background:
50 if theme.isLight
51 then
52 theme.interfaceColourLightest
53 else
54 linearGradient
55 [ theme.interfaceColourLightest
56 , theme.interfaceColourLighter
57 ]
58 , color: theme.textColour
59 , boxShadow:
60 if theme.isLight
61 then "none"
62 else
63 "1px 1px 10px rgba(0,0,0,0.66)"
64 , border:
65 if theme.isLight
66 then "1px solid " <> theme.interfaceColourLighter
67 else
68 "none"
69 , borderRadius: "20px"
70 , padding: "0px 18px 0px 18px"
71 , marginLeft: "2px"
72 , marginRight: "2px"
73 , minWidth: "100px"
74 , height: "40px"
75 , fontFamily: theme.textFontFamily
76 , letterSpacing: "0.2em"
77 , textTransform: "uppercase"
78 , outline: "none"
79 , "&:focus":
80 css
81 { background:
82 linearGradient
83 [ "-5deg"
84 , theme.interfaceColourDarker
85 , theme.highlightColourDark
86 , theme.highlightColour
87 ]
88 , color: theme.interfaceColourLighter
89 , backgroundSize: "400% 400%, 100% 100%"
90 , animation: "$gradientBG 3s ease infinite"
91 }
92 , "&:active":
93 css
94 { background:
95 linearGradient
96 [ "180deg"
97 , theme.interfaceColourLighter
98 , theme.interfaceColourLightest
99 ]
100 , boxShadow: "inset 0 0 2px black"
101 }
102 , "&:disabled":
103 css
104 { boxShadow: "0 0 0 black"
105 , background: theme.backgroundColour
106 , border: "1px dotted " <> theme.interfaceColourLightest
107 , textDecoration: "line-through"
108 , textDecorationColor: theme.red
109 }
110 }
111 , highlightedButton:
112 css
113 { background:
114 if theme.isLight
115 then
116 theme.highlightColour
117 else
118 linearGradient [ theme.highlightColour, theme.highlightColourDark ]
119 , "&:active":
120 css
121 { background:
122 linearGradient [ theme.highlightColourDark, theme.highlightColour ]
123 }
124 , color: theme.textColour
125 }
126 }
127 component "Button" \{ children, buttonType, buttonProps } -> React.do
128 rawClasses <- useStyles
129 let
130 classes = flip classNames rawClasses
131 -- [TODO]: How do you do this in a typesafe manner?
132 pure <<< (element $ unsafeCreateDOMComponent "button")
133 $ { className:
134 classes
135 [ _.btn
136 , guard (buttonType == HighlightedButton) _.highlightedButton
137 ]
138 , disabled: buttonType == DisabledButton
139 , children
140 }
141 `union`
142 buttonProps
144linearGradient ∷ Array String -> String
145linearGradient elems = "linear-gradient(" <> intercalate "," elems <> ")"