From 2dd9dd52a2cafc5240a15e773e2785d8800e2abe Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Tue, 15 May 2018 14:14:37 +0100 Subject: [PATCH] Implements simple stats in profile view. --- forum.nim | 10 +++--- redesign/forum.nim | 12 +++++-- redesign/nimforum.scss | 52 ++++++++++++++++++++++++++++++- redesign/profile.nim | 71 ++++++++++++++++++++++++++++++++++++++++-- 4 files changed, 135 insertions(+), 10 deletions(-) diff --git a/forum.nim b/forum.nim index 716f060..49c85bb 100644 --- a/forum.nim +++ b/forum.nim @@ -1015,10 +1015,10 @@ template createTFD() = #[ DB functions. TODO: Move to another module? ]# -proc selectUser(userRow: seq[string]): threadlist.User = +proc selectUser(userRow: seq[string], avatarSize: int=80): threadlist.User = return threadlist.User( name: userRow[0], - avatarUrl: userRow[1].getGravatarUrl(), + avatarUrl: userRow[1].getGravatarUrl(avatarSize), lastOnline: userRow[2].parseInt, rank: parseEnum[Rank](userRow[3]) ) @@ -1216,7 +1216,8 @@ routes: let postsQuery = sql(""" select p.id, p.content, strftime('%s', p.creation), p.author, - u.name, u.email, strftime('%s', u.lastOnline), u.status + u.name, u.email, strftime('%s', u.lastOnline), u.status, + strftime('%s', u.creation) from post p, person u where u.id = p.author and u.name = ? order by p.id desc; @@ -1230,7 +1231,8 @@ routes: let rows = db.getAllRows(postsQuery, username) profile.user = selectUser(@[ rows[0][4], rows[0][5], rows[0][6], rows[0][7] - ]) + ], avatarSize=200) + profile.joinTime = rows[0][8].parseInt() if c.rank >= Admin: profile.email = some(rows[0][5]) diff --git a/redesign/forum.nim b/redesign/forum.nim index 686fc2a..9de7c75 100644 --- a/redesign/forum.nim +++ b/redesign/forum.nim @@ -4,16 +4,18 @@ from dom import window, Location include karax/prelude import jester/patterns -import threadlist, postlist, header +import threadlist, postlist, header, profile import karaxutils type State = ref object url: Location + profile: ProfileState proc newState(): State = State( - url: window.location + url: window.location, + profile: newProfileState() ) var state = newState() @@ -44,7 +46,11 @@ proc render(): VNode = result = buildHtml(tdiv()): renderHeader() route([ - r("/t/@id?", + r("/profile/@username", + (params: Params) => + (render(state.profile, params["username"])) + ), + r("/t/@id", (params: Params) => (renderPostList(params["id"].parseInt(), isLoggedIn())) ), diff --git a/redesign/nimforum.scss b/redesign/nimforum.scss index 84ee7f9..dcab208 100644 --- a/redesign/nimforum.scss +++ b/redesign/nimforum.scss @@ -449,4 +449,54 @@ hr { border: 0; } -@import "syntax.scss"; \ No newline at end of file +@import "syntax.scss"; + +// - Profile view + +.profile { + @extend .tile; + margin-top: $control-padding-y*5; +} + +.profile-icon { + @extend .tile-icon; +} + +.profile-avatar { + @extend .avatar; + @extend .avatar-xl; + + height: 8.2rem; + width: 8.2rem; +} + +.profile-content { + @extend .tile-content; + padding: $control-padding-x $control-padding-y; +} + +.profile-title { + @extend .tile-title; +} + +.profile-stats { + dl { + border-top: 1px solid $border-color; + border-bottom: 1px solid $border-color; + } + + dt { + font-weight: normal; + color: lighten($dark-color, 15%); + } + + dt, dd { + display: inline-block; + margin: 0; + margin-right: $control-padding-x; + } + + dd { + margin-right: $control-padding-x-lg; + } +} \ No newline at end of file diff --git a/redesign/profile.nim b/redesign/profile.nim index b2fc8c7..67cffee 100644 --- a/redesign/profile.nim +++ b/redesign/profile.nim @@ -1,5 +1,6 @@ -import options -import threadlist, post +import options, httpcore, json, sugar + +import threadlist, post, category, error type Profile* = object user*: User @@ -9,3 +10,69 @@ type # Information that only admins should see. email*: Option[string] +when defined(js): + include karax/prelude + import karax/[kajax] + import karaxutils + + type + ProfileState* = ref object + profile: Option[Profile] + loading: bool + status: HttpCode + + proc newProfileState*(): ProfileState = + ProfileState( + loading: false, + status: Http200 + ) + + proc onProfile(httpStatus: int, response: kstring, state: ProfileState) = + # TODO: Try to abstract these. + state.loading = false + state.status = httpStatus.HttpCode + if state.status != Http200: return + + let parsed = parseJson($response) + let profile = to(parsed, Profile) + + state.profile = some(profile) + + proc render*(state: ProfileState, username: string): VNode = + if state.status != Http200: + return renderError("Couldn't retrieve profile.") + + if state.profile.isNone: + let uri = makeUri("profile.json", ("username", username)) + ajaxGet(uri, @[], (s: int, r: kstring) => onProfile(s, r, state)) + + return buildHtml(tdiv(class="loading loading-lg")) + + let profile = state.profile.get() + result = buildHtml(): + section(class="container grid-xl"): + tdiv(class="profile"): + tdiv(class="profile-icon"): + render(profile.user, "profile-avatar") + tdiv(class="profile-content"): + h2(class="profile-title"): + text profile.user.name + + tdiv(class="profile-stats"): + dl(): + dt(text "Joined") + dd(text threadlist.renderActivity(profile.joinTime)) + dt(text "Last Post") + dd(text renderActivity(profile.posts[0].info.creation)) + dt(text "Last Online") + dd(text renderActivity(profile.user.lastOnline)) + dt(text "Rank") + dd(text $profile.user.rank) + + tdiv(class="columns"): + tdiv(class="column col-6"): + h4(text "Latest Posts") + tdiv(class="column col-6"): + h4(text "Latest Threads") + +