mirror of
https://github.com/glanceapp/glance.git
synced 2024-09-11 04:55:38 +03:00
Calendar Events implemented.
This commit is contained in:
parent
1411268e35
commit
584a3ac016
1
go.mod
1
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
|
||||
|
13
go.sum
13
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=
|
||||
|
@ -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 {
|
||||
|
@ -1,27 +1,34 @@
|
||||
{{ template "widget-base.html" . }}
|
||||
|
||||
{{ define "widget-content" }}
|
||||
{{ template "widget-base.html" . }} {{ define "widget-content" }}
|
||||
<div class="flex justify-between items-center">
|
||||
<div class="color-highlight size-h1">{{ .Calendar.CurrentMonthName }}</div>
|
||||
<ul class="list-horizontal-text color-highlight size-h4">
|
||||
<li>Week {{ .Calendar.CurrentWeekNumber }}</li>
|
||||
<li>{{ .Calendar.CurrentYear }}</li>
|
||||
</ul>
|
||||
<div class="color-highlight size-h1">{{ .Calendar.CurrentMonthName }}</div>
|
||||
<ul class="list-horizontal-text color-highlight size-h4">
|
||||
<li>Week {{ .Calendar.CurrentWeekNumber }}</li>
|
||||
<li>{{ .Calendar.CurrentYear }}</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-wrap size-h6 margin-top-10 color-subdue">
|
||||
<div class="calendar-day">Mo</div>
|
||||
<div class="calendar-day">Tu</div>
|
||||
<div class="calendar-day">We</div>
|
||||
<div class="calendar-day">Th</div>
|
||||
<div class="calendar-day">Fr</div>
|
||||
<div class="calendar-day">Sa</div>
|
||||
<div class="calendar-day">Su</div>
|
||||
<div class="calendar-day">Mo</div>
|
||||
<div class="calendar-day">Tu</div>
|
||||
<div class="calendar-day">We</div>
|
||||
<div class="calendar-day">Th</div>
|
||||
<div class="calendar-day">Fr</div>
|
||||
<div class="calendar-day">Sa</div>
|
||||
<div class="calendar-day">Su</div>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-wrap">
|
||||
{{ range .Calendar.Days }}
|
||||
<div class="calendar-day{{ if eq . $.Calendar.CurrentDay }} calendar-day-today{{ end }}">{{ . }}</div>
|
||||
<div class="flex flex-wrap justify-center items-center">
|
||||
{{ range .Calendar.Days }}
|
||||
<div
|
||||
class="calendar-day{{ if eq .Day $.Calendar.CurrentDay }} calendar-day-today{{ end }} {{ if .IsEvent}} calendar-isevent{{ end }}"
|
||||
>
|
||||
{{ if .IsEvent}}
|
||||
<div class="tooltip">
|
||||
<span class="tooltiptext">{{ .Event.EventHover }}</span>
|
||||
</div>
|
||||
{{ end }}
|
||||
<span>{{ .Day }}</span>
|
||||
</div>
|
||||
{{ end }}
|
||||
</div>
|
||||
{{ end }}
|
||||
|
@ -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()
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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()
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user