From 725535d4a797062dda88687b525941e6739c3b68 Mon Sep 17 00:00:00 2001 From: Vidir Valberg Gudmundsson Date: Wed, 19 Jul 2017 16:12:12 +0200 Subject: [PATCH] Some progress on the dayview. --- schedule/src/Decoders.elm | 6 +- schedule/src/Views.elm | 17 ++- schedule/src/Views/DayPicker.elm | 2 +- schedule/src/Views/DayView.elm | 165 ++++++++++++++++++++++-- schedule/src/Views/EventDetail.elm | 6 +- schedule/src/Views/FilterView.elm | 45 ++++++- schedule/src/Views/ScheduleOverview.elm | 47 ++----- src/static_src/css/bornhack.css | 46 ++++--- 8 files changed, 260 insertions(+), 74 deletions(-) diff --git a/schedule/src/Decoders.elm b/schedule/src/Decoders.elm index 67f99d8a..d04b887c 100644 --- a/schedule/src/Decoders.elm +++ b/schedule/src/Decoders.elm @@ -14,7 +14,7 @@ import Date exposing (Date, Month(..)) -- External modules -import Date.Extra as DateExtra +import Date.Extra -- DECODERS @@ -60,12 +60,12 @@ dateDecoder : Decoder Date dateDecoder = let unpacked x = - case DateExtra.fromIsoString x of + case Date.Extra.fromIsoString x of Just value -> value Nothing -> - DateExtra.fromParts 1970 Jan 1 0 0 0 0 + Date.Extra.fromParts 1970 Jan 1 0 0 0 0 in Json.Decode.map unpacked string diff --git a/schedule/src/Views.elm b/schedule/src/Views.elm index c6d82c52..4e5ce5d0 100644 --- a/schedule/src/Views.elm +++ b/schedule/src/Views.elm @@ -10,9 +10,15 @@ import Views.EventDetail exposing (eventDetailView) import Views.ScheduleOverview exposing (scheduleOverviewView) +-- Core modules + +import Date exposing (Month(..)) + + -- External modules import Html exposing (Html, Attribute, div, input, text, li, ul, a, h4, label, i, span, hr, small, p) +import Date.Extra view : Model -> Html Msg @@ -25,7 +31,16 @@ view model = scheduleOverviewView model DayRoute dayIso -> - dayView dayIso model + let + day = + case (List.head (List.filter (\x -> (Date.Extra.toFormattedString "y-MM-dd" x.date) == dayIso) model.days)) of + Just day -> + day + + Nothing -> + Day "" (Date.Extra.fromParts 1970 Jan 1 0 0 0 0) "" + in + dayView day model EventRoute eventSlug -> eventDetailView eventSlug model diff --git a/schedule/src/Views/DayPicker.elm b/schedule/src/Views/DayPicker.elm index d572ab28..6d25bc99 100644 --- a/schedule/src/Views/DayPicker.elm +++ b/schedule/src/Views/DayPicker.elm @@ -61,7 +61,7 @@ dayButton day activeDay = , ( "btn-default", not isActive ) , ( "btn-primary", isActive ) ] - , href ("#day/" ++ (Date.toFormattedString "y-M-d" day.date)) + , href ("#day/" ++ (Date.toFormattedString "y-MM-dd" day.date)) , onClick (MakeActiveday day) ] [ text day.day_name diff --git a/schedule/src/Views/DayView.elm b/schedule/src/Views/DayView.elm index fb5d826a..c7bf9562 100644 --- a/schedule/src/Views/DayView.elm +++ b/schedule/src/Views/DayView.elm @@ -3,21 +3,168 @@ module Views.DayView exposing (dayView) -- Local modules import Messages exposing (Msg(..)) -import Models exposing (Model) -import Views.FilterView exposing (filterSidebar) +import Models exposing (Model, Day, EventInstance) + + +-- Core modules + +import Date exposing (Date) -- External modules -import Html exposing (Html, text, div, ul, li, span, i, h4, table) +import Html exposing (Html, text, div, ul, li, span, i, h4, table, p) +import Html.Attributes exposing (classList, style) +import Date.Extra --- Something about having a column per location!! +blockHeight : Int +blockHeight = + 15 -dayView : String -> Model -> Html Msg -dayView dayIso model = - div [] - [ filterSidebar model - , table [] [] +headerHeight : Int +headerHeight = + 50 + + +px : Int -> String +px value = + (toString value) ++ "px" + + +dayView : Day -> Model -> Html Msg +dayView day model = + let + start = + Date.Extra.add Date.Extra.Hour model.flags.schedule_midnight_offset_hours day.date + + lastHour = + Date.Extra.add Date.Extra.Day 1 start + + minutes = + Date.Extra.range Date.Extra.Minute 15 start lastHour + + filteredEventInstances = + List.filter (\x -> Date.Extra.equalBy Date.Extra.Day x.from day.date) model.eventInstances + in + div + [ classList [ ( "row", True ) ] ] + [ gutter minutes + , locationColumns minutes filteredEventInstances model.eventLocations + ] + + +locationColumns minutes eventInstances eventLocations = + let + columnWidth = + 100.0 / toFloat (List.length eventLocations) + in + div + [ style + [ ( "display", "flex" ) + , ( "justify-content", "space-around" ) + ] + ] + (List.map (\x -> locationColumn columnWidth minutes eventInstances x) eventLocations) + + +locationColumn columnWidth minutes eventInstances location = + let + locationInstances = + List.filter (\x -> x.location == location.slug) eventInstances + in + div + [ style + [ ( "width", (toString columnWidth) ++ "%" ) + ] + , classList + [ ( "location-column", True ) ] + ] + ([ div + [ style + [ ( "height", px headerHeight ) + ] + , classList + [ ( "location-column-header", True ) + ] + ] + [ text location.name ] + ] + ++ (List.map (\x -> hourBlock locationInstances x) minutes) + ) + + +hourBlock eventInstances minutes = + let + filteredEventInstances = + List.filter (\x -> Date.Extra.equalBy Date.Extra.Minute minutes x.from) eventInstances + in + div + [ style + [ ( "display", "flex" ) + , ( "height", px blockHeight ) + ] + , classList + [ ( "location-column-slot", True ) + ] + ] + (List.map eventInstanceBlock filteredEventInstances) + + +eventInstanceBlock : EventInstance -> Html Msg +eventInstanceBlock eventInstance = + let + length = + (toFloat (Date.Extra.diff Date.Extra.Minute eventInstance.from eventInstance.to)) / 15 + + height = + (toString (length * toFloat blockHeight)) ++ "px" + in + div + [ classList + [ ( "event", True ) + , ( "event-in-dayview", True ) + ] + , style + [ ( "height", height ) + , ( "background-color", eventInstance.backgroundColor ) + ] + ] + [ p [] [ text ((Date.Extra.toFormattedString "HH:mm" eventInstance.from) ++ " " ++ eventInstance.title) ] + ] + + +gutter : List Date -> Html Msg +gutter hours = + div + [ classList + [ ( "col-sm-1", True ) + , ( "day-view-gutter", True ) + ] ] + ([ div [ style [ ( "height", px headerHeight ) ] ] + [ text "" + ] + ] + ++ (List.map gutterHour hours) + ) + + +gutterHour : Date -> Html Msg +gutterHour date = + let + textToShow = + case Date.minute date of + 0 -> + (Date.Extra.toFormattedString "HH:mm" date) + + 30 -> + (Date.Extra.toFormattedString "HH:mm" date) + + _ -> + "" + in + div [ style [ ( "height", px blockHeight ) ] ] + [ text textToShow + ] diff --git a/schedule/src/Views/EventDetail.elm b/schedule/src/Views/EventDetail.elm index 01c1163a..9f21f36a 100644 --- a/schedule/src/Views/EventDetail.elm +++ b/schedule/src/Views/EventDetail.elm @@ -11,7 +11,7 @@ import Models exposing (..) import Html exposing (Html, text, div, ul, li, span, i, h4, a, p, hr) import Html.Attributes exposing (class, classList, href) import Markdown -import Date.Extra as DateExtra +import Date.Extra eventDetailView : EventSlug -> Model -> Html Msg @@ -99,8 +99,8 @@ eventInstanceItem : EventInstance -> Html Msg eventInstanceItem eventInstance = li [] [ text - ((DateExtra.toFormattedString "y-MM-dd HH:mm" eventInstance.from) + ((Date.Extra.toFormattedString "y-MM-dd HH:mm" eventInstance.from) ++ " to " - ++ (DateExtra.toFormattedString "y-MM-d HH:mm" eventInstance.to) + ++ (Date.Extra.toFormattedString "y-MM-d HH:mm" eventInstance.to) ) ] diff --git a/schedule/src/Views/FilterView.elm b/schedule/src/Views/FilterView.elm index b3a134b9..185e1f99 100644 --- a/schedule/src/Views/FilterView.elm +++ b/schedule/src/Views/FilterView.elm @@ -1,4 +1,4 @@ -module Views.FilterView exposing (filterSidebar, videoRecordingFilters, applyVideoRecordingFilters) +module Views.FilterView exposing (filterSidebar, applyFilters) -- Local modules @@ -11,6 +11,47 @@ import Models exposing (Model, EventInstance) import Html exposing (Html, text, div, ul, li, span, i, h4) import Html.Attributes exposing (class, classList, href) import Html.Events exposing (onClick) +import Date.Extra exposing (Interval(..), equalBy) + + +applyFilters day model = + let + types = + List.map (\eventType -> eventType.slug) + (if List.isEmpty model.filter.eventTypes then + model.eventTypes + else + model.filter.eventTypes + ) + + locations = + List.map (\eventLocation -> eventLocation.slug) + (if List.isEmpty model.filter.eventLocations then + model.eventLocations + else + model.filter.eventLocations + ) + + videoFilters = + List.map (\filter -> filter.filter) + (if List.isEmpty model.filter.videoRecording then + videoRecordingFilters + else + model.filter.videoRecording + ) + + filteredEventInstances = + List.filter + (\eventInstance -> + (Date.Extra.equalBy Month eventInstance.from day.date) + && (Date.Extra.equalBy Date.Extra.Day eventInstance.from day.date) + && List.member eventInstance.location locations + && List.member eventInstance.eventType types + && applyVideoRecordingFilters videoFilters eventInstance + ) + model.eventInstances + in + filteredEventInstances filterSidebar : Model -> Html Msg @@ -61,7 +102,7 @@ applyVideoRecordingFilters filters eventInstance = results = List.map (\filter -> filter eventInstance) filters in - List.member True (Debug.log "results" results) + List.member True results filterView : diff --git a/schedule/src/Views/ScheduleOverview.elm b/schedule/src/Views/ScheduleOverview.elm index 10b7f352..32ce0e9a 100644 --- a/schedule/src/Views/ScheduleOverview.elm +++ b/schedule/src/Views/ScheduleOverview.elm @@ -4,7 +4,7 @@ module Views.ScheduleOverview exposing (scheduleOverviewView) import Messages exposing (Msg(..)) import Models exposing (Model, Day, EventInstance) -import Views.FilterView exposing (filterSidebar, videoRecordingFilters, applyVideoRecordingFilters) +import Views.FilterView exposing (filterSidebar, applyFilters) -- External modules @@ -12,7 +12,7 @@ import Views.FilterView exposing (filterSidebar, videoRecordingFilters, applyVid import Html exposing (Html, text, div, ul, li, span, i, h4, p, small, a) import Html.Lazy exposing (lazy, lazy2) import Html.Attributes exposing (class, classList, href, style) -import Date.Extra as Date exposing (Interval(..), equalBy) +import Date.Extra scheduleOverviewView : Model -> Html Msg @@ -32,40 +32,8 @@ scheduleOverviewView model = dayRowView : Day -> Model -> Html Msg dayRowView day model = let - types = - List.map (\eventType -> eventType.slug) - (if List.isEmpty model.filter.eventTypes then - model.eventTypes - else - model.filter.eventTypes - ) - - locations = - List.map (\eventLocation -> eventLocation.slug) - (if List.isEmpty model.filter.eventLocations then - model.eventLocations - else - model.filter.eventLocations - ) - - videoFilters = - List.map (\filter -> filter.filter) - (if List.isEmpty model.filter.videoRecording then - videoRecordingFilters - else - model.filter.videoRecording - ) - filteredEventInstances = - List.filter - (\eventInstance -> - (Date.equalBy Month eventInstance.from day.date) - && (Date.equalBy Date.Day eventInstance.from day.date) - && List.member eventInstance.location locations - && List.member eventInstance.eventType types - && applyVideoRecordingFilters videoFilters eventInstance - ) - model.eventInstances + applyFilters day model in div [] [ h4 [] @@ -78,7 +46,10 @@ dayRowView day model = dayEventInstanceView : EventInstance -> Html Msg dayEventInstanceView eventInstance = a - [ class "event" + [ classList + [ ( "event", True ) + , ( "event-in-overview", True ) + ] , href ("#event/" ++ eventInstance.eventSlug) , style [ ( "background-color", eventInstance.backgroundColor ) @@ -87,9 +58,9 @@ dayEventInstanceView eventInstance = ] ([ small [] [ text - ((Date.toFormattedString "H:m" eventInstance.from) + ((Date.Extra.toFormattedString "HH:mm" eventInstance.from) ++ " - " - ++ (Date.toFormattedString "H:m" eventInstance.to) + ++ (Date.Extra.toFormattedString "HH:mm" eventInstance.to) ) ] ] diff --git a/src/static_src/css/bornhack.css b/src/static_src/css/bornhack.css index 105e0b59..3804502f 100644 --- a/src/static_src/css/bornhack.css +++ b/src/static_src/css/bornhack.css @@ -149,27 +149,43 @@ footer { .event { padding: 5px; vertical-align: top; - margin: 5px; - width: 200px; - max-width: 200px; - min-width: 200px; - min-height: 100px; flex-grow: 1; border: 1px solid black; cursor: pointer; } -.event-td { - padding: 5px; - vertical-align: top; +.event-in-overview { + min-height: 100px; + margin: 5px; + width: 200px; max-width: 200px; min-width: 200px; - flex-grow: 1; - cursor: pointer; } -.event-td a { - display: block; +.location-column { + margin: 0 2px; + background-color: #eee; +} + +.location-column-header { + text-align: center; + font-weight: bold; + line-height: 50px; + font-size: 20px; + border-bottom: 1px solid #fff; +} + +.location-column-slot { + border-bottom: 1px solid #fff; +} + +.day-view-gutter { + text-align: right; +} + +.event-in-dayview { + overflow: hidden; + text-overflow: ellipsis; } @@ -180,16 +196,12 @@ footer { } } -.event:hover, .event-td:hover { +.event:hover { background-color: black !important; color: white !important; text-decoration: none !important; } -.event-td a:hover { - text-decoration: none !important; -} - .fa-select { font-family: 'FontAwesome','Helvetica Neue',Helvetica,Arial,sans-serif; }