From 7142da950d468edd04f3fdb509634684fc28c38f Mon Sep 17 00:00:00 2001 From: Drew DeVault Date: Wed, 20 May 2020 12:39:37 -0400 Subject: [PATCH] alps theme: initial layout for calendar --- plugins/caldav/routes.go | 60 ++++++++++++++++++ themes/alps/assets/style.css | 101 ++++++++++++++++++++++++++++++- themes/alps/calendar-header.html | 18 ++++++ themes/alps/calendar.html | 84 +++++++++++++++++++++++++ 4 files changed, 262 insertions(+), 1 deletion(-) create mode 100644 themes/alps/calendar-header.html create mode 100644 themes/alps/calendar.html diff --git a/plugins/caldav/routes.go b/plugins/caldav/routes.go index cb8aa2a..d7c31f7 100644 --- a/plugins/caldav/routes.go +++ b/plugins/caldav/routes.go @@ -18,9 +18,16 @@ import ( type CalendarRenderData struct { alps.BaseRenderData Time time.Time + Now time.Time + Dates [7 * 6]time.Time Calendar *caldav.Calendar Events []CalendarObject PrevPage, NextPage string + PrevTime, NextTime time.Time + + EventsForDate func(time.Time) []CalendarObject + DaySuffix func(n int) string + Sub func(a, b int) int } type EventRenderData struct { @@ -96,13 +103,66 @@ func registerRoutes(p *alps.GoPlugin, u *url.URL) { return fmt.Errorf("failed to query calendar: %v", err) } + // TODO: Time zones are hard + var dates [7 * 6]time.Time + initialDate := start.UTC() + initialDate = initialDate.AddDate(0, 0, -int(initialDate.Weekday())) + for i := 0; i < len(dates); i += 1 { + dates[i] = initialDate + initialDate = initialDate.AddDate(0, 0, 1) + } + + eventMap := make(map[time.Time][]CalendarObject) + for _, ev := range events { + ev := ev // make a copy + // TODO: include event on each date for which it is active + co := ev.Data.Events()[0] + startTime, _ := co.DateTimeStart(nil) + startTime = startTime.UTC().Truncate(time.Hour * 24) + eventMap[startTime] = append(eventMap[startTime], CalendarObject{&ev}) + } + return ctx.Render(http.StatusOK, "calendar.html", &CalendarRenderData{ BaseRenderData: *alps.NewBaseRenderData(ctx), Time: start, + Now: time.Now(), // TODO: Use client time zone Calendar: calendar, + Dates: dates, Events: newCalendarObjectList(events), PrevPage: start.AddDate(0, -1, 0).Format(monthPageLayout), NextPage: start.AddDate(0, 1, 0).Format(monthPageLayout), + PrevTime: start.AddDate(0, -1, 0), + NextTime: start.AddDate(0, 1, 0), + + EventsForDate: func(when time.Time) []CalendarObject { + if events, ok := eventMap[when.Truncate(time.Hour * 24)]; ok { + return events + } + return nil + }, + + DaySuffix: func(n int) string { + if n % 100 >= 11 && n % 100 <= 13 { + return "th" + } + return map[int]string{ + 0: "th", + 1: "st", + 2: "nd", + 3: "rd", + 4: "th", + 5: "th", + 6: "th", + 7: "th", + 8: "th", + 9: "th", + }[n % 10] + }, + + Sub: func (a, b int) int { + // Why isn't this built-in, come on Go + return a - b + }, }) }) diff --git a/themes/alps/assets/style.css b/themes/alps/assets/style.css index c62fbbc..8ce6549 100644 --- a/themes/alps/assets/style.css +++ b/themes/alps/assets/style.css @@ -261,6 +261,11 @@ main.new-contact .actions > *:not(:last-child) { margin-right: 1rem; } +.actions h3 { + align-self: center; + margin: 0 1.3rem 0 1rem; +} + .message-list-subject a { color: #77c; } .message-list-unread.message-list-sender, @@ -370,7 +375,7 @@ main table tfoot { padding: 0.3rem 0.5rem; } -.actions-pagination .button-link:first-child:not(:last-child) { +.actions-pagination .button-link:not(:last-child) { margin-right: 0.3rem; } @@ -444,6 +449,100 @@ main table tfoot { margin-top: 1rem; } +main.calendar .dates { + flex-grow: 1; + padding: 0.3rem; + display: grid; + grid-template-columns: 1fr 1fr 1fr 1fr 1fr 1fr 1fr; + grid-template-rows: auto 1fr 1fr 1fr 1fr 1fr 1fr auto; + grid-template-areas: + "sunday-top monday-top wednesday-top tuesday-top thursday-top friday-top saturday-top" + "dates dates dates dates dates dates dates" + "dates dates dates dates dates dates dates" + "dates dates dates dates dates dates dates" + "dates dates dates dates dates dates dates" + "dates dates dates dates dates dates dates" + "dates dates dates dates dates dates dates" + "sunday-bottom monday-bottom wednesday-bottom tuesday-bottom thursday-bottom friday-bottom saturday-bottom"; + grid-gap: 0.3rem; +} + +main.calendar .dates .weekday { + text-align: center; + font-size: 1.1rem; + font-weight: normal; +} + +main.calendar .dates .sunday-top { grid-area: sunday-top; } +main.calendar .dates .monday-top { grid-area: monday-top; } +main.calendar .dates .tuesday-top { grid-area: tuesday-top; } +main.calendar .dates .wednesday-top { grid-area: wednesday-top; } +main.calendar .dates .thursday-top { grid-area: thursday-top; } +main.calendar .dates .friday-top { grid-area: friday-top; } +main.calendar .dates .saturday-top { grid-area: saturday-top; } +main.calendar .dates .sunday-bottom { grid-area: sunday-bottom; } +main.calendar .dates .monday-bottom { grid-area: monday-bottom; } +main.calendar .dates .tuesday-bottom { grid-area: tuesday-bottom; } +main.calendar .dates .wednesday-bottom { grid-area: wednesday-bottom; } +main.calendar .dates .thursday-bottom { grid-area: thursday-bottom; } +main.calendar .dates .friday-bottom { grid-area: friday-bottom; } +main.calendar .dates .saturday-bottom { grid-area: saturday-bottom; } + +main.calendar .date { + border: 1px solid #eee; + padding: 0.3rem; + background: white; + display: flex; + flex-direction: column; + position: relative; +} + +main.calendar .date.active { + background-color: #f6fff6; + border: 1px solid #afa; +} + +main.calendar .date .date-link { + position: absolute; + top: 0; right: 0; bottom: 0; left: 0; +} + +main.calendar .date.extra { + background: transparent; + border: none; +} + +main.calendar .date ul { + list-style: none; + margin: 0; + padding-left: 0.3rem; +} + +main.calendar .date .events { + flex-grow: 1; +} + +main.calendar .date.extra .events { + visibility: hidden; +} + +main.calendar .events .start-time { + color: #444; +} + +main.calendar .events .overflow { + color: #444; + text-align: right; +} + +main.calendar .date h4 { + font-weight: normal; + text-align: right; + color: #666; +} + +main.calendar .date h4 .da { font-size: 1.2rem; } + input[type="submit"], .button, button, diff --git a/themes/alps/calendar-header.html b/themes/alps/calendar-header.html new file mode 100644 index 0000000..d902806 --- /dev/null +++ b/themes/alps/calendar-header.html @@ -0,0 +1,18 @@ +
+
+ « {{.PrevTime.Format "January"}} +

{{.Time.Format "January 2006"}}

+ {{.NextTime.Format "January"}} » + {{if ne .Time.Month .Now.Month}} + Today » + {{end}} +
+ + +
diff --git a/themes/alps/calendar.html b/themes/alps/calendar.html new file mode 100644 index 0000000..5bdd6eb --- /dev/null +++ b/themes/alps/calendar.html @@ -0,0 +1,84 @@ +{{template "head.html" .}} +{{template "nav.html" .}} + +
+ + +
+
+
+ {{ template "calendar-header.html" . }} +
+ +
+

Sunday

+

Monday

+

Tuesday

+

Wednesday

+

Thursday

+

Friday

+

Saturday

+ + {{$base := .}} + {{range .Dates}} +
+ {{if eq $base.Time.Month .Month}} + + {{end}} +
+ {{$events := (call $base.EventsForDate .)}} + {{if $events}} +
    + {{$overflow := 0}} + {{if gt (len $events) 3}} + {{$overflow = call $base.Sub (len $events) 3}} + {{$events = slice $events 0 3}} + {{end}} + + {{range $events}} + {{$event := index .Data.Events 0}} +
  • + + {{($event.DateTimeStart nil).Format "15:04"}} + + {{$event.Props.Text "SUMMARY"}} +
  • + {{end}} + {{if ne $overflow 0}} +
  • ...and {{$overflow}} more
  • + {{end}} +
+ {{end}} +
+

+ {{.Format "Jan"}} + {{.Format "2"}}{{call $base.DaySuffix .Day}} +

+
+ {{end}} + +

Sunday

+

Monday

+

Tuesday

+

Wednesday

+

Thursday

+

Friday

+

Saturday

+
+ +
+ {{ template "calendar-header.html" . }} +
+
+
+
+ +{{template "foot.html"}}