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