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