elm-pages 3.0.0-beta.1 → 3.0.0-beta.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/codegen/elm-pages-codegen.js +17 -8
- package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/Pages-Review-DeadCodeEliminateData.elmi +0 -0
- package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/Pages-Review-DeadCodeEliminateData.elmo +0 -0
- package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/Pages-Review-DeadCodeEliminateDataTest.elmo +0 -0
- package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/d.dat +0 -0
- package/generator/dead-code-review/elm-stuff/tests-0.19.1/js/Runner.elm.js +285 -101
- package/generator/dead-code-review/elm-stuff/tests-0.19.1/js/node_runner.js +1 -1
- package/generator/dead-code-review/elm-stuff/tests-0.19.1/js/node_supervisor.js +1 -1
- package/generator/dead-code-review/src/Pages/Review/DeadCodeEliminateData.elm +140 -17
- package/generator/dead-code-review/tests/Pages/Review/DeadCodeEliminateDataTest.elm +218 -0
- package/generator/review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/d.dat +0 -0
- package/generator/review/elm-stuff/tests-0.19.1/js/node_runner.js +1 -1
- package/generator/review/elm-stuff/tests-0.19.1/js/node_supervisor.js +1 -1
- package/generator/src/SharedTemplate.elm +1 -1
- package/generator/src/generate-template-module-connector.js +0 -28
- package/package.json +1 -2
- package/src/DataSource/File.elm +1 -1
- package/src/DataSource/Internal/Request.elm +0 -5
- package/src/Form/Field.elm +1 -1
- package/src/Form.elm +1 -1
- package/src/Head/Seo.elm +16 -27
- package/src/Pages/Internal/NotFoundReason.elm +3 -2
- package/src/Pages/Internal/Platform/Cli.elm +41 -21
- package/src/Pages/Internal/Platform.elm +3 -3
- package/src/Pages/ProgramConfig.elm +1 -1
- package/src/Server/Session.elm +149 -83
- package/src/Server/SetCookie.elm +89 -31
package/src/Form.elm
CHANGED
|
@@ -575,7 +575,7 @@ field name (Field fieldParser kind) (Form definitions parseFn toInitialValues) =
|
|
|
575
575
|
|
|
576
576
|
{-| Declare a hidden field for the form.
|
|
577
577
|
|
|
578
|
-
Unlike [`field`](#field) declarations which are rendered using [`Form.
|
|
578
|
+
Unlike [`field`](#field) declarations which are rendered using [`Form.FieldView`](Form-FieldView)
|
|
579
579
|
functions, `hiddenField` inputs are automatically inserted into the form when you render it.
|
|
580
580
|
|
|
581
581
|
You define the field's validations the same way as for `field`, with the
|
package/src/Head/Seo.elm
CHANGED
|
@@ -49,10 +49,12 @@ with the `head` function that you pass to your Pages config (`Pages.application`
|
|
|
49
49
|
|
|
50
50
|
-}
|
|
51
51
|
|
|
52
|
+
import DateOrDateTime exposing (DateOrDateTime)
|
|
52
53
|
import Head
|
|
53
54
|
import Head.Twitter as Twitter
|
|
54
55
|
import LanguageTag.Country
|
|
55
56
|
import LanguageTag.Language
|
|
57
|
+
import MimeType exposing (MimeType)
|
|
56
58
|
import Pages.Url
|
|
57
59
|
|
|
58
60
|
|
|
@@ -235,9 +237,9 @@ website common =
|
|
|
235
237
|
article :
|
|
236
238
|
{ tags : List String
|
|
237
239
|
, section : Maybe String
|
|
238
|
-
, publishedTime : Maybe
|
|
239
|
-
, modifiedTime : Maybe
|
|
240
|
-
, expirationTime : Maybe
|
|
240
|
+
, publishedTime : Maybe DateOrDateTime
|
|
241
|
+
, modifiedTime : Maybe DateOrDateTime
|
|
242
|
+
, expirationTime : Maybe DateOrDateTime
|
|
241
243
|
}
|
|
242
244
|
-> Common
|
|
243
245
|
-> List Head.Tag
|
|
@@ -252,7 +254,7 @@ book :
|
|
|
252
254
|
->
|
|
253
255
|
{ tags : List String
|
|
254
256
|
, isbn : Maybe String
|
|
255
|
-
, releaseDate : Maybe
|
|
257
|
+
, releaseDate : Maybe DateOrDateTime
|
|
256
258
|
}
|
|
257
259
|
-> List Head.Tag
|
|
258
260
|
book common details =
|
|
@@ -354,7 +356,7 @@ tagsForAudio : Audio -> List ( String, Maybe Head.AttributeValue )
|
|
|
354
356
|
tagsForAudio audio =
|
|
355
357
|
[ ( "og:audio", audio.url |> Head.raw |> Just )
|
|
356
358
|
, ( "og:audio:secure_url", audio.url |> Head.raw |> Just )
|
|
357
|
-
, ( "og:audio:type", audio.mimeType |> Maybe.map Head.raw )
|
|
359
|
+
, ( "og:audio:type", audio.mimeType |> Maybe.map (MimeType.toString >> Head.raw) )
|
|
358
360
|
]
|
|
359
361
|
|
|
360
362
|
|
|
@@ -371,14 +373,14 @@ type ContentDetails
|
|
|
371
373
|
| Article
|
|
372
374
|
{ tags : List String
|
|
373
375
|
, section : Maybe String
|
|
374
|
-
, publishedTime : Maybe
|
|
375
|
-
, modifiedTime : Maybe
|
|
376
|
-
, expirationTime : Maybe
|
|
376
|
+
, publishedTime : Maybe DateOrDateTime
|
|
377
|
+
, modifiedTime : Maybe DateOrDateTime
|
|
378
|
+
, expirationTime : Maybe DateOrDateTime
|
|
377
379
|
}
|
|
378
380
|
| Book
|
|
379
381
|
{ tags : List String
|
|
380
382
|
, isbn : Maybe String
|
|
381
|
-
, releaseDate : Maybe
|
|
383
|
+
, releaseDate : Maybe DateOrDateTime
|
|
382
384
|
}
|
|
383
385
|
| Song
|
|
384
386
|
{-
|
|
@@ -399,20 +401,6 @@ type ContentDetails
|
|
|
399
401
|
}
|
|
400
402
|
|
|
401
403
|
|
|
402
|
-
{-| <https://en.wikipedia.org/wiki/ISO_8601>
|
|
403
|
-
-}
|
|
404
|
-
type alias Iso8601DateTime =
|
|
405
|
-
-- TODO should be more type-safe here
|
|
406
|
-
String
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
{-| <https://en.wikipedia.org/wiki/Media_type>
|
|
410
|
-
-}
|
|
411
|
-
type alias MimeType =
|
|
412
|
-
-- TODO should be more type-safe here
|
|
413
|
-
String
|
|
414
|
-
|
|
415
|
-
|
|
416
404
|
{-| See <https://ogp.me/#structured>
|
|
417
405
|
-}
|
|
418
406
|
type alias Image =
|
|
@@ -448,6 +436,7 @@ tagsForVideo video =
|
|
|
448
436
|
, ( "og:video:secure_url", video.url |> Head.raw |> Just )
|
|
449
437
|
, ( "og:video:width", video.dimensions |> Maybe.map .width |> Maybe.map String.fromInt |> Maybe.map Head.raw )
|
|
450
438
|
, ( "og:video:height", video.dimensions |> Maybe.map .height |> Maybe.map String.fromInt |> Maybe.map Head.raw )
|
|
439
|
+
, ( "og:video:type", video.mimeType |> Maybe.map (MimeType.toString >> Head.raw) )
|
|
451
440
|
]
|
|
452
441
|
|
|
453
442
|
|
|
@@ -466,9 +455,9 @@ tags (Content common details) =
|
|
|
466
455
|
-}
|
|
467
456
|
[ ( "og:type", "article" |> Head.raw |> Just )
|
|
468
457
|
, ( "article:section", articleDetails.section |> Maybe.map Head.raw )
|
|
469
|
-
, ( "article:published_time", articleDetails.publishedTime |> Maybe.map Head.raw )
|
|
470
|
-
, ( "article:modified_time", articleDetails.modifiedTime |> Maybe.map Head.raw )
|
|
471
|
-
, ( "article:expiration_time", articleDetails.expirationTime |> Maybe.map Head.raw )
|
|
458
|
+
, ( "article:published_time", articleDetails.publishedTime |> Maybe.map (DateOrDateTime.toIso8601 >> Head.raw) )
|
|
459
|
+
, ( "article:modified_time", articleDetails.modifiedTime |> Maybe.map (DateOrDateTime.toIso8601 >> Head.raw) )
|
|
460
|
+
, ( "article:expiration_time", articleDetails.expirationTime |> Maybe.map (DateOrDateTime.toIso8601 >> Head.raw) )
|
|
472
461
|
]
|
|
473
462
|
++ List.map
|
|
474
463
|
(\tag -> ( "article:tag", tag |> Head.raw |> Just ))
|
|
@@ -477,7 +466,7 @@ tags (Content common details) =
|
|
|
477
466
|
Book bookDetails ->
|
|
478
467
|
[ ( "og:type", "book" |> Head.raw |> Just )
|
|
479
468
|
, ( "og:isbn", bookDetails.isbn |> Maybe.map Head.raw )
|
|
480
|
-
, ( "og:release_date", bookDetails.releaseDate |> Maybe.map Head.raw )
|
|
469
|
+
, ( "og:release_date", bookDetails.releaseDate |> Maybe.map (DateOrDateTime.toIso8601 >> Head.raw) )
|
|
481
470
|
]
|
|
482
471
|
++ List.map
|
|
483
472
|
(\tag -> ( "book:tag", tag |> Head.raw |> Just ))
|
|
@@ -44,11 +44,11 @@ type NotFoundReason
|
|
|
44
44
|
document :
|
|
45
45
|
List RoutePattern
|
|
46
46
|
-> Payload
|
|
47
|
-
-> { title : String, body : Html msg }
|
|
47
|
+
-> { title : String, body : List (Html msg) }
|
|
48
48
|
document pathPatterns payload =
|
|
49
49
|
{ title = "Page not found"
|
|
50
50
|
, body =
|
|
51
|
-
Html.div
|
|
51
|
+
[ Html.div
|
|
52
52
|
[ Attr.id "not-found-reason"
|
|
53
53
|
, Attr.style "padding" "30px"
|
|
54
54
|
]
|
|
@@ -110,6 +110,7 @@ document pathPatterns payload =
|
|
|
110
110
|
, Html.text <| "TODO"
|
|
111
111
|
]
|
|
112
112
|
)
|
|
113
|
+
]
|
|
113
114
|
}
|
|
114
115
|
|
|
115
116
|
|
|
@@ -829,13 +829,13 @@ sendSinglePageProgress site contentJson config model info =
|
|
|
829
829
|
)
|
|
830
830
|
|> Tuple.first
|
|
831
831
|
|
|
832
|
-
viewValue : { title : String, body : Html (Pages.Msg.Msg userMsg) }
|
|
832
|
+
viewValue : { title : String, body : List (Html (Pages.Msg.Msg userMsg)) }
|
|
833
833
|
viewValue =
|
|
834
834
|
(config.view Dict.empty Dict.empty Nothing currentPage Nothing sharedData pageData maybeActionData |> .view) pageModel
|
|
835
835
|
in
|
|
836
836
|
PageServerResponse.RenderPage responseInfo
|
|
837
837
|
{ head = config.view Dict.empty Dict.empty Nothing currentPage Nothing sharedData pageData maybeActionData |> .head
|
|
838
|
-
, view = viewValue.body |>
|
|
838
|
+
, view = viewValue.body |> bodyToString
|
|
839
839
|
, title = viewValue.title
|
|
840
840
|
}
|
|
841
841
|
|
|
@@ -871,7 +871,7 @@ sendSinglePageProgress site contentJson config model info =
|
|
|
871
871
|
pageData =
|
|
872
872
|
config.errorPageToData error
|
|
873
873
|
|
|
874
|
-
viewValue : { title : String, body : Html (Pages.Msg.Msg userMsg) }
|
|
874
|
+
viewValue : { title : String, body : List (Html (Pages.Msg.Msg userMsg)) }
|
|
875
875
|
viewValue =
|
|
876
876
|
(config.view Dict.empty Dict.empty Nothing currentPage Nothing sharedData pageData Nothing |> .view) pageModel
|
|
877
877
|
in
|
|
@@ -880,7 +880,7 @@ sendSinglePageProgress site contentJson config model info =
|
|
|
880
880
|
, headers = record.headers
|
|
881
881
|
}
|
|
882
882
|
{ head = config.view Dict.empty Dict.empty Nothing currentPage Nothing sharedData pageData Nothing |> .head
|
|
883
|
-
, view = viewValue.body |> HtmlPrinter.htmlToString
|
|
883
|
+
, view = viewValue.body |> List.map HtmlPrinter.htmlToString |> String.join "\n"
|
|
884
884
|
, title = viewValue.title
|
|
885
885
|
}
|
|
886
886
|
)
|
|
@@ -957,42 +957,49 @@ sendSinglePageProgress site contentJson config model info =
|
|
|
957
957
|
case maybeNotFoundReason of
|
|
958
958
|
Nothing ->
|
|
959
959
|
let
|
|
960
|
-
byteEncodedPageData
|
|
961
|
-
byteEncodedPageData =
|
|
960
|
+
( actionHeaders, byteEncodedPageData ) =
|
|
962
961
|
case pageDataResult of
|
|
963
962
|
Ok pageServerResponse ->
|
|
964
963
|
case pageServerResponse of
|
|
965
|
-
PageServerResponse.RenderPage
|
|
964
|
+
PageServerResponse.RenderPage ignored1 pageData ->
|
|
966
965
|
-- TODO want to encode both shared and page data in dev server and HTML-embedded data
|
|
967
966
|
-- but not for writing out the content.dat files - would be good to optimize this redundant data out
|
|
968
967
|
--if model.isDevServer then
|
|
969
968
|
case isAction of
|
|
970
969
|
Just actionRequestKind ->
|
|
971
970
|
case actionDataResult of
|
|
972
|
-
Ok (PageServerResponse.RenderPage
|
|
971
|
+
Ok (PageServerResponse.RenderPage ignored2 actionData) ->
|
|
973
972
|
case actionRequestKind of
|
|
974
973
|
ActionResponseRequest ->
|
|
975
|
-
|
|
974
|
+
( ignored2.headers
|
|
975
|
+
, sharedDataResult
|
|
976
976
|
|> Result.map (\sharedData -> ResponseSketch.HotUpdate pageData sharedData (Just actionData))
|
|
977
977
|
|> Result.withDefault (ResponseSketch.RenderPage pageData (Just actionData))
|
|
978
978
|
|> config.encodeResponse
|
|
979
979
|
|> Bytes.Encode.encode
|
|
980
|
+
)
|
|
980
981
|
|
|
981
982
|
ActionOnlyRequest ->
|
|
982
983
|
---- TODO need to encode action data when only that is requested (not ResponseSketch?)
|
|
983
|
-
|
|
984
|
+
( ignored2.headers
|
|
985
|
+
, actionData
|
|
984
986
|
|> config.encodeAction
|
|
985
987
|
|> Bytes.Encode.encode
|
|
988
|
+
)
|
|
986
989
|
|
|
987
990
|
_ ->
|
|
988
|
-
|
|
991
|
+
( ignored1.headers
|
|
992
|
+
, Bytes.Encode.encode (Bytes.Encode.unsignedInt8 0)
|
|
993
|
+
)
|
|
989
994
|
|
|
990
995
|
Nothing ->
|
|
991
|
-
|
|
996
|
+
( ignored1.headers
|
|
997
|
+
, sharedDataResult
|
|
992
998
|
|> Result.map (\something -> ResponseSketch.HotUpdate pageData something Nothing)
|
|
993
999
|
|> Result.withDefault (ResponseSketch.RenderPage pageData Nothing)
|
|
994
1000
|
|> config.encodeResponse
|
|
995
1001
|
|> Bytes.Encode.encode
|
|
1002
|
+
)
|
|
996
1003
|
|
|
997
1004
|
--else
|
|
998
1005
|
-- pageData
|
|
@@ -1001,7 +1008,8 @@ sendSinglePageProgress site contentJson config model info =
|
|
|
1001
1008
|
-- |> Bytes.Encode.encode
|
|
1002
1009
|
PageServerResponse.ServerResponse serverResponse ->
|
|
1003
1010
|
-- TODO handle error?
|
|
1004
|
-
|
|
1011
|
+
( serverResponse.headers
|
|
1012
|
+
, PageServerResponse.toRedirect serverResponse
|
|
1005
1013
|
|> Maybe.map
|
|
1006
1014
|
(\{ location } ->
|
|
1007
1015
|
location
|
|
@@ -1011,10 +1019,12 @@ sendSinglePageProgress site contentJson config model info =
|
|
|
1011
1019
|
-- TODO handle other cases besides redirects?
|
|
1012
1020
|
|> Maybe.withDefault (Bytes.Encode.unsignedInt8 0)
|
|
1013
1021
|
|> Bytes.Encode.encode
|
|
1022
|
+
)
|
|
1014
1023
|
|
|
1015
|
-
PageServerResponse.ErrorPage error
|
|
1024
|
+
PageServerResponse.ErrorPage error { headers } ->
|
|
1016
1025
|
-- TODO this case should never happen
|
|
1017
|
-
|
|
1026
|
+
( headers
|
|
1027
|
+
, sharedDataResult
|
|
1018
1028
|
|> Result.map
|
|
1019
1029
|
(\sharedData ->
|
|
1020
1030
|
ResponseSketch.HotUpdate (config.errorPageToData error)
|
|
@@ -1024,10 +1034,13 @@ sendSinglePageProgress site contentJson config model info =
|
|
|
1024
1034
|
|> Result.map config.encodeResponse
|
|
1025
1035
|
|> Result.map Bytes.Encode.encode
|
|
1026
1036
|
|> Result.withDefault (Bytes.Encode.encode (Bytes.Encode.unsignedInt8 0))
|
|
1037
|
+
)
|
|
1027
1038
|
|
|
1028
1039
|
_ ->
|
|
1029
1040
|
-- TODO handle error?
|
|
1030
|
-
|
|
1041
|
+
( []
|
|
1042
|
+
, Bytes.Encode.encode (Bytes.Encode.unsignedInt8 0)
|
|
1043
|
+
)
|
|
1031
1044
|
in
|
|
1032
1045
|
case renderedOrApiResponse of
|
|
1033
1046
|
PageServerResponse.RenderPage responseInfo rendered ->
|
|
@@ -1040,7 +1053,9 @@ sendSinglePageProgress site contentJson config model info =
|
|
|
1040
1053
|
, staticHttpCache = Dict.empty
|
|
1041
1054
|
, is404 = False
|
|
1042
1055
|
, statusCode = responseInfo.statusCode
|
|
1043
|
-
, headers =
|
|
1056
|
+
, headers =
|
|
1057
|
+
-- TODO should `responseInfo.headers` be used? Is there a problem in the case where there is both an action and data response in one? Do we need to make sure it is performed as two separate HTTP requests to ensure that the cookies are set correctly in that case?
|
|
1058
|
+
actionHeaders
|
|
1044
1059
|
}
|
|
1045
1060
|
|> ToJsPayload.PageProgress
|
|
1046
1061
|
|> Effect.SendSinglePageNew byteEncodedPageData
|
|
@@ -1143,7 +1158,7 @@ render404Page config sharedData model path notFoundReason =
|
|
|
1143
1158
|
pathAndRoute =
|
|
1144
1159
|
{ path = path, route = config.notFoundRoute }
|
|
1145
1160
|
|
|
1146
|
-
viewValue : { title : String, body : Html (Pages.Msg.Msg userMsg) }
|
|
1161
|
+
viewValue : { title : String, body : List (Html (Pages.Msg.Msg userMsg)) }
|
|
1147
1162
|
viewValue =
|
|
1148
1163
|
(config.view Dict.empty
|
|
1149
1164
|
Dict.empty
|
|
@@ -1159,7 +1174,7 @@ render404Page config sharedData model path notFoundReason =
|
|
|
1159
1174
|
in
|
|
1160
1175
|
{ route = Path.toAbsolute path
|
|
1161
1176
|
, contentJson = Dict.empty
|
|
1162
|
-
, html = viewValue.body |>
|
|
1177
|
+
, html = viewValue.body |> bodyToString
|
|
1163
1178
|
, errors = []
|
|
1164
1179
|
, head = config.view Dict.empty Dict.empty Nothing pathAndRoute Nothing justSharedData pageData Nothing |> .head
|
|
1165
1180
|
, title = viewValue.title
|
|
@@ -1179,7 +1194,7 @@ render404Page config sharedData model path notFoundReason =
|
|
|
1179
1194
|
|> config.encodeResponse
|
|
1180
1195
|
|> Bytes.Encode.encode
|
|
1181
1196
|
|
|
1182
|
-
notFoundDocument : { title : String, body : Html msg }
|
|
1197
|
+
notFoundDocument : { title : String, body : List (Html msg) }
|
|
1183
1198
|
notFoundDocument =
|
|
1184
1199
|
{ path = path
|
|
1185
1200
|
, reason = notFoundReason
|
|
@@ -1188,7 +1203,7 @@ render404Page config sharedData model path notFoundReason =
|
|
|
1188
1203
|
in
|
|
1189
1204
|
{ route = Path.toAbsolute path
|
|
1190
1205
|
, contentJson = Dict.empty
|
|
1191
|
-
, html =
|
|
1206
|
+
, html = bodyToString notFoundDocument.body
|
|
1192
1207
|
, errors = []
|
|
1193
1208
|
, head = []
|
|
1194
1209
|
, title = notFoundDocument.title
|
|
@@ -1204,6 +1219,11 @@ render404Page config sharedData model path notFoundReason =
|
|
|
1204
1219
|
|> Effect.SendSinglePageNew byteEncodedPageData
|
|
1205
1220
|
|
|
1206
1221
|
|
|
1222
|
+
bodyToString : List (Html msg) -> String
|
|
1223
|
+
bodyToString body =
|
|
1224
|
+
body |> List.map HtmlPrinter.htmlToString |> String.join "\n"
|
|
1225
|
+
|
|
1226
|
+
|
|
1207
1227
|
urlToRoute : ProgramConfig userMsg userModel route pageData actionData sharedData effect mappedMsg errorPage -> Url -> route
|
|
1208
1228
|
urlToRoute config url =
|
|
1209
1229
|
if url.path |> String.startsWith "/____elm-pages-internal____" then
|
|
@@ -58,7 +58,7 @@ type alias Program userModel userMsg pageData actionData sharedData errorPage =
|
|
|
58
58
|
mainView :
|
|
59
59
|
ProgramConfig userMsg userModel route pageData actionData sharedData effect (Msg userMsg pageData actionData sharedData errorPage) errorPage
|
|
60
60
|
-> Model userModel pageData actionData sharedData
|
|
61
|
-
-> { title : String, body : Html (Pages.Msg.Msg userMsg) }
|
|
61
|
+
-> { title : String, body : List (Html (Pages.Msg.Msg userMsg)) }
|
|
62
62
|
mainView config model =
|
|
63
63
|
case model.notFound of
|
|
64
64
|
Just info ->
|
|
@@ -95,7 +95,7 @@ mainView config model =
|
|
|
95
95
|
Err error ->
|
|
96
96
|
{ title = "Page Data Error"
|
|
97
97
|
, body =
|
|
98
|
-
Html.div [] [ Html.text error ]
|
|
98
|
+
[ Html.div [] [ Html.text error ] ]
|
|
99
99
|
}
|
|
100
100
|
|
|
101
101
|
|
|
@@ -124,9 +124,9 @@ view config model =
|
|
|
124
124
|
{ title = title
|
|
125
125
|
, body =
|
|
126
126
|
[ onViewChangeElement model.url
|
|
127
|
-
, body |> Html.map UserMsg
|
|
128
127
|
, AriaLiveAnnouncer.view model.ariaNavigationAnnouncement
|
|
129
128
|
]
|
|
129
|
+
++ List.map (Html.map UserMsg) body
|
|
130
130
|
}
|
|
131
131
|
|
|
132
132
|
|
|
@@ -65,7 +65,7 @@ type alias ProgramConfig userMsg userModel route pageData actionData sharedData
|
|
|
65
65
|
-> pageData
|
|
66
66
|
-> Maybe actionData
|
|
67
67
|
->
|
|
68
|
-
{ view : userModel -> { title : String, body : Html (Pages.Msg.Msg userMsg) }
|
|
68
|
+
{ view : userModel -> { title : String, body : List (Html (Pages.Msg.Msg userMsg)) }
|
|
69
69
|
, head : List Head.Tag
|
|
70
70
|
}
|
|
71
71
|
, handleRoute : route -> DataSource (Maybe NotFoundReason)
|