1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
module Gargantext.Components.Themes where
import Gargantext.Prelude
import DOM.Simple (document)
import Data.Array as A
import Data.Eq.Generic (genericEq)
import Data.Generic.Rep (class Generic)
import Data.Maybe (Maybe(..))
import Data.Nullable (toMaybe)
import Effect (Effect)
import FFI.Simple ((...), (.=))
import Gargantext.Utils.Reactix as R2
import Reactix as R
import Reactix.DOM.HTML as H
import Toestand as T
-- (?) Unknown runtime DOM errors lead to a FFI workaround for setting the
-- property of the element (see `markThemeToDOMTree` method)
--
-- Both use cases throw the error:
--
-- ```
-- TypeError: FFI_Simple_Functions.applyMethod'(...)(...)(...) is not a function
-- ```
--
-- ```purescript
-- _ <- el ... "setAttribute" $ [ "data-theme", name ]
-- _ <- pure $ (el .= "data-theme") name
-- ```
foreign import setAttribute :: R.Element -> String -> String -> Effect Unit
here :: R2.Here
here = R2.here "Gargantext.Components.Themes"
stylesheetElId :: String
stylesheetElId = "bootstrap-css"
newtype Theme = Theme { location :: String
, name :: String }
derive instance Generic Theme _
instance Eq Theme where
eq = genericEq
themeName :: Theme -> String
themeName (Theme { name }) = name
defaultTheme :: Theme
defaultTheme = Theme { name: "default"
, location: "styles/bootstrap-default.css" }
greysonTheme :: Theme
greysonTheme = Theme { name: "greyson"
, location: "styles/bootstrap-greyson.css" }
monotonyTheme :: Theme
monotonyTheme = Theme { name: "monotony"
, location: "styles/bootstrap-monotony.css" }
herbieTheme :: Theme
herbieTheme = Theme { name: "herbie"
, location: "styles/bootstrap-herbie.css" }
darksterTheme :: Theme
darksterTheme = Theme { name: "darkster"
, location: "styles/bootstrap-darkster.css" }
allThemes :: Array Theme
allThemes = [ defaultTheme, greysonTheme, monotonyTheme, herbieTheme, darksterTheme]
switchTheme :: Theme -> Effect Unit
switchTheme (Theme { location }) = do
mEl <- R2.getElementById stylesheetElId
case mEl of
Nothing -> pure unit
Just el -> do
_ <- pure $ (el .= "href") location
pure unit
markThemeToDOMTree :: Theme -> Effect Unit
markThemeToDOMTree (Theme { name }) = do
mEl <- pure $ toMaybe (document ... "getElementById" $ [ "app" ])
case mEl of
Nothing -> pure unit
Just el -> setAttribute el "data-theme" name
type ThemeSwitcherProps = (
theme :: T.Box Theme
, themes :: Array Theme
)
themeSwitcher :: R2.Component ThemeSwitcherProps
themeSwitcher = R.createElement themeSwitcherCpt
themeSwitcherCpt :: R.Component ThemeSwitcherProps
themeSwitcherCpt = here.component "themeSwitcher" cpt
where
cpt { theme, themes } _ = do
currentTheme <- T.useLive T.unequal theme
let option (Theme { name }) = H.option { value: name } [ H.text name ]
let options = map option themes
R.useEffectOnce' $ markThemeToDOMTree currentTheme
pure $ R2.select { className: "form-control"
, defaultValue: themeName currentTheme
, on: { change: onChange theme } } options
where
onChange box e = do
let value = R.unsafeEventValue e
let mTheme = A.head $ A.filter (\(Theme { name }) -> value == name) themes
case mTheme of
Nothing -> pure unit
Just t -> do
switchTheme t
markThemeToDOMTree t
T.write_ t box