Working on event detail. Also small visual help in DayView. Also some favorite stuff.
This commit is contained in:
parent
974694bd5f
commit
a447ca476f
|
@ -7,7 +7,7 @@ import Models exposing (Day, Speaker, Event, EventInstance, EventLocation, Event
|
|||
|
||||
-- Core modules
|
||||
|
||||
import Json.Decode exposing (int, string, float, list, bool, dict, Decoder)
|
||||
import Json.Decode exposing (int, string, float, list, bool, dict, Decoder, nullable)
|
||||
import Json.Decode.Pipeline exposing (decode, required, optional, hardcoded)
|
||||
import Date exposing (Date, Month(..))
|
||||
|
||||
|
@ -55,6 +55,7 @@ eventDecoder =
|
|||
|> required "speakers" (list speakerDecoder)
|
||||
|> required "video_recording" bool
|
||||
|> optional "video_url" string ""
|
||||
|> required "event_type" string
|
||||
|
||||
|
||||
dateDecoder : Decoder Date
|
||||
|
@ -86,6 +87,7 @@ eventInstanceDecoder =
|
|||
|> required "location_icon" string
|
||||
|> required "video_recording" bool
|
||||
|> optional "video_url" string ""
|
||||
|> optional "is_favorited" (nullable bool) Nothing
|
||||
|
||||
|
||||
eventLocationDecoder : Decoder EventLocation
|
||||
|
|
|
@ -75,6 +75,7 @@ type alias EventInstance =
|
|||
, locationIcon : String
|
||||
, videoRecording : Bool
|
||||
, videoUrl : String
|
||||
, isFavorited : Maybe Bool
|
||||
}
|
||||
|
||||
|
||||
|
@ -85,6 +86,7 @@ type alias Event =
|
|||
, speakers : List Speaker
|
||||
, videoRecording : Bool
|
||||
, videoUrl : String
|
||||
, eventType : String
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -52,12 +52,12 @@ dayView day model =
|
|||
div
|
||||
[ classList [ ( "row", True ) ] ]
|
||||
[ gutter minutes
|
||||
, locationColumns filteredEventInstances model.eventLocations model.flags.schedule_midnight_offset_hours
|
||||
, locationColumns filteredEventInstances model.eventLocations model.flags.schedule_midnight_offset_hours minutes
|
||||
]
|
||||
|
||||
|
||||
locationColumns : List EventInstance -> List EventLocation -> Int -> Html Msg
|
||||
locationColumns eventInstances eventLocations offset =
|
||||
locationColumns : List EventInstance -> List EventLocation -> Int -> List Date -> Html Msg
|
||||
locationColumns eventInstances eventLocations offset minutes =
|
||||
let
|
||||
columnWidth =
|
||||
100.0 / toFloat (List.length eventLocations)
|
||||
|
@ -71,11 +71,11 @@ locationColumns eventInstances eventLocations offset =
|
|||
[ ( "col-sm-11", True )
|
||||
]
|
||||
]
|
||||
(List.map (\location -> locationColumn columnWidth eventInstances offset location) eventLocations)
|
||||
(List.map (\location -> locationColumn columnWidth eventInstances offset minutes location) eventLocations)
|
||||
|
||||
|
||||
locationColumn : Float -> List EventInstance -> Int -> EventLocation -> Html Msg
|
||||
locationColumn columnWidth eventInstances offset location =
|
||||
locationColumn : Float -> List EventInstance -> Int -> List Date -> EventLocation -> Html Msg
|
||||
locationColumn columnWidth eventInstances offset minutes location =
|
||||
let
|
||||
locationInstances =
|
||||
List.filter (\instance -> instance.location == location.slug) eventInstances
|
||||
|
@ -102,6 +102,23 @@ locationColumn columnWidth eventInstances offset location =
|
|||
]
|
||||
[ text location.name ]
|
||||
]
|
||||
++ (List.map
|
||||
(\x ->
|
||||
div
|
||||
[ style
|
||||
[ ( "backgroundColor"
|
||||
, if Date.minute x == 30 || Date.minute x == 45 then
|
||||
"#f8f8f8"
|
||||
else
|
||||
"#fff"
|
||||
)
|
||||
, ( "height", px blockHeight )
|
||||
]
|
||||
]
|
||||
[]
|
||||
)
|
||||
minutes
|
||||
)
|
||||
++ (List.map (\group -> renderGroup offset group) overlappingGroups)
|
||||
)
|
||||
|
||||
|
|
|
@ -6,9 +6,14 @@ import Messages exposing (Msg(..))
|
|||
import Models exposing (..)
|
||||
|
||||
|
||||
-- Core modules
|
||||
|
||||
import Date
|
||||
|
||||
|
||||
-- External modules
|
||||
|
||||
import Html exposing (Html, text, div, ul, li, span, i, h4, a, p, hr)
|
||||
import Html exposing (Html, text, div, ul, li, span, i, h3, h4, a, p, hr, strong)
|
||||
import Html.Attributes exposing (class, classList, href)
|
||||
import Html.Events exposing (onClick)
|
||||
import Markdown
|
||||
|
@ -22,58 +27,84 @@ eventDetailView eventSlug model =
|
|||
model.events
|
||||
|> List.filter (\e -> e.slug == eventSlug)
|
||||
|> List.head
|
||||
|
||||
eventInstances =
|
||||
List.filter (\instance -> instance.eventSlug == eventSlug) model.eventInstances
|
||||
in
|
||||
case event of
|
||||
Just event ->
|
||||
div [ class "row" ]
|
||||
[ div [ class "col-sm-9" ]
|
||||
[ a [ onClick BackInHistory, classList [ ( "btn", True ), ( "btn-default", True ) ] ]
|
||||
[ i [ classList [ ( "fa", True ), ( "fa-chevron-left", True ) ] ] []
|
||||
, text " Back"
|
||||
]
|
||||
, h4 [] [ text event.title ]
|
||||
, p [] [ Markdown.toHtml [] event.abstract ]
|
||||
, hr [] []
|
||||
, eventInstancesList eventSlug model.eventInstances
|
||||
]
|
||||
, div
|
||||
[ classList
|
||||
[ ( "col-sm-3", True )
|
||||
, ( "schedule-sidebar", True )
|
||||
, ( "sticky", True )
|
||||
]
|
||||
]
|
||||
[ videoRecordingSidebar event
|
||||
, speakerSidebar event.speakers
|
||||
]
|
||||
[ eventDetailContent event
|
||||
, eventDetailSidebar event eventInstances
|
||||
]
|
||||
|
||||
Nothing ->
|
||||
div [ class "row" ]
|
||||
[ text
|
||||
(case model.dataLoaded of
|
||||
True ->
|
||||
"Event not found."
|
||||
|
||||
False ->
|
||||
"Loading..."
|
||||
)
|
||||
[ h4 [] [ text "Event not found." ]
|
||||
, a [ href "#" ] [ text "Click here to go the schedule overview." ]
|
||||
]
|
||||
|
||||
|
||||
videoRecordingSidebar : Event -> Html Msg
|
||||
videoRecordingSidebar event =
|
||||
eventDetailContent : Event -> Html Msg
|
||||
eventDetailContent event =
|
||||
div [ class "col-sm-9" ]
|
||||
[ a [ onClick BackInHistory, classList [ ( "btn", True ), ( "btn-default", True ) ] ]
|
||||
[ i [ classList [ ( "fa", True ), ( "fa-chevron-left", True ) ] ] []
|
||||
, text " Back"
|
||||
]
|
||||
, h3 [] [ text event.title ]
|
||||
, p [] [ Markdown.toHtml [] event.abstract ]
|
||||
]
|
||||
|
||||
|
||||
eventDetailSidebar : Event -> List EventInstance -> Html Msg
|
||||
eventDetailSidebar event eventInstances =
|
||||
let
|
||||
( video, willBeRecorded ) =
|
||||
if event.videoUrl /= "" then
|
||||
( h4 [] [ text "Watch the video here!" ], True )
|
||||
else if event.videoRecording == True then
|
||||
( h4 [] [ text "This event will be recorded!" ], True )
|
||||
else
|
||||
( h4 [] [ text "This event will NOT be recorded!" ], False )
|
||||
videoRecordingLink =
|
||||
case event.videoUrl of
|
||||
"" ->
|
||||
[]
|
||||
|
||||
_ ->
|
||||
[ a [ href event.videoUrl, classList [ ( "btn", True ), ( "btn-success", True ) ] ]
|
||||
[ i [ classList [ ( "fa", True ), ( "fa-film", True ) ] ] []
|
||||
, text " Watch recording here!"
|
||||
]
|
||||
]
|
||||
in
|
||||
div [ classList [ ( "alert", True ), ( "alert-danger", not willBeRecorded ), ( "alert-info", willBeRecorded ) ] ]
|
||||
[ video ]
|
||||
div
|
||||
[ classList
|
||||
[ ( "col-sm-3", True )
|
||||
, ( "schedule-sidebar", True )
|
||||
, ( "sticky", True )
|
||||
]
|
||||
]
|
||||
(videoRecordingLink
|
||||
++ [ speakerSidebar event.speakers
|
||||
, eventMetaDataSidebar event
|
||||
, eventInstancesSidebar eventInstances
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
eventMetaDataSidebar : Event -> Html Msg
|
||||
eventMetaDataSidebar event =
|
||||
let
|
||||
videoRecording =
|
||||
case event.videoRecording of
|
||||
True ->
|
||||
"Yes"
|
||||
|
||||
False ->
|
||||
"No"
|
||||
in
|
||||
div []
|
||||
[ h4 [] [ text "Metadata" ]
|
||||
, ul []
|
||||
[ li [] [ strong [] [ text "Type: " ], text event.eventType ]
|
||||
, li [] [ strong [] [ text "Recording: " ], text videoRecording ]
|
||||
]
|
||||
]
|
||||
|
||||
|
||||
speakerSidebar : List Speaker -> Html Msg
|
||||
|
@ -94,27 +125,30 @@ speakerDetail speaker =
|
|||
]
|
||||
|
||||
|
||||
eventInstancesList : String -> List EventInstance -> Html Msg
|
||||
eventInstancesList eventSlug eventInstances =
|
||||
let
|
||||
instances =
|
||||
List.filter (\instance -> instance.eventSlug == eventSlug) eventInstances
|
||||
in
|
||||
div []
|
||||
[ h4 []
|
||||
[ text "This event will occur at:" ]
|
||||
, ul
|
||||
[]
|
||||
(List.map eventInstanceItem instances)
|
||||
]
|
||||
eventInstancesSidebar : List EventInstance -> Html Msg
|
||||
eventInstancesSidebar eventInstances =
|
||||
div []
|
||||
[ h4 []
|
||||
[ text "This event will occur at:" ]
|
||||
, ul
|
||||
[]
|
||||
(List.map eventInstanceItem eventInstances)
|
||||
]
|
||||
|
||||
|
||||
eventInstanceItem : EventInstance -> Html Msg
|
||||
eventInstanceItem eventInstance =
|
||||
li []
|
||||
[ text
|
||||
((Date.Extra.toFormattedString "y-MM-dd HH:mm" eventInstance.from)
|
||||
++ " to "
|
||||
++ (Date.Extra.toFormattedString "y-MM-d HH:mm" eventInstance.to)
|
||||
)
|
||||
]
|
||||
let
|
||||
toFormat =
|
||||
if Date.day eventInstance.from == Date.day eventInstance.to then
|
||||
"HH:mm"
|
||||
else
|
||||
"E HH:mm"
|
||||
in
|
||||
li []
|
||||
[ text
|
||||
((Date.Extra.toFormattedString "E HH:mm" eventInstance.from)
|
||||
++ " to "
|
||||
++ (Date.Extra.toFormattedString toFormat eventInstance.to)
|
||||
)
|
||||
]
|
||||
|
|
|
@ -438,6 +438,7 @@ class Event(CampRelatedModel):
|
|||
for speaker in self.speakers.all()
|
||||
],
|
||||
'video_recording': self.video_recording,
|
||||
'event_type': self.event_type.name,
|
||||
}
|
||||
|
||||
if self.video_url:
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
{% block extra_head %}
|
||||
<noscript>
|
||||
<meta http-equiv="refresh" content="3; url={% url "noscript_schedule_index" camp_slug=camp.slug %}" />
|
||||
<meta http-equiv="refresh" content="0; url={% url "noscript_schedule_index" camp_slug=camp.slug %}" />
|
||||
</noscript>
|
||||
{% endblock %}
|
||||
|
||||
|
|
|
@ -220,10 +220,16 @@ footer {
|
|||
.schedule-filter ul {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.schedule-filter ul li {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.schedule-filter .btn {
|
||||
min-width: 200px;
|
||||
width: 100%;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue