-
Notifications
You must be signed in to change notification settings - Fork 5
/
boiler_plate.elm
318 lines (254 loc) · 9.4 KB
/
boiler_plate.elm
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
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
module Main exposing (main)
import BodyBuilder exposing (..)
import BodyBuilder.Attributes as Attributes exposing (..)
import BodyBuilder.Events as Events
import BodyBuilder.Router as Router
exposing
( History
, Page
, StandardHistoryMsg(..)
, Transition
, handleStandardHistory
, historyView
, initHistoryAndData
, maybeTransitionSubscription
, pageWithDefaultTransition
, push
)
import BodyBuilder.Style as Style
import Browser
import Browser.Navigation as Nav
import Color
import Elegant exposing (SizeUnit, percent, pt, px, vh)
import Elegant.Border as Border
import Elegant.Box as Box
import Elegant.Constants as Constants
import Elegant.Corner as Corner
import Elegant.Cursor as Cursor
import Elegant.Dimensions as Dimensions
import Elegant.Display as Display
import Elegant.Outline as Outline
import Elegant.Padding as Padding
import Elegant.Typography as Typography
import Modifiers exposing (..)
import Time
import Url
find_by : (a -> b) -> b -> List a -> Maybe a
find_by insideDataFun data =
List.filter (\e -> insideDataFun e == data)
>> List.head
type Route
= BlogpostsIndex
| BlogpostsShow Int
type alias Data =
{ blogposts : List Blogpost
, key : Nav.Key
, url : Url.Url
}
type alias MyHistory =
History Route Msg
type alias Model =
{ history : MyHistory
, data : Data
}
type HistoryMsg
= BlogpostShow Int
type Msg
= HistoryMsgWrapper HistoryMsg
| StandardHistoryWrapper StandardHistoryMsg
| UrlChanged Url.Url
| LinkClicked Browser.UrlRequest
type alias MarkdownString =
String
type alias Blogpost =
{ id : Int
, title : String
, content : MarkdownString
, publishedAt : Maybe Time.Posix
, image : String
}
handleHistory : HistoryMsg -> MyHistory -> MyHistory
handleHistory route history =
case route of
BlogpostShow id ->
history |> push (Router.pageWithDefaultTransition (BlogpostsShow id))
gray : Color.Color
gray =
Color.grayscale 0.9
titleView : Blogpost -> NodeWithStyle Msg
titleView blogpost =
button
[ Events.onClick <| HistoryMsgWrapper <| BlogpostShow blogpost.id
, standardCellStyle
]
[ text blogpost.title ]
showView : { b | maybeBlogpost : Maybe Blogpost } -> NodeWithStyle Msg
showView data =
case data.maybeBlogpost of
Nothing ->
node [] [ text "Error" ]
Just blogPost ->
Router.pageWithHeader
(Router.headerElement
{ left = Router.headerButton (StandardHistoryWrapper Router.Back) "← BACK"
, center = Router.headerButton (StandardHistoryWrapper Router.Back) "Blog"
, right = node [] []
}
)
(blogpostView blogPost)
blogpostView : Blogpost -> NodeWithStyle msg
blogpostView blogpost =
node []
[ img "" blogpost.image [ style [ Style.block [ Display.fullWidth ] ] ]
, node
[ style
[ Style.block []
, Style.box [ Box.padding [ Padding.horizontal Constants.medium ] ]
]
]
(textToHtml blogpost.content)
]
textToHtml : String -> List (NodeWithStyle msg)
textToHtml =
(>>)
(String.split "\n")
(List.foldr (\e accu -> [ text e, br ] ++ accu) [])
standardCellStyle : Modifiers.Modifier (Attributes.BoxContainer (Attributes.MaybeBlockContainer a))
standardCellStyle =
style
[ Style.block
[ Display.alignment Display.left
, Display.fullWidth
]
, Style.box
[ Box.cursor Cursor.pointer
, Box.border
[ Border.all [ Border.none ]
, Border.bottom [ Border.solid, Elegant.color gray ]
]
, Box.outline [ Outline.none ]
, Box.typography
[ Typography.fontFamilyInherit
, Typography.size Constants.zeta
]
, Box.corner [ Corner.circular Corner.all (px 0) ]
, Box.padding [ Padding.all Constants.large ]
, Box.background [ Elegant.color Color.white ]
]
]
blogpostsIndex : List Blogpost -> NodeWithStyle Msg
blogpostsIndex blogposts =
node
[ style
[ Style.block [ Display.dimensions [ Dimensions.height (vh 100) ] ]
, Style.box [ Box.background [ Elegant.color gray ] ]
]
]
(blogposts |> List.map titleView)
blogpostsShow : Int -> List Blogpost -> NodeWithStyle Msg
blogpostsShow id blogposts =
node [] [ showView { maybeBlogpost = blogposts |> find_by .id id } ]
pageView : Data -> Page Route Msg -> Maybe (Transition Route Msg) -> NodeWithStyle Msg
pageView { blogposts } { route } transition =
case route of
BlogpostsIndex ->
blogpostsIndex blogposts
BlogpostsShow id ->
blogpostsShow id blogposts
chooseView : Model -> Document Msg
chooseView model =
case model.data.url.path of
"/admin" ->
adminView model
_ ->
homeView model
homeView : Model -> Document Msg
homeView ({ history, data } as model) =
{ title = "ProjectTest"
, body =
div
[ style
[ Style.box
[ Box.typography
[ Typography.fontFamilySansSerif
, Typography.size Constants.zeta
]
]
]
]
[ historyView (pageView data) history ]
}
adminView : Model -> Document Msg
adminView ({ history, data } as model) =
{ title = "Admin ProjectTest"
, body =
div
[ style
[ Style.box
[ Box.typography
[ Typography.fontFamilySansSerif
, Typography.size Constants.zeta
]
]
]
]
[ text "ADMIN is going to be here :)" ]
}
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
let
data =
model.data
in
case msg of
HistoryMsgWrapper historyMsg ->
( { model | history = handleHistory historyMsg model.history }, Cmd.none )
StandardHistoryWrapper historyMsg ->
model |> handleStandardHistory historyMsg
LinkClicked urlRequest ->
case urlRequest of
Browser.Internal url ->
( model, Nav.pushUrl data.key (Url.toString url) )
Browser.External href ->
( model, Nav.load href )
UrlChanged url ->
( { model | data = { data | url = url } }
, Cmd.none
)
subscriptions : Model -> Sub Msg
subscriptions model =
maybeTransitionSubscription model.history
initBlogposts : List Blogpost
initBlogposts =
[ { id = 1
, title = "La cigale et la fourmi"
, publishedAt = Just <| Time.millisToPosix 1502323200
, content = "La Cigale, ayant chanté\nTout l'Été,\nSe trouva fort dépourvue\nQuand la bise fut venue.\nPas un seul petit morceau\nDe mouche ou de vermisseau.\nElle alla crier famine\nChez la Fourmi sa voisine,\nLa priant de lui prêter\nQuelque grain pour subsister\nJusqu'à la saison nouvelle.\nJe vous paierai, lui dit-elle,\nAvant l'Oût, foi d'animal,\nIntérêt et principal.\nLa Fourmi n'est pas prêteuse ;\nC'est là son moindre défaut.\n« Que faisiez-vous au temps chaud ?\nDit-elle à cette emprunteuse.\n— Nuit et jour à tout venant\nJe chantais, ne vous déplaise.\n— Vous chantiez ? j'en suis fort aise.\nEh bien !dansez maintenant. »\n"
, image = "https://upload.wikimedia.org/wikipedia/commons/thumb/c/c1/Snodgrass_Magicicada_septendecim.jpg/1024px-Snodgrass_Magicicada_septendecim.jpg"
}
, { id = 2
, title = "Le corbeau et le renard"
, content = "Maître Corbeau, sur un arbre perché,\nTenait en son bec un fromage.\nMaître Renard, par l'odeur alléché,\nLui tint à peu près ce langage :\nEt bonjour, Monsieur du Corbeau.\nQue vous êtes joli ! que vous me semblez beau !\nSans mentir, si votre ramage\nSe rapporte à votre plumage,\nVous êtes le Phénix des hôtes de ces bois.\nÀ ces mots, le Corbeau ne se sent pas de joie ;\nEt pour montrer sa belle voix,\nIl ouvre un large bec, laisse tomber sa proie.\nLe Renard s'en saisit, et dit : Mon bon Monsieur,\nApprenez que tout flatteur\nVit aux dépens de celui qui l'écoute.\nCette leçon vaut bien un fromage, sans doute.\nLe Corbeau honteux et confus\nJura, mais un peu tard, qu'on ne l'y prendrait plus."
, publishedAt = Just <| Time.millisToPosix 1502323200
, image = "https://upload.wikimedia.org/wikipedia/commons/4/47/Karga_9107.svg"
}
]
initData : () -> Url.Url -> Nav.Key -> Data
initData flags url key =
{ blogposts = initBlogposts
, key = key
, url = url
}
init : () -> Url.Url -> Nav.Key -> { data : Data, history : MyHistory }
init flags url key =
initHistoryAndData BlogpostsIndex (initData flags url key) StandardHistoryWrapper
main : Program () Model Msg
main =
application
{ init = \flags -> \url -> \key -> ( init flags url key, Cmd.none )
, onUrlChange = UrlChanged
, onUrlRequest = LinkClicked
, update = update
, subscriptions = subscriptions
, view = chooseView
}