diff --git a/pages/profile/profile.go b/pages/profile/profile.go index b60cf7f4..507b2062 100644 --- a/pages/profile/profile.go +++ b/pages/profile/profile.go @@ -2,6 +2,7 @@ package profile import ( "sort" + "time" "github.com/aerogo/aero" "github.com/animenotifier/arn" @@ -68,6 +69,39 @@ func Profile(ctx *aero.Context, viewUser *arn.User) string { friends = friends[:maxFriends] } + // Activities + activities := arn.FilterActivities(func(activity arn.Activity) bool { + return activity.GetCreatedBy() == viewUser.ID + }) + + // Time zone offset + var timeZoneOffset time.Duration + analytics := viewUser.Analytics() + + if analytics != nil { + timeZoneOffset = time.Duration(-analytics.General.TimezoneOffset) * time.Minute + } + + now := time.Now().UTC().Add(timeZoneOffset) + weekDay := int(now.Weekday()) + currentYearDay := int(now.YearDay()) + + // Day offset is the number of days we need to reach Sunday + dayOffset := 0 + + if weekDay > 0 { + dayOffset = 7 - weekDay + } + + dayToActivityCount := map[int]int{} + + for _, activity := range activities { + activityTime := activity.GetCreatedTime().Add(timeZoneOffset) + activityYearDay := activityTime.YearDay() + days := currentYearDay - activityYearDay + dayToActivityCount[days+dayOffset]++ + } + // Characters characters := []*arn.Character{} @@ -93,5 +127,5 @@ func Profile(ctx *aero.Context, viewUser *arn.User) string { } ctx.Data = openGraph - return ctx.HTML(components.Profile(viewUser, user, animeList, characters, friends, topGenres, ctx.URI())) + return ctx.HTML(components.Profile(viewUser, user, animeList, characters, friends, topGenres, dayToActivityCount, ctx.URI())) } diff --git a/pages/profile/profile.pixy b/pages/profile/profile.pixy index 8562194b..16579a04 100644 --- a/pages/profile/profile.pixy +++ b/pages/profile/profile.pixy @@ -1,30 +1,32 @@ -component Profile(viewUser *arn.User, user *arn.User, animeList *arn.AnimeList, characters []*arn.Character, friends []*arn.User, topGenres []string, uri string) +component Profile(viewUser *arn.User, user *arn.User, animeList *arn.AnimeList, characters []*arn.Character, friends []*arn.User, topGenres []string, dayToActivityCount map[int]int, uri string) .profile ProfileHeader(viewUser, user, uri) .profile-columns //- Favorites .profile-column.profile-favorites.mountable(data-mountable-type="column") + //- Anime .profile-section h3.profile-column-header.mountable(data-mountable-type="favorites") Anime if len(animeList.Items) == 0 p.no-data.mountable(data-mountable-type="favorites") Nothing here yet. else - .profile-favorite-anime-container + .profile-favorite-anime-container.mountable(data-mountable-type="favorites") each item in animeList.Top(6) - a.profile-favorite-anime.tip.mountable(href=item.Anime().Link(), aria-label=item.Anime().Title.ByUser(user), data-mountable-type="favorites") + a.profile-favorite-anime.tip.mountable(href=item.Anime().Link(), aria-label=item.Anime().Title.ByUser(user), data-mountable-type="anime") img.profile-favorite-anime-image.lazy(data-src=item.Anime().ImageLink("small"), data-webp=true, alt=item.Anime().Title.ByUser(user)) + //- Characters .profile-section h3.profile-column-header.mountable(data-mountable-type="favorites") Characters if len(characters) == 0 p.no-data.mountable(data-mountable-type="favorites") Nothing here yet. else - .profile-favorite-characters-container + .profile-favorite-characters-container.mountable(data-mountable-type="favorites") each character in characters - .mountable(data-mountable-type="favorites") + .mountable(data-mountable-type="character") CharacterSmall(character, user) //- a.profile-favorite-character.tip.mountable(href=character.Link(), aria-label=character.Name.ByUser(user), data-mountable-type="favorite-anime") //- img.profile-favorite-character-image.lazy(data-src=character.ImageLink("small"), data-webp=true, alt=character.Name.ByUser(user)) @@ -37,27 +39,47 @@ component Profile(viewUser *arn.User, user *arn.User, animeList *arn.AnimeList, //- Extra .profile-column.profile-extra.mountable(data-mountable-type="column") + //- Genres .profile-section h3.profile-column-header.mountable(data-mountable-type="extra") Genres if len(topGenres) == 0 p.no-data.mountable(data-mountable-type="extra") Nothing here yet. else - .anime-genres + .anime-genres.mountable(data-mountable-type="extra") each genre in topGenres - a.anime-genre.mountable(href="/genre/" + strings.ToLower(genre), data-mountable-type="extra")= genre + a.anime-genre.mountable(href="/genre/" + strings.ToLower(genre), data-mountable-type="genre")= genre + //- Friends .profile-section h3.profile-column-header.mountable(data-mountable-type="extra") Friends if len(friends) == 0 p.no-data.mountable(data-mountable-type="extra") Nothing here yet. else - .profile-friends + .profile-friends.mountable(data-mountable-type="extra") each friend in friends - .profile-friend.mountable(data-mountable-type="extra") + .profile-friend.mountable(data-mountable-type="friend") Avatar(friend) + //- Activity + .profile-section + h3.profile-column-header.mountable(data-mountable-type="extra") Activity + + .profile-activities.mountable(data-mountable-type="extra") + for month := 5; month >= 0; month-- + .activities-month + for week := 3; week >= 0; week-- + .activities-week + for day := 6; day >= 0; day-- + if dayToActivityCount[month * 28 + week * 7 + day] == 0 + .box.mountable(data-count="0", data-mountable-type=fmt.Sprintf("month-%d", month)) + else + .box.tip.mountable(aria-label=fmt.Sprintf("%s: %s", time.Weekday((6 - day + 1) % 7).String(), stringutils.Plural(dayToActivityCount[month * 28 + week * 7 + day], "activity")), data-count=dayToActivityCount[month * 28 + week * 7 + day], data-mountable-type=fmt.Sprintf("month-%d", month)) + + if day == 2 + .spacer-box + component ProfileHeader(viewUser *arn.User, user *arn.User, uri string) ProfileHead(viewUser, user, uri) diff --git a/pages/profile/profile.scarlet b/pages/profile/profile.scarlet index 3ed54435..69c9fba9 100644 --- a/pages/profile/profile.scarlet +++ b/pages/profile/profile.scarlet @@ -159,6 +159,39 @@ const profile-image-size = 280px // 100% // filter brightness(35%) blur(0) +.profile-activities + horizontal + +const month-margin = 0.4rem + +.activities-month + horizontal + margin 0 calc(month-margin / 2) + +.activities-week + vertical + +.box + width 0.75rem + height 0.75rem + border-radius 1px + margin 1px + background hsla(link-color-h, link-color-s, link-color-l, 0.75) + + :hover + cursor pointer + background link-hover-color + + [data-count="0"] + background reverse-light-color + + :hover + cursor default + background reverse-light-color + +.spacer-box + height month-margin + .profile-image object-fit cover width 100%