diff --git a/mixins/Comments.pixy b/mixins/Comments.pixy index 81ac9372..5ae53376 100644 --- a/mixins/Comments.pixy +++ b/mixins/Comments.pixy @@ -1,19 +1,15 @@ component Comments(parent arn.PostParent, user *arn.User) .thread .posts - if user == nil && parent.CountPosts() == 0 - p.no-data.mountable No comments have been written yet. - else - each post in parent.Posts() - Postable(post, user, true, "", "") - if user != nil if arn.IsLocked(parent) footer.footer.mountable p.text-center= "This " + strings.ToLower(reflect.TypeOf(parent).Elem().Name()) + " is locked." else - NewPostArea(user, "Comment") - - .buttons - if !arn.IsLocked(parent) - NewPostActions(reflect.TypeOf(parent).Elem().Name(), parent.GetID(), false) \ No newline at end of file + NewPostArea(parent, user, "Comment") + + if user == nil && parent.CountPosts() == 0 + p.no-data.mountable No comments have been written yet. + else + each post in parent.PostsRelevantFirst(5) + Postable(post, user, true, "", "") \ No newline at end of file diff --git a/mixins/NewPostArea.pixy b/mixins/NewPostArea.pixy index 4411df50..fcfa1a38 100644 --- a/mixins/NewPostArea.pixy +++ b/mixins/NewPostArea.pixy @@ -1,4 +1,4 @@ -component NewPostArea(user *arn.User, placeholder string) +component NewPostArea(parent arn.PostParent, user *arn.User, placeholder string) #new-post.post.mountable .post-parent .post-author @@ -6,11 +6,18 @@ component NewPostArea(user *arn.User, placeholder string) textarea#new-post-text.post-content(placeholder=placeholder + "...", aria-label=placeholder) -component NewPostActions(parentType string, parentID string, cancelButton bool) - #new-post-actions.buttons - button#reply-button.mountable.action(data-action="createPost", data-trigger="click", data-parent-type=parentType, data-parent-id=parentID) + if !arn.IsLocked(parent) + NewPostActions(parent, false) + +component NewPostActions(parent arn.PostParent, cancelButton bool) + .buttons.new-post-actions + button#reply-button.mountable.action(data-action="createPost", data-trigger="click", data-parent-type=parent.TypeName(), data-parent-id=parent.GetID()) Icon("mail-reply") - span Reply + + if parent.TypeName() == "Post" || parent.TypeName() == "Thread" + span= "Reply to " + parent.Creator().Nick + else + span Submit if cancelButton button#reply-cancel-button.mountable.action(data-action="cancelReply", data-trigger="click") diff --git a/mixins/Postable.pixy b/mixins/Postable.pixy index b59aee25..f3a55e2c 100644 --- a/mixins/Postable.pixy +++ b/mixins/Postable.pixy @@ -1,5 +1,5 @@ component Postable(post arn.Postable, user *arn.User, includeReplies bool, headerContent string, highlightAuthorID string) - .post.mountable(id=strings.ToLower(post.Type()) + "-" + fmt.Sprint(post.GetID()), data-pro=post.Creator().IsPro(), data-api="/api/" + strings.ToLower(post.Type()) + "/" + post.GetID()) + .post.mountable(id=strings.ToLower(post.TypeName()) + "-" + fmt.Sprint(post.GetID()), data-pro=post.Creator().IsPro(), data-api="/api/" + strings.ToLower(post.TypeName()) + "/" + post.GetID()) .post-parent .post-author Avatar(post.Creator()) @@ -12,7 +12,7 @@ component Postable(post arn.Postable, user *arn.User, includeReplies bool, heade if user != nil && user.ID == post.Creator().ID .post-edit-interface - if post.Type() == "Thread" + if post.TypeName() == "Thread" input.post-title-input.hidden(id="title-" + post.GetID(), value=post.TitleByUser(user), type="text", placeholder="Thread title") textarea.post-text-input.hidden(id="source-" + post.GetID())= post.GetText() @@ -48,7 +48,7 @@ component Postable(post arn.Postable, user *arn.User, includeReplies bool, heade a.post-tool.post-edit.tip.action(data-action="editPost", data-trigger="click", data-id=post.GetID(), aria-label="Edit") Icon("pencil") - if post.Type() != "Thread" + if post.TypeName() != "Thread" if user != nil && (user.Role == "admin" || user.Role == "editor") a.post-tool.post-delete.tip.action(data-action="deletePost", data-trigger="click", data-id=post.GetID(), aria-label="Delete") Icon("trash") diff --git a/pages/activity/activity.go b/pages/activity/activity.go index c3f6bcb5..17d3e651 100644 --- a/pages/activity/activity.go +++ b/pages/activity/activity.go @@ -37,7 +37,7 @@ func fetchActivities(user *arn.User, followedOnly bool) []arn.Activity { return false } - if activity.Type() == "ActivityCreate" { + if activity.TypeName() == "ActivityCreate" { obj := activity.(*arn.ActivityCreate).Object() if obj == nil { @@ -48,7 +48,7 @@ func fetchActivities(user *arn.User, followedOnly bool) []arn.Activity { return !isDraftable || !draft.GetIsDraft() } - if activity.Type() == "ActivityConsumeAnime" { + if activity.TypeName() == "ActivityConsumeAnime" { return activity.(*arn.ActivityConsumeAnime).Anime() != nil } diff --git a/pages/activity/activity.pixy b/pages/activity/activity.pixy index 89a80757..4e6c6d87 100644 --- a/pages/activity/activity.pixy +++ b/pages/activity/activity.pixy @@ -32,20 +32,20 @@ component Activity(activity arn.Activity, user *arn.User) .post-content .activity-header .activity-parent - if activity.Type() == "ActivityCreate" + if activity.TypeName() == "ActivityCreate" ActivityCreateTitle(activity.(*arn.ActivityCreate), user) - else if activity.Type() == "ActivityConsumeAnime" + else if activity.TypeName() == "ActivityConsumeAnime" ActivityConsumeAnimeTitle(activity.(*arn.ActivityConsumeAnime), user) - if user != nil && user.ID == activity.GetCreatedBy() && activity.Type() == "ActivityConsumeAnime" - button.activity-action.tip.action(data-action="deleteObject", data-trigger="click", aria-label="Delete", data-return-path="/activity", data-confirm-type="activity", data-api=fmt.Sprintf("/api/%s/%s", strings.ToLower(activity.Type()), activity.GetID())) + if user != nil && user.ID == activity.GetCreatedBy() && activity.TypeName() == "ActivityConsumeAnime" + button.activity-action.tip.action(data-action="deleteObject", data-trigger="click", aria-label="Delete", data-return-path="/activity", data-confirm-type="activity", data-api=fmt.Sprintf("/api/%s/%s", strings.ToLower(activity.TypeName()), activity.GetID())) RawIcon("trash") .activity-date.utc-date(data-date=activity.GetCreated()) - if activity.Type() == "ActivityCreate" + if activity.TypeName() == "ActivityCreate" ActivityCreateText(activity.(*arn.ActivityCreate), user) - else if activity.Type() == "ActivityConsumeAnime" + else if activity.TypeName() == "ActivityConsumeAnime" ActivityConsumeAnimeText(activity.(*arn.ActivityConsumeAnime), user) component ActivityConsumeAnimeTitle(activity *arn.ActivityConsumeAnime, user *arn.User) diff --git a/pages/anime/character.scarlet b/pages/anime/character.scarlet index 8f526022..04d39003 100644 --- a/pages/anime/character.scarlet +++ b/pages/anime/character.scarlet @@ -6,7 +6,6 @@ align-items center margin 0.5rem default-transition - transform scale(1) :hover .image-title diff --git a/pages/editor/mal.pixy b/pages/editor/mal.pixy index 90e735df..76b73f13 100644 --- a/pages/editor/mal.pixy +++ b/pages/editor/mal.pixy @@ -33,5 +33,5 @@ component CompareMAL(comparisons []*utils.MALComparison, year string, status str .data-comparison-difference-detail= difference.DetailsA() .data-comparison-difference-detail= difference.DetailsB() - button.data-comparison-difference-ignore.action(data-action="newAnimeDiffIgnore", data-trigger="click", data-id=arn.CreateDifferenceID(comparison.Anime.ID, "mal", comparison.MALAnime.ID, difference.Type()), data-hash=difference.Hash()) + button.data-comparison-difference-ignore.action(data-action="newAnimeDiffIgnore", data-trigger="click", data-id=arn.CreateDifferenceID(comparison.Anime.ID, "mal", comparison.MALAnime.ID, difference.TypeName()), data-hash=difference.Hash()) RawIcon("trash") diff --git a/pages/post/reply-ui.go b/pages/post/reply-ui.go index 5f62f859..04d3b8f6 100644 --- a/pages/post/reply-ui.go +++ b/pages/post/reply-ui.go @@ -19,5 +19,5 @@ func ReplyUI(ctx *aero.Context) string { return ctx.Error(http.StatusNotFound, "Post not found", err) } - return ctx.HTML(components.NewPostArea(user, "Reply") + components.NewPostActions(post.Type(), post.ID, true)) + return ctx.HTML(components.NewPostArea(post, user, "Reply") + components.NewPostActions(post, true)) } diff --git a/pages/profile/old.pixy b/pages/profile/old.pixy new file mode 100644 index 00000000..9bb326d5 --- /dev/null +++ b/pages/profile/old.pixy @@ -0,0 +1,37 @@ +//- component ProfileTabs(viewUser *arn.User, uri string) +//- .tabs.mountable.never-unmount +//- Tab("Anime", "th", "/+" + viewUser.Nick) +//- Tab("Characters", "child", "/+" + viewUser.Nick + "/characters/liked") +//- Tab("Forum", "comment", "/+" + viewUser.Nick + "/forum/threads") +//- Tab("Tracks", "music", "/+" + viewUser.Nick + "/soundtracks/liked") +//- Tab("Quotes", "quote-left", "/+" + viewUser.Nick + "/quotes/liked") +//- Tab("Stats", "area-chart", "/+" + viewUser.Nick + "/stats") +//- Tab("Followers", "users", "/+" + viewUser.Nick + "/followers") + +//- if strings.Contains(uri, "/soundtracks") +//- .tabs +//- Tab("Liked", "heart", "/+" + viewUser.Nick + "/soundtracks/liked") +//- Tab("Added", "plus", "/+" + viewUser.Nick + "/soundtracks/added") + +//- if strings.Contains(uri, "/quotes") +//- .tabs +//- Tab("Liked", "heart", "/+" + viewUser.Nick + "/quotes/liked") +//- Tab("Added", "plus", "/+" + viewUser.Nick + "/quotes/added") + +//- Anime shelf +//- if len(animeList.Items) == 0 +//- p.no-data.mountable= viewUser.Nick + " hasn't added any anime yet." +//- else +//- .profile-watching-list.mountable +//- each item in animeList.Items +//- if item.Status == arn.AnimeListStatusWatching || item.Status == arn.AnimeListStatusCompleted +//- a.profile-watching-list-item.tip(href=item.Anime().Link(), aria-label=item.Anime().Title.ByUser(user) + " (" + fmt.Sprint(item.Episodes) + " / " + arn.EpisodesToString(item.Anime().EpisodeCount) + ")") +//- img.profile-watching-list-item-image.lazy(data-src=item.Anime().ImageLink("small"), data-webp="true", data-color=item.Anime().AverageColor(), alt=item.Anime().Title.ByUser(user), importance="high") + +//- Footer +//- .footer +//- .buttons +//- if user != nil && (user.Role == "admin" || user.Role == "editor") +//- a.button.profile-action(href="/api/user/" + viewUser.ID, target="_blank", rel="noopener") +//- Icon("search-plus") +//- span JSON \ No newline at end of file diff --git a/pages/profile/profile.go b/pages/profile/profile.go index c0c2c7ad..b60cf7f4 100644 --- a/pages/profile/profile.go +++ b/pages/profile/profile.go @@ -1,12 +1,19 @@ package profile import ( + "sort" + "github.com/aerogo/aero" "github.com/animenotifier/arn" "github.com/animenotifier/notify.moe/components" "github.com/animenotifier/notify.moe/utils" ) +const ( + maxCharacters = 6 + maxFriends = 7 +) + // Get user profile page. func Get(ctx *aero.Context) string { nick := ctx.Get("nick") @@ -22,6 +29,8 @@ func Get(ctx *aero.Context) string { // Profile renders the user profile page of the given viewUser. func Profile(ctx *aero.Context, viewUser *arn.User) string { user := utils.GetUser(ctx) + + // Anime list animeList := viewUser.AnimeList() if user == nil || user.ID != viewUser.ID { @@ -30,6 +39,10 @@ func Profile(ctx *aero.Context, viewUser *arn.User) string { animeList.SortByRating() + // Genres + topGenres := animeList.TopGenres(5) + + // Open graph openGraph := &arn.OpenGraph{ Tags: map[string]string{ "og:title": viewUser.Nick, @@ -46,7 +59,39 @@ func Profile(ctx *aero.Context, viewUser *arn.User) string { }, } - ctx.Data = openGraph + // Friends + friends := viewUser.Follows().UsersWhoFollowBack() - return ctx.HTML(components.Profile(viewUser, user, animeList, ctx.URI())) + arn.SortUsersFollowers(friends) + + if len(friends) > maxFriends { + friends = friends[:maxFriends] + } + + // Characters + characters := []*arn.Character{} + + for character := range arn.StreamCharacters() { + if arn.Contains(character.Likes, viewUser.ID) { + characters = append(characters, character) + } + } + + sort.Slice(characters, func(i, j int) bool { + aLikes := len(characters[i].Likes) + bLikes := len(characters[j].Likes) + + if aLikes == bLikes { + return characters[i].Name.Canonical < characters[j].Name.Canonical + } + + return aLikes > bLikes + }) + + if len(characters) > maxCharacters { + characters = characters[:maxCharacters] + } + + ctx.Data = openGraph + return ctx.HTML(components.Profile(viewUser, user, animeList, characters, friends, topGenres, ctx.URI())) } diff --git a/pages/profile/profile.pixy b/pages/profile/profile.pixy index 9fc722ea..6a69dc7e 100644 --- a/pages/profile/profile.pixy +++ b/pages/profile/profile.pixy @@ -1,48 +1,53 @@ -component Profile(viewUser *arn.User, user *arn.User, animeList *arn.AnimeList, uri string) - ProfileHeader(viewUser, user, uri) +component Profile(viewUser *arn.User, user *arn.User, animeList *arn.AnimeList, characters []*arn.Character, friends []*arn.User, topGenres []string, uri string) + .profile + ProfileHeader(viewUser, user, uri) - //- if len(animeList.Items) == 0 - //- p.no-data.mountable= viewUser.Nick + " hasn't added any anime yet." - //- else - //- .profile-watching-list.mountable - //- each item in animeList.Items - //- if item.Status == arn.AnimeListStatusWatching || item.Status == arn.AnimeListStatusCompleted - //- a.profile-watching-list-item.tip(href=item.Anime().Link(), aria-label=item.Anime().Title.ByUser(user) + " (" + fmt.Sprint(item.Episodes) + " / " + arn.EpisodesToString(item.Anime().EpisodeCount) + ")") - //- img.profile-watching-list-item-image.lazy(data-src=item.Anime().ImageLink("small"), data-webp="true", data-color=item.Anime().AverageColor(), alt=item.Anime().Title.ByUser(user), importance="high") + .profile-columns + .profile-column.profile-favorites + .profile-section + h3.profile-column-header.mountable Anime + + .profile-favorite-anime-container + 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") + img.profile-favorite-anime-image.lazy(data-src=item.Anime().ImageLink("small"), data-webp=true, alt=item.Anime().Title.ByUser(user)) - //- .footer - //- .buttons - //- if user != nil && (user.Role == "admin" || user.Role == "editor") - //- a.button.profile-action(href="/api/user/" + viewUser.ID, target="_blank", rel="noopener") - //- Icon("search-plus") - //- span JSON + .profile-section + h3.profile-column-header.mountable(data-mountable-type="favorites") Characters + + .profile-favorite-characters-container + each character in characters + .mountable(data-mountable-type="favorites") + 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)) -component ProfileTabs(viewUser *arn.User, uri string) - .tabs.mountable.never-unmount - Tab("Anime", "th", "/+" + viewUser.Nick) - Tab("Characters", "child", "/+" + viewUser.Nick + "/characters/liked") - Tab("Forum", "comment", "/+" + viewUser.Nick + "/forum/threads") - Tab("Tracks", "music", "/+" + viewUser.Nick + "/soundtracks/liked") - Tab("Quotes", "quote-left", "/+" + viewUser.Nick + "/quotes/liked") - Tab("Stats", "area-chart", "/+" + viewUser.Nick + "/stats") - Tab("Followers", "users", "/+" + viewUser.Nick + "/followers") - - if strings.Contains(uri, "/soundtracks") - .tabs - Tab("Liked", "heart", "/+" + viewUser.Nick + "/soundtracks/liked") - Tab("Added", "plus", "/+" + viewUser.Nick + "/soundtracks/added") + .profile-column.profile-activity + .profile-section + h3.profile-column-header.mountable(data-mountable-type="activity") Activity + Comments(viewUser, user) + + .profile-column.profile-extra + .profile-section + h3.profile-column-header.mountable(data-mountable-type="extra") Genres - if strings.Contains(uri, "/quotes") - .tabs - Tab("Liked", "heart", "/+" + viewUser.Nick + "/quotes/liked") - Tab("Added", "plus", "/+" + viewUser.Nick + "/quotes/added") + .anime-genres + each genre in topGenres + a.anime-genre.mountable(href="/genre/" + strings.ToLower(genre), data-mountable-type="extra")= genre + .profile-section + h3.profile-column-header.mountable(data-mountable-type="extra") Friends + + .profile-friends + each friend in friends + .profile-friend.mountable(data-mountable-type="extra") + Avatar(friend) + component ProfileHeader(viewUser *arn.User, user *arn.User, uri string) ProfileHead(viewUser, user, uri) - //- ProfileTabs(viewUser, uri) component ProfileHead(viewUser *arn.User, user *arn.User, uri string) - .profile + .profile-head img.profile-cover.lazy(data-src=viewUser.CoverLink("large"), data-webp="true", alt="Cover image") .profile-image-container.mountable.never-unmount @@ -137,5 +142,4 @@ component ProfileHead(viewUser *arn.User, user *arn.User, uri string) else button.profile-action.action.mountable.never-unmount(data-action="unfollowUser", data-trigger="click", data-api="/api/userfollows/" + user.ID + "/remove/" + viewUser.ID) Icon("user-times") - span Unfollow - \ No newline at end of file + span Unfollow \ No newline at end of file diff --git a/pages/profile/profile.scarlet b/pages/profile/profile.scarlet index 4defe5bb..1ed543c5 100644 --- a/pages/profile/profile.scarlet +++ b/pages/profile/profile.scarlet @@ -1,6 +1,6 @@ const profile-image-size = 280px -.profile +.profile-head vertical align-items center @@ -40,8 +40,59 @@ const profile-image-size = 280px color pro-color animation sk-pulse 1.5s infinite linear +.profile-columns + vertical + +.profile-column + // border 1px solid red + // height 100px + padding calc(content-padding / 2) + +.profile-column-header + font-style bold + margin-bottom 1rem + +.profile-section + margin-bottom 1rem + +.profile-favorite-anime-container + display grid + grid-template-columns repeat(auto-fill, anime-image-small-width) + grid-template-rows repeat(auto-fill, anime-image-small-height) + grid-gap 0.5rem + justify-content space-evenly + +.profile-friends + display grid + grid-template-columns repeat(auto-fill, avatar-size) + grid-template-rows repeat(auto-fill, avatar-size) + grid-gap 0.5rem + margin 0 0.5rem + justify-content space-evenly + +.profile-favorite-anime + // anime-mini-item + +.profile-favorite-anime-image + // anime-mini-item-image + border-radius ui-element-border-radius + +.profile-favorite-characters-container + display grid + grid-template-columns repeat(auto-fill, character-image-small-width) + grid-template-rows repeat(auto-fill, character-image-small-height) + grid-gap 0.5rem + justify-content space-evenly + +// .profile-favorite-character +// margin 0.25rem + +// .profile-favorite-character-image + +// border-radius ui-element-border-radius + > 740px - .profile + .profile-head horizontal align-items stretch @@ -61,6 +112,10 @@ const profile-image-size = 280px padding content-padding margin-top 0 + .profile-columns + display grid + grid-template-columns 27% 46% 27% + .profile-pro-status position absolute right 0 diff --git a/pages/recommended/anime.go b/pages/recommended/anime.go index ae4e7e06..b8785fb3 100644 --- a/pages/recommended/anime.go +++ b/pages/recommended/anime.go @@ -30,7 +30,7 @@ func Anime(ctx *aero.Context) string { completed := animeList.FilterStatus(arn.AnimeListStatusCompleted) // Genre affinity - bestGenres := getBestGenres(animeList) + bestGenres := animeList.TopGenres(bestGenreCount) // Get all anime var tv []*arn.Anime diff --git a/pages/recommended/bestgenres.go b/pages/recommended/bestgenres.go deleted file mode 100644 index e33c6a6e..00000000 --- a/pages/recommended/bestgenres.go +++ /dev/null @@ -1,43 +0,0 @@ -package recommended - -import ( - "sort" - - "github.com/animenotifier/arn" -) - -// getBestGenres returns the most liked genres for the user's anime list. -func getBestGenres(animeList *arn.AnimeList) []string { - genreItems := animeList.Genres() - genreAffinity := map[string]float64{} - bestGenres := []string{} - - for genre, animeListItems := range genreItems { - affinity := 0.0 - - for _, item := range animeListItems { - if item.Status != arn.AnimeListStatusCompleted { - continue - } - - if item.Rating.Overall != 0 { - affinity += item.Rating.Overall - } else { - affinity += 5.0 - } - } - - genreAffinity[genre] = affinity - bestGenres = append(bestGenres, genre) - } - - sort.Slice(bestGenres, func(i, j int) bool { - return genreAffinity[bestGenres[i]] > genreAffinity[bestGenres[j]] - }) - - if len(bestGenres) > bestGenreCount { - bestGenres = bestGenres[:bestGenreCount] - } - - return bestGenres -} diff --git a/pages/thread/reply-ui.go b/pages/thread/reply-ui.go index 7d15a081..986b82a3 100644 --- a/pages/thread/reply-ui.go +++ b/pages/thread/reply-ui.go @@ -19,5 +19,5 @@ func ReplyUI(ctx *aero.Context) string { return ctx.Error(http.StatusNotFound, "Thread not found", err) } - return ctx.HTML(components.NewPostArea(user, "Reply") + components.NewPostActions(thread.Type(), thread.ID, true)) + return ctx.HTML(components.NewPostArea(thread, user, "Reply") + components.NewPostActions(thread, true)) } diff --git a/pages/thread/thread.pixy b/pages/thread/thread.pixy index 6b6ffeb1..dfb5c20d 100644 --- a/pages/thread/thread.pixy +++ b/pages/thread/thread.pixy @@ -11,11 +11,11 @@ component Thread(thread *arn.Thread, user *arn.User) footer.footer.mountable p.text-center This topic is locked. else - NewPostArea(user, "Reply") + NewPostArea(thread, user, "Reply") .buttons if !thread.Locked - NewPostActions("Thread", thread.ID, false) + NewPostActions(thread, false) if user.Role == "admin" || user.Role == "editor" if thread.Locked diff --git a/scripts/Actions/Forum.ts b/scripts/Actions/Forum.ts index 68f80aa3..53be74c2 100644 --- a/scripts/Actions/Forum.ts +++ b/scripts/Actions/Forum.ts @@ -105,7 +105,7 @@ export async function reply(arn: AnimeNotifier, element: HTMLElement) { } // Delete old reply button - let oldPostActions = document.getElementById("new-post-actions") + let oldPostActions = document.getElementsByClassName("new-post-actions")[0] if(oldPostActions) { oldPostActions.remove() diff --git a/scripts/AnimeNotifier.ts b/scripts/AnimeNotifier.ts index 1a2b721d..ca3b4299 100644 --- a/scripts/AnimeNotifier.ts +++ b/scripts/AnimeNotifier.ts @@ -159,6 +159,7 @@ export default class AnimeNotifier { Promise.resolve().then(() => this.lazyLoad()), Promise.resolve().then(() => this.displayLocalDates()), Promise.resolve().then(() => this.setSelectBoxValue()), + Promise.resolve().then(() => this.textAreaFocus()), Promise.resolve().then(() => this.markPlayingSoundTrack()), Promise.resolve().then(() => this.assignActions()), Promise.resolve().then(() => this.updatePushUI()), @@ -194,6 +195,26 @@ export default class AnimeNotifier { } } + textAreaFocus() { + const newPostText = document.getElementById("new-post-text") as HTMLTextAreaElement + + if(!newPostText || newPostText["has-input-listener"]) { + return + } + + newPostText.addEventListener("input", () => { + if(newPostText.value.length > 0) { + const newPostActions = document.getElementsByClassName("new-post-actions")[0] + newPostActions.classList.add("new-post-actions-enabled") + } else { + const newPostActions = document.getElementsByClassName("new-post-actions")[0] + newPostActions.classList.remove("new-post-actions-enabled") + } + }) + + newPostText["has-input-listener"] = true + } + async onIdle() { // Register event listeners document.addEventListener("keydown", this.onKeyDown.bind(this), false) @@ -1071,6 +1092,7 @@ export default class AnimeNotifier { this.lazyLoad(findAllInside("lazy", element)) this.mountMountables(findAllInside("mountable", element)) this.assignTooltipOffsets(findAllInside("tip", element)) + this.textAreaFocus() } scrollTo(target: HTMLElement) { diff --git a/styles/forum.scarlet b/styles/forum.scarlet index ce227e61..0d800e6a 100644 --- a/styles/forum.scarlet +++ b/styles/forum.scarlet @@ -80,10 +80,18 @@ post-content-padding-y = 0.75rem align-items flex-start margin-right 0.5rem -#new-post-actions - horizontal +.new-post-actions justify-content flex-end + opacity 0 + height 0 + transform translateY(-50%) + transition all transition-speed ease + +.new-post-actions-enabled + opacity 1 + height auto margin-bottom 0.75rem + transform translateY(0) // Toolbar diff --git a/utils/animediff/CanonicalTitle.go b/utils/animediff/CanonicalTitle.go index 8c937ede..9042b597 100644 --- a/utils/animediff/CanonicalTitle.go +++ b/utils/animediff/CanonicalTitle.go @@ -7,8 +7,8 @@ type CanonicalTitle struct { NumericHash uint64 } -// Type returns the diff type. -func (diff *CanonicalTitle) Type() string { +// TypeName returns the diff type. +func (diff *CanonicalTitle) TypeName() string { return "CanonicalTitle" } diff --git a/utils/animediff/EndDate.go b/utils/animediff/EndDate.go index 2c657888..8cf653d3 100644 --- a/utils/animediff/EndDate.go +++ b/utils/animediff/EndDate.go @@ -7,8 +7,8 @@ type EndDate struct { NumericHash uint64 } -// Type returns the diff type. -func (diff *EndDate) Type() string { +// TypeName returns the diff type. +func (diff *EndDate) TypeName() string { return "EndDate" } diff --git a/utils/animediff/EpisodeCount.go b/utils/animediff/EpisodeCount.go index 96d130ec..2357891d 100644 --- a/utils/animediff/EpisodeCount.go +++ b/utils/animediff/EpisodeCount.go @@ -9,8 +9,8 @@ type EpisodeCount struct { NumericHash uint64 } -// Type returns the diff type. -func (diff *EpisodeCount) Type() string { +// TypeName returns the diff type. +func (diff *EpisodeCount) TypeName() string { return "EpisodeCount" } diff --git a/utils/animediff/Genres.go b/utils/animediff/Genres.go index 29b79a15..9e4e4f64 100644 --- a/utils/animediff/Genres.go +++ b/utils/animediff/Genres.go @@ -9,8 +9,8 @@ type Genres struct { NumericHash uint64 } -// Type returns the diff type. -func (diff *Genres) Type() string { +// TypeName returns the diff type. +func (diff *Genres) TypeName() string { return "Genres" } diff --git a/utils/animediff/Interface.go b/utils/animediff/Interface.go index 61ee3ac2..a8b246cd 100644 --- a/utils/animediff/Interface.go +++ b/utils/animediff/Interface.go @@ -2,7 +2,7 @@ package animediff // Difference describes a difference between two anime. type Difference interface { - Type() string + TypeName() string Explanation() string DetailsA() string DetailsB() string diff --git a/utils/animediff/JapaneseTitle.go b/utils/animediff/JapaneseTitle.go index cff44bec..09c0fbe3 100644 --- a/utils/animediff/JapaneseTitle.go +++ b/utils/animediff/JapaneseTitle.go @@ -7,8 +7,8 @@ type JapaneseTitle struct { NumericHash uint64 } -// Type returns the diff type. -func (diff *JapaneseTitle) Type() string { +// TypeName returns the diff type. +func (diff *JapaneseTitle) TypeName() string { return "JapaneseTitle" } diff --git a/utils/animediff/RomajiTitle.go b/utils/animediff/RomajiTitle.go index 05b9031a..488322ed 100644 --- a/utils/animediff/RomajiTitle.go +++ b/utils/animediff/RomajiTitle.go @@ -7,8 +7,8 @@ type RomajiTitle struct { NumericHash uint64 } -// Type returns the diff type. -func (diff *RomajiTitle) Type() string { +// TypeName returns the diff type. +func (diff *RomajiTitle) TypeName() string { return "RomajiTitle" } diff --git a/utils/animediff/StartDate.go b/utils/animediff/StartDate.go index f3033dc5..130487f4 100644 --- a/utils/animediff/StartDate.go +++ b/utils/animediff/StartDate.go @@ -7,8 +7,8 @@ type StartDate struct { NumericHash uint64 } -// Type returns the diff type. -func (diff *StartDate) Type() string { +// TypeName returns the diff type. +func (diff *StartDate) TypeName() string { return "StartDate" } diff --git a/utils/animediff/Status.go b/utils/animediff/Status.go index f8f18386..9a8dd962 100644 --- a/utils/animediff/Status.go +++ b/utils/animediff/Status.go @@ -7,8 +7,8 @@ type Status struct { NumericHash uint64 } -// Type returns the diff type. -func (diff *Status) Type() string { +// TypeName returns the diff type. +func (diff *Status) TypeName() string { return "Status" } diff --git a/utils/animediff/Synopsis.go b/utils/animediff/Synopsis.go index fbaf236c..f739c5a1 100644 --- a/utils/animediff/Synopsis.go +++ b/utils/animediff/Synopsis.go @@ -7,8 +7,8 @@ type Synopsis struct { NumericHash uint64 } -// Type returns the diff type. -func (diff *Synopsis) Type() string { +// TypeName returns the diff type. +func (diff *Synopsis) TypeName() string { return "Synopsis" }