From 584a3ac016bd99cd8c410630c73dcd26f3f8ecaa Mon Sep 17 00:00:00 2001 From: develoopeer Date: Sun, 28 Jul 2024 23:21:13 +0300 Subject: [PATCH] Calendar Events implemented. --- go.mod | 1 + go.sum | 13 +++++ internal/assets/static/main.css | 58 +++++++++++++++++++--- internal/assets/templates/calendar.html | 43 ++++++++++------- internal/feed/calendar.go | 64 ++++++++++++++++++++++--- internal/feed/primitives.go | 11 ++++- internal/widget/calendar.go | 3 +- 7 files changed, 161 insertions(+), 32 deletions(-) diff --git a/go.mod b/go.mod index 502fc709..f353a602 100644 --- a/go.mod +++ b/go.mod @@ -11,6 +11,7 @@ require ( require ( github.com/PuerkitoBio/goquery v1.9.1 // indirect github.com/andybalholm/cascadia v1.3.2 // indirect + github.com/arran4/golang-ical v0.3.1 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/mmcdole/goxpp v1.1.1 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect diff --git a/go.sum b/go.sum index 54489e6c..db0748fc 100644 --- a/go.sum +++ b/go.sum @@ -2,12 +2,19 @@ github.com/PuerkitoBio/goquery v1.9.1 h1:mTL6XjbJTZdpfL+Gwl5U2h1l9yEkJjhmlTeV9VP github.com/PuerkitoBio/goquery v1.9.1/go.mod h1:cW1n6TmIMDoORQU5IU/P1T3tGFunOeXEpGP2WHRwkbY= github.com/andybalholm/cascadia v1.3.2 h1:3Xi6Dw5lHF15JtdcmAHD3i1+T8plmv7BQ/nsViSLyss= github.com/andybalholm/cascadia v1.3.2/go.mod h1:7gtRlve5FxPPgIgX36uWBX58OdBsSS6lUvCFb+h7KvU= +github.com/arran4/golang-ical v0.3.1 h1:v13B3eQZ9VDHTAvT6M11vVzxYgcYmjyPBE2eAZl3VZk= +github.com/arran4/golang-ical v0.3.1/go.mod h1:LZWxF8ZIu/sjBVUCV0udiVPrQAgq3V0aa0RfbO99Qkk= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/mmcdole/gofeed v1.3.0 h1:5yn+HeqlcvjMeAI4gu6T+crm7d0anY85+M+v6fIFNG4= github.com/mmcdole/gofeed v1.3.0/go.mod h1:9TGv2LcJhdXePDzxiuMnukhV2/zb6VtnZt1mS+SjkLE= github.com/mmcdole/goxpp v1.1.1 h1:RGIX+D6iQRIunGHrKqnA2+700XMCnNv0bAOOv5MUhx8= @@ -17,10 +24,12 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= @@ -63,5 +72,9 @@ golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/internal/assets/static/main.css b/internal/assets/static/main.css index 62b44809..47036b20 100644 --- a/internal/assets/static/main.css +++ b/internal/assets/static/main.css @@ -813,15 +813,61 @@ kbd:active { } .calendar-day { - width: calc(100% / 7); - text-align: center; - padding: 0.6rem 0; + width: calc(100% / 7); + text-align: center; + display: flex; + flex-direction: column; + align-items: center; + padding: 0.6rem 0; } .calendar-day-today { - border-radius: var(--border-radius); - background-color: hsl(var(--bghs), calc(var(--scheme) (var(--scheme) (var(--bgl)) + 6%))); - color: var(--color-text-highlight); + border-radius: var(--border-radius); + background-color: hsl( + var(--bghs), + calc(var(--scheme) (var(--scheme) (var(--bgl)) + 6%)) + ); + color: var(--color-text-highlight); +} + +.calendar-isevent { + color: var(--color-primary); + cursor: pointer; +} +.tooltip { + position: relative; + display: inline-block; + width: 0; + height: 0; +} +.tooltiptext { + transition: 0.5s; +} +/* Tooltip text */ +.tooltip .tooltiptext { + visibility: hidden; + width: 150px; + background-color: hsl( + var(--bghs), + calc(var(--scheme) (var(--scheme) (var(--bgl)) + 6%)) + ); + color: var(--color-text-highlight); + text-align: center; + padding: 5px 0; + border-radius: 6px; + opacity: 0; + + position: absolute; + z-index: 1; + bottom: 100%; + left: 50%; + margin-bottom: 5px; + margin-left: -75px; +} + +.calendar-day:hover .tooltiptext { + visibility: visible; + opacity: 0.8; } .weather-column { diff --git a/internal/assets/templates/calendar.html b/internal/assets/templates/calendar.html index 68fda833..ce20968e 100644 --- a/internal/assets/templates/calendar.html +++ b/internal/assets/templates/calendar.html @@ -1,27 +1,34 @@ -{{ template "widget-base.html" . }} - -{{ define "widget-content" }} +{{ template "widget-base.html" . }} {{ define "widget-content" }}
-
{{ .Calendar.CurrentMonthName }}
- +
{{ .Calendar.CurrentMonthName }}
+
-
Mo
-
Tu
-
We
-
Th
-
Fr
-
Sa
-
Su
+
Mo
+
Tu
+
We
+
Th
+
Fr
+
Sa
+
Su
-
- {{ range .Calendar.Days }} -
{{ . }}
+
+ {{ range .Calendar.Days }} +
+ {{ if .IsEvent}} +
+ {{ .Event.EventHover }} +
{{ end }} + {{ .Day }} +
+ {{ end }}
{{ end }} diff --git a/internal/feed/calendar.go b/internal/feed/calendar.go index f7ec5d45..b4e6d3ee 100644 --- a/internal/feed/calendar.go +++ b/internal/feed/calendar.go @@ -1,11 +1,19 @@ package feed -import "time" +import ( + "log" + "net/http" + "os" + "strings" + "time" + + ics "github.com/arran4/golang-ical" +) // TODO: very inflexible, refactor to allow more customizability // TODO: allow changing first day of week // TODO: allow changing between showing the previous and next week and the entire month -func NewCalendar(now time.Time) *Calendar { +func NewCalendar(now time.Time, icsurl string) *Calendar { year, week := now.ISOWeek() weekday := now.Weekday() @@ -25,18 +33,35 @@ func NewCalendar(now time.Time) *Calendar { startDaysFrom := now.Day() - int(weekday+6) - days := make([]int, 21) - + days := make([]CalendayDay, 21) + events, _ := ReadPublicIcs(icsurl) for i := 0; i < 21; i++ { day := startDaysFrom + i + month := now.Month() + var dayEvent CalendarEvent if day < 1 { day = previousMonthDays + day + month -= 1 } else if day > currentMonthDays { day = day - currentMonthDays + month += 1 } - - days[i] = day + if events != nil { + for _, event := range events { + startAt, err := event.GetStartAt() + if err != nil { + log.Panic(err) + } + if startAt.Day() == day && startAt.Month() == month { + dayEvent.StartedDay = startAt + dayEvent.EventHover = event.GetProperty("SUMMARY").Value + days[i].IsEvent = true + } + } + } + days[i].Day = day + days[i].Event = dayEvent } return &Calendar{ @@ -48,6 +73,33 @@ func NewCalendar(now time.Time) *Calendar { } } +func ParseEventsFromFile(file string) []*ics.VEvent { + eventString, err := os.ReadFile(file) + if err != nil { + log.Panic(err) + } + cal, err := ics.ParseCalendar(strings.NewReader(string(eventString))) + if err != nil { + log.Panic(err) + } + events := cal.Events() + return events +} + +func ReadPublicIcs(url string) ([]*ics.VEvent, error) { + response, err := http.Get(url) + if err != nil { + return nil, err + } + defer response.Body.Close() + cal, err := ics.ParseCalendar(response.Body) + if err != nil { + return nil, err + } + events := cal.Events() + return events, nil +} + func daysInMonth(m time.Month, year int) int { return time.Date(year, m+1, 0, 0, 0, 0, 0, time.UTC).Day() } diff --git a/internal/feed/primitives.go b/internal/feed/primitives.go index 6e0c98f3..62723773 100644 --- a/internal/feed/primitives.go +++ b/internal/feed/primitives.go @@ -21,12 +21,21 @@ type ForumPost struct { type ForumPosts []ForumPost +type CalendarEvent struct { + StartedDay time.Time + EventHover string +} +type CalendayDay struct { + Day int + IsEvent bool + Event CalendarEvent +} type Calendar struct { CurrentDay int CurrentWeekNumber int CurrentMonthName string CurrentYear int - Days []int + Days []CalendayDay } type Weather struct { diff --git a/internal/widget/calendar.go b/internal/widget/calendar.go index a1263538..ae30ec67 100644 --- a/internal/widget/calendar.go +++ b/internal/widget/calendar.go @@ -12,6 +12,7 @@ import ( type Calendar struct { widgetBase `yaml:",inline"` Calendar *feed.Calendar + Icsurl string `yaml:"icsurl"` } func (widget *Calendar) Initialize() error { @@ -21,7 +22,7 @@ func (widget *Calendar) Initialize() error { } func (widget *Calendar) Update(ctx context.Context) { - widget.Calendar = feed.NewCalendar(time.Now()) + widget.Calendar = feed.NewCalendar(time.Now(), widget.Icsurl) widget.withError(nil).scheduleNextUpdate() }