diff --git a/layout/layout.pixy b/layout/layout.pixy index c28806c3..c4f4b889 100644 --- a/layout/layout.pixy +++ b/layout/layout.pixy @@ -24,6 +24,7 @@ component Content(content string) component Navigation nav#navigation NavigationButton("Dash", "/", "inbox") + NavigationButton("Anime", "/anime", "television") NavigationButton("Forum", "/forum", "comment") NavigationButton("Genres", "/genres", "tags") diff --git a/main.go b/main.go index c0fdb19d..8b2bef4e 100644 --- a/main.go +++ b/main.go @@ -12,7 +12,9 @@ import ( "github.com/animenotifier/notify.moe/pages/forums" "github.com/animenotifier/notify.moe/pages/genre" "github.com/animenotifier/notify.moe/pages/genres" + "github.com/animenotifier/notify.moe/pages/posts" "github.com/animenotifier/notify.moe/pages/profile" + "github.com/animenotifier/notify.moe/pages/search" "github.com/animenotifier/notify.moe/pages/threads" ) @@ -44,12 +46,14 @@ func main() { } app.Ajax("/", dashboard.Get) + app.Ajax("/anime", search.Get) app.Ajax("/anime/:id", anime.Get) app.Ajax("/genres", genres.Get) app.Ajax("/genres/:name", genre.Get) app.Ajax("/forum", forums.Get) app.Ajax("/forum/:tag", forum.Get) app.Ajax("/threads/:id", threads.Get) + app.Ajax("/posts/:id", posts.Get) app.Ajax("/user/:nick", profile.Get) app.Run() diff --git a/mixins/Avatar.pixy b/mixins/Avatar.pixy index 879ff6b0..bfbe8b56 100644 --- a/mixins/Avatar.pixy +++ b/mixins/Avatar.pixy @@ -1,12 +1,18 @@ component Avatar(user *arn.User) a.user.ajax(href="/+" + user.Nick, title=user.Nick) - if user.Avatar != "" - if strings.Contains(user.Avatar, "gravatar.com") - img.user-image(src=user.Avatar + "?s=100&r=x&d=mm", alt=user.Nick) - else - img.user-image(src=user.Avatar, alt=user.Nick) + AvatarNoLink(user) + +component AvatarNoLink(user *arn.User) + if user.Avatar != "" + if strings.Contains(user.Avatar, "gravatar.com") + img.user-image(src=user.Avatar + "?s=100&r=x&d=mm", alt=user.Nick) else - svg.user-image(width="50", height="50") - circle.head(cx="25", cy="19", r="10") - circle.body(cx="25", cy="50", r="20") - //- text(x="25", y="44", text-anchor="middle") TODO \ No newline at end of file + img.user-image(src=user.Avatar, alt=user.Nick) + else + SVGAvatar(50) + +component SVGAvatar(size int) + svg.user-image(width=size, height=size, viewBox="0 0 50 50") + circle.head(cx="25", cy="19", r="10") + circle.body(cx="25", cy="50", r="20") + //- text(x="25", y="44", text-anchor="middle") TODO \ No newline at end of file diff --git a/mixins/Postable.pixy b/mixins/Postable.pixy new file mode 100644 index 00000000..2f8ce6b3 --- /dev/null +++ b/mixins/Postable.pixy @@ -0,0 +1,43 @@ +component Postable(post arn.Postable, viewUser *arn.User, highlightAuthorID string) + .post(data-highlight=post.Author().ID == highlightAuthorID) + .post-author + Avatar(post.Author()) + + //- if post.recipient && post.recipient.ID !== post.author.ID + //- a.user.post-recipient(href="/+" + post.recipient.nick, title=post.recipient.nick) + //- img.user-image(src=post.recipient.avatar ? (post.recipient.avatar + "?s=100&r=x&d=mm") : "/images/elements/no-gravatar.svg", alt=post.recipient.nick) + .post-content + div(id="render-" + post.ID())!= aero.Markdown(post.Text()) + + //- if user && user.ID === post.authorId + //- textarea.post-input.hidden(id="source-" + post.ID)= post.text + //- a.post-save.hidden(id="save-" + post.ID, onclick=`$.saveEdit("${type.toLowerCase()}", "${post.ID}")`) + //- i.fa.fa-save + //- span Save + + .post-toolbar(id="toolbar-" + post.ID()) + .spacer + .post-likes(id="likes-" + post.ID())= len(post.Likes()) + + //- if user != nil + //- if user.ID !== post.authorId + //- - var liked = post.likes && post.likes.indexOf(user.ID) !== -1 + + //- a.post-tool.post-like(id="like-" + post.ID, onclick=`$.like("${type.toLowerCase()}", "${post.ID}")`, title="Like", class=liked ? "hidden" : ") + //- i.fa.fa-thumbs-up.fa-fw + + //- a.post-tool.post-unlike(id="unlike-" + post.ID, onclick=`$.unlike("${type.toLowerCase()}", "${post.ID}")`, title="Unlike", class=!liked ? "hidden" : ") + //- i.fa.fa-thumbs-down.fa-fw + + //- if type === "Posts" || type === "Threads" + //- if user.ID === post.authorId + //- a.post-tool.post-edit(onclick=`$.edit("${post.ID}")`, title="Edit") + //- i.fa.fa-pencil.fa-fw + + //- if post.Type() != "Thread" + a.post-tool.post-permalink.ajax(href=post.Link(), title="Permalink") + Icon("link") + + //- if type === "Messages" && user && (user.ID === post.authorId || user.ID === post.recipientId) + //- a.post-tool.post-delete(onclick=`if(confirm("Do you really want to delete this ${typeSingular.toLowerCase()} from ${post.author.nick}?")) $.delete${typeSingular}("${post.ID}")`, title="Delete") + //- i.fa.fa-trash.fa-fw \ No newline at end of file diff --git a/pages/beta/beta.pixy b/pages/beta/beta.pixy deleted file mode 100644 index b7db83d2..00000000 --- a/pages/beta/beta.pixy +++ /dev/null @@ -1,14 +0,0 @@ -component Beta - section - header - h2 The future - - p Shht! The next version of notify.moe is currently being built here. - hr - ul - li - a.ajax(href="/anime/21499") Sousei no Onmyouji - li - a.ajax(href="/anime/1000001") RWBY - li - a(href="/api/anime/1000001") RWBY (JSON API) \ No newline at end of file diff --git a/pages/dashboard/dashboard.go b/pages/dashboard/dashboard.go index ed739211..479f3b51 100644 --- a/pages/dashboard/dashboard.go +++ b/pages/dashboard/dashboard.go @@ -1,11 +1,28 @@ package dashboard import ( + "sort" + "github.com/aerogo/aero" + "github.com/animenotifier/arn" "github.com/animenotifier/notify.moe/components" ) +const maxPosts = 6 + // Get ... func Get(ctx *aero.Context) string { - return ctx.HTML(components.Dashboard()) + posts, err := arn.GetPosts() + + if err != nil { + return ctx.Error(500, "Error fetching posts") + } + + sort.Sort(sort.Reverse(posts)) + + if len(posts) > maxPosts { + posts = posts[:maxPosts] + } + + return ctx.HTML(components.Dashboard(posts)) } diff --git a/pages/dashboard/dashboard.pixy b/pages/dashboard/dashboard.pixy index 39ae4e24..f71d9a87 100644 --- a/pages/dashboard/dashboard.pixy +++ b/pages/dashboard/dashboard.pixy @@ -1,4 +1,12 @@ -component Dashboard +component Dashboard(posts []*arn.Post) section header - h2 Dash \ No newline at end of file + h2 Dash + + .dashboard-widget + each post in posts + a.dashboard-event.ui.ajax(href=post.Link()) + .dashboard-event-author + AvatarNoLink(post.Author()) + .dashboard-event-text + span= post.Thread().Title \ No newline at end of file diff --git a/pages/dashboard/dashboard.styl b/pages/dashboard/dashboard.styl new file mode 100644 index 00000000..c796827b --- /dev/null +++ b/pages/dashboard/dashboard.styl @@ -0,0 +1,23 @@ +.dashboard-widget + display flex + flex-flow column + align-items center + +.dashboard-event + display flex + flex-flow column wrap + margin-bottom 1rem + padding 0.75rem + width 100% + max-width 700px + +.dashboard-event-author + display flex + justify-content center + width 100% + +.dashboard-event-text + display flex + justify-content center + align-items center + width 100% \ No newline at end of file diff --git a/pages/forum/forum.go b/pages/forum/forum.go index 0d49177a..ed9523e8 100644 --- a/pages/forum/forum.go +++ b/pages/forum/forum.go @@ -21,9 +21,5 @@ func Get(ctx *aero.Context) string { threads = threads[:threadsPerPage] } - for _, thread := range threads { - thread.Init() - } - return ctx.HTML(components.Forum(tag, threads)) } diff --git a/pages/forum/forum.pixy b/pages/forum/forum.pixy index 1989dbc6..422963d8 100644 --- a/pages/forum/forum.pixy +++ b/pages/forum/forum.pixy @@ -8,7 +8,7 @@ component Forum(tag string, threads []*arn.Thread) component ThreadLink(thread *arn.Thread) .thread-link(data-sticky=thread.Sticky) .post-author.thread-author - Avatar(thread.Author) + Avatar(thread.Author()) .thread-content-container .post-content.thread-content if thread.Sticky diff --git a/pages/posts/posts.go b/pages/posts/posts.go new file mode 100644 index 00000000..0195e644 --- /dev/null +++ b/pages/posts/posts.go @@ -0,0 +1,19 @@ +package posts + +import ( + "github.com/aerogo/aero" + "github.com/animenotifier/arn" + "github.com/animenotifier/notify.moe/components" +) + +// Get ... +func Get(ctx *aero.Context) string { + id := ctx.Get("id") + post, err := arn.GetPost(id) + + if err != nil { + return ctx.Error(404, "Post not found") + } + + return ctx.HTML(components.Post(post)) +} diff --git a/pages/posts/posts.pixy b/pages/posts/posts.pixy new file mode 100644 index 00000000..92ac48f4 --- /dev/null +++ b/pages/posts/posts.pixy @@ -0,0 +1,5 @@ +component Post(post *arn.Post) + Postable(post.ToPostable(), nil, "") + + .thread-source + a.ajax(href=post.Thread().Link())= post.Thread().Title \ No newline at end of file diff --git a/pages/posts/posts.styl b/pages/posts/posts.styl new file mode 100644 index 00000000..757dce43 --- /dev/null +++ b/pages/posts/posts.styl @@ -0,0 +1,3 @@ +.thread-source + font-size 0.9rem + text-align right !important \ No newline at end of file diff --git a/pages/search/search.go b/pages/search/search.go new file mode 100644 index 00000000..e42d9746 --- /dev/null +++ b/pages/search/search.go @@ -0,0 +1,30 @@ +package search + +import ( + "github.com/aerogo/aero" + "github.com/animenotifier/arn" + "github.com/animenotifier/notify.moe/components" +) + +// Get ... +func Get(ctx *aero.Context) string { + titleCount := 0 + animeCount := 0 + + // let info: any = await bluebird.props({ + // popular: arn.db.get('Cache', 'popularAnime'), + // stats: arn.db.get('Cache', 'animeStats') + // }) + + // return response.render({ + // user, + // popularAnime: info.popular.anime, + // animeCount: info.stats.animeCount, + // titleCount: info.stats.titleCount, + // anime: null + // }) + + popular, _ := arn.GetPopularCache() + + return ctx.HTML(components.Search(popular.Anime, titleCount, animeCount)) +} diff --git a/pages/search/search.pixy b/pages/search/search.pixy new file mode 100644 index 00000000..d015bb34 --- /dev/null +++ b/pages/search/search.pixy @@ -0,0 +1,16 @@ +component Search(popularAnime []*arn.Anime, titleCount int, animeCount int) + h2 Anime + + #search-container + input#search(type="text", placeholder="Search...", onkeyup="$.searchAnime();", onfocus="this.select();", disabled="disabled", data-count=titleCount, data-anime-count=animeCount) + + #search-results-container + #search-results + + if popularAnime != nil + h3.popular-title Popular + + .popular-anime-list + each anime in popularAnime + a.popular-anime.ajax(href="/anime/" + toString(anime.ID), title=anime.Title.Romaji + " (" + arn.Plural(anime.Watching, "user") + " watching)") + img.anime-image.popular-anime-image(src=anime.Image, alt=anime.Title.Romaji) \ No newline at end of file diff --git a/pages/search/search.styl b/pages/search/search.styl new file mode 100644 index 00000000..834626b9 --- /dev/null +++ b/pages/search/search.styl @@ -0,0 +1,2 @@ +.popular-title + text-align center \ No newline at end of file diff --git a/pages/threads/threads.go b/pages/threads/threads.go index 8cd83f89..f62eeb0e 100644 --- a/pages/threads/threads.go +++ b/pages/threads/threads.go @@ -17,8 +17,6 @@ func Get(ctx *aero.Context) string { return ctx.Error(404, "Thread not found") } - thread.Author, _ = arn.GetUser(thread.AuthorID) - replies, filterErr := arn.FilterPosts(func(post *arn.Post) bool { return post.ThreadID == thread.ID }) diff --git a/pages/threads/threads.pixy b/pages/threads/threads.pixy index 7b8c3a6c..dc015422 100644 --- a/pages/threads/threads.pixy +++ b/pages/threads/threads.pixy @@ -3,51 +3,7 @@ component Thread(thread *arn.Thread, posts []*arn.Post) h2.thread-title= thread.Title .posts - Post(thread.ToPostable(), nil, "Threads", "Thread", thread.Author.ID) + Postable(thread.ToPostable(), nil, thread.Author().ID) each post in posts - Post(post.ToPostable(), nil, "Posts", "Post", thread.Author.ID) - -component Post(post arn.Postable, viewUser *arn.User, postType string, postTypeSingular string, highlightAuthorID string) - .post(data-highlight=post.Author().ID == highlightAuthorID) - .post-author - Avatar(post.Author()) - - //- if post.recipient && post.recipient.ID !== post.author.ID - //- a.user.post-recipient(href="/+" + post.recipient.nick, title=post.recipient.nick) - //- img.user-image(src=post.recipient.avatar ? (post.recipient.avatar + "?s=100&r=x&d=mm") : "/images/elements/no-gravatar.svg", alt=post.recipient.nick) - .post-content - div(id="render-" + post.ID())!= aero.Markdown(post.Text()) - - //- if user && user.ID === post.authorId - //- textarea.post-input.hidden(id="source-" + post.ID)= post.text - //- a.post-save.hidden(id="save-" + post.ID, onclick=`$.saveEdit("${type.toLowerCase()}", "${post.ID}")`) - //- i.fa.fa-save - //- span Save - - .post-toolbar(id="toolbar-" + post.ID()) - .spacer - .post-likes(id="likes-" + post.ID())= len(post.Likes()) - - //- if user != nil - //- if user.ID !== post.authorId - //- - var liked = post.likes && post.likes.indexOf(user.ID) !== -1 - - //- a.post-tool.post-like(id="like-" + post.ID, onclick=`$.like("${type.toLowerCase()}", "${post.ID}")`, title="Like", class=liked ? "hidden" : ") - //- i.fa.fa-thumbs-up.fa-fw - - //- a.post-tool.post-unlike(id="unlike-" + post.ID, onclick=`$.unlike("${type.toLowerCase()}", "${post.ID}")`, title="Unlike", class=!liked ? "hidden" : ") - //- i.fa.fa-thumbs-down.fa-fw - - //- if type === "Posts" || type === "Threads" - //- if user.ID === post.authorId - //- a.post-tool.post-edit(onclick=`$.edit("${post.ID}")`, title="Edit") - //- i.fa.fa-pencil.fa-fw - - //- if type !== "Threads" - //- a.post-tool.post-permalink.ajax(href="/" + type.toLowerCase() + "/" + post.ID, title="Permalink") - //- i.fa.fa-link.fa-fw - - //- if type === "Messages" && user && (user.ID === post.authorId || user.ID === post.recipientId) - //- a.post-tool.post-delete(onclick=`if(confirm("Do you really want to delete this ${typeSingular.toLowerCase()} from ${post.author.nick}?")) $.delete${typeSingular}("${post.ID}")`, title="Delete") - //- i.fa.fa-trash.fa-fw \ No newline at end of file + Postable(post.ToPostable(), nil, thread.Author().ID) \ No newline at end of file