[frontend] Profile pages upgrade (#640)

* fix css indentation

* profile styling update

* update status styling to match profile

* empty header fix

* generate random avatars for thread views

* appease the linter gods

* upgrade deps

* turn profile accent into border + $bg background

* upgrade deps

* small accessibility tweaks

Co-authored-by: tobi <31960611+tsmethurst@users.noreply.github.com>
This commit is contained in:
f0x52
2022-06-21 10:48:42 +02:00
committed by GitHub
parent 8c7945fb78
commit 7c6c0cd547
9 changed files with 1355 additions and 1301 deletions

View File

@@ -23,6 +23,7 @@ import (
"encoding/json" "encoding/json"
"errors" "errors"
"fmt" "fmt"
"math/rand"
"net/http" "net/http"
"strings" "strings"
@@ -35,6 +36,21 @@ import (
"github.com/superseriousbusiness/gotosocial/internal/oauth" "github.com/superseriousbusiness/gotosocial/internal/oauth"
) )
var randAvatars = make(map[string]string)
func (m *Module) ensureAvatar(status apimodel.Status) {
if status.Account.Avatar == "" && len(m.defaultAvatars) > 0 {
avatar, ok := randAvatars[status.Account.ID]
if !ok {
//nolint:gosec
randomIndex := rand.Intn(len(m.defaultAvatars))
avatar = m.defaultAvatars[randomIndex]
randAvatars[status.Account.ID] = avatar
}
status.Account.Avatar = avatar
}
}
func (m *Module) threadGETHandler(c *gin.Context) { func (m *Module) threadGETHandler(c *gin.Context) {
ctx := c.Request.Context() ctx := c.Request.Context()
@@ -104,6 +120,16 @@ func (m *Module) threadGETHandler(c *gin.Context) {
return return
} }
m.ensureAvatar(*status)
for _, status := range context.Descendants {
m.ensureAvatar(status)
}
for _, status := range context.Ancestors {
m.ensureAvatar(status)
}
c.HTML(http.StatusOK, "thread.tmpl", gin.H{ c.HTML(http.StatusOK, "thread.tmpl", gin.H{
"instance": instance, "instance": instance,
"status": status, "status": status,

View File

@@ -16,6 +16,9 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
$br: 0.4rem;
$boxshadow: 0 0.4rem 1rem -0.2rem rgba(0,0,0,0.2);
html, body { html, body {
padding: 0; padding: 0;
margin: 0; margin: 0;

View File

@@ -18,76 +18,89 @@
main { main {
background: transparent; background: transparent;
} padding-top: 0;
.headerimage {
img {
width: 100%;
height: 15em;
object-fit: cover;
border-radius: 10px;
}
} }
.profile { .profile {
position: relative; position: relative;
background: $bg_darker3; background: $bg_darker3;
padding: 2rem; display: grid;
display: flex; grid-template-rows: minmax(6rem, 20%) auto auto;
grid-template-columns: 1fr;
flex-wrap: wrap; flex-wrap: wrap;
justify-content: space-around; justify-content: space-around;
gap: 0.5rem; gap: 0.5rem;
margin-bottom: 0.2rem; margin-bottom: 0.2rem;
border-radius: $br;
box-shadow: $boxshadow;
.headerimage {
height: 100%;
aspect-ratio: 3 / 1;
overflow: hidden;
box-shadow: $boxshadow;
img {
width: 100%;
height: 100%;
object-fit: cover;
border-radius: $br $br 0 0;
}
}
.basic { .basic {
display: flex; margin-top: -7rem;
flex-direction: column; padding: 0 1rem;
flex: 1 1 25em;
gap: 0.5rem; display: grid;
grid-template-columns: auto 1fr;
grid-template-rows: 6.5rem auto;
.avatar {
box-sizing: border-box;
height: 8.5rem;
width: 8.5rem;
grid-row: 1 / span 2;
background: $bg;
border: 0.2rem solid $acc2;
padding: 0;
border-radius: $br;
position: relative;
box-shadow: $boxshadow;
img {
object-fit: cover;
border-radius: $br;
width: 100%;
height: 100%;
}
}
a { a {
position: relative; position: relative;
z-index: 1; z-index: 1;
color: inherit; color: inherit;
text-decoration: none; text-decoration: none;
padding: 0.5rem;
} }
.avatar-container {
position: relative;
width: 100%;
max-width: 25em;
.avatar {
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
img {
object-fit: cover;
border-radius: 10px;
width: 100%;
height: 100%;
}
}
}
.avatar-container:before {
content: "";
float: left;
padding-top: 100%;
}
.displayname { .displayname {
align-self: end;
font-weight: bold;
font-size: 2rem;
line-height: 2.2rem;
}
.username {
padding-top: 0.25rem;
color: $acc1;
font-weight: bold; font-weight: bold;
font-size: 1.6rem;
align-self: start;
} }
} }
.detailed { .detailed {
padding: 0 1rem;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
flex: 1 1 25em; flex: 1 1 25em;
@@ -108,24 +121,23 @@ main {
} }
.accountstats { .accountstats {
position: relative; background: $bg_lighter3;
background: $bg_darker3;
padding: 0.5rem;
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
justify-content: space-evenly; justify-content: space-between;
gap: 0.5rem; padding: 0 1.2rem;
margin-bottom: 0.2rem; border-radius: 0 0 $br $br;
.entry { .entry {
background: $bg_lighter3; padding: 1rem 0;
padding: 0.5rem;
flex-grow: 1;
text-align: center; text-align: center;
} }
} }
footer + div { .toot, .toot:last-child {
/* something weird from the devstack.. */ box-shadow: $boxshadow;
display: none; }
#recent {
margin-left: 1rem;
} }

View File

@@ -24,17 +24,20 @@ main {
.thread { .thread {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
border-radius: $br;
background: $bg_darker5;
box-shadow: $boxshadow;
} }
.toot { .toot {
position: relative; position: relative;
background: $bg_darker3; background: $bg_darker3;
padding: 2rem; padding: 1.5rem;
/* padding-bottom: 0; */
display: grid; display: grid;
grid-template-columns: 3.2rem auto 1fr; grid-template-columns: 4rem auto 1fr;
column-gap: 0.5rem; column-gap: 0.5rem;
margin-bottom: 0.2rem; margin-bottom: $br;
border-radius: $br;
a { a {
position: relative; position: relative;
@@ -45,11 +48,16 @@ main {
.avatar { .avatar {
grid-row: span 2; grid-row: span 2;
aspect-ratio: 1/1;
img { img {
height: 3.2rem; height: 100%;
width: 3.2rem; width: 100%;
object-fit: cover; object-fit: cover;
background: $bg;
border: 0.1rem solid $acc2;
/* box-sizing: border-box; */
border-radius: calc($br / 1.5);
} }
} }
@@ -78,6 +86,9 @@ main {
z-index: 2; z-index: 2;
cursor: pointer; cursor: pointer;
} }
label:hover {
background: $acc2;
}
} }
.text { .text {
@@ -203,16 +214,16 @@ main {
z-index: 0; z-index: 0;
} }
$border-radius: 0.3rem;
&:first-child { &:first-child {
/* top left, top right */ /* top left, top right */
border-radius: $border-radius $border-radius 0 0; border-radius: $br $br 0 0;
} }
&:last-child { &:last-child {
/* bottom left, bottom right */ /* bottom left, bottom right */
border-radius: 0 0 $border-radius $border-radius; border-radius: 0 0 $br $br;
padding-bottom: 1.5rem; padding-bottom: 1.5rem;
margin-bottom: 0;
} }
&.expanded { &.expanded {

File diff suppressed because it is too large Load Diff

View File

@@ -18,7 +18,7 @@
</head> </head>
<body> <body>
<div class="page"> <div class="page">
<a href="/" class="nounderline"> <a aria-label="instance homepage" href="/" class="nounderline header">
<header> <header>
<img src="/assets/logo.png" alt="Instance Logo"/> <img src="/assets/logo.png" alt="Instance Logo"/>
<div> <div>

View File

@@ -1,28 +1,32 @@
{{ template "header.tmpl" .}} {{ template "header.tmpl" .}}
<main> <main>
{{ if .account.Header }}<a href="{{.account.Header}}" class="headerimage"><img src="{{.account.Header}}"></a>{{ end }}
<div class="profile"> <div class="profile">
<div class="headerimage">
{{ if .account.Header }}
<img
src="{{.account.Header}}"
alt="{{if .account.DisplayName}}{{.account.DisplayName}}{{else}}{{.account.Username}}{{end}}'s header"
/>
{{ end }}
</div>
<div class="basic"> <div class="basic">
<a href="{{.account.Avatar}}" class="avatar"><img src="{{.account.Avatar}}" alt="{{if .account.DisplayName}}{{.account.DisplayName}}{{else}}{{.account.Username}}{{end}}'s avatar"></a>
<a href="{{.account.URL}}" class="displayname">{{if .account.DisplayName}}{{.account.DisplayName}}{{else}}{{.account.Username}}{{end}}</a> <a href="{{.account.URL}}" class="displayname">{{if .account.DisplayName}}{{.account.DisplayName}}{{else}}{{.account.Username}}{{end}}</a>
<a href="{{.account.URL}}" class="username">@{{.account.Username}}</a> <a href="{{.account.URL}}" class="username">@{{.account.Username}}</a>
<div class="avatar-container">
<a href="{{.account.Avatar}}" class="avatar"><img src="{{.account.Avatar}}"></a>
</div>
</div> </div>
<div class="detailed"> <div class="detailed">
<h2>About @{{.account.Username}}</h2>
<div class="bio"> <div class="bio">
{{ if .account.Note }}{{ .account.Note | noescape }}{{else}}This GoToSocial user hasn't written a bio yet!{{end}} {{ if .account.Note }}{{ .account.Note | noescape }}{{else}}This GoToSocial user hasn't written a bio yet!{{end}}
</div> </div>
</div> </div>
</div>
<div class="accountstats"> <div class="accountstats">
<div class="entry">Joined {{.account.CreatedAt | timestampShort}}</div> <div class="entry">Joined <b>{{.account.CreatedAt | timestampShort}}</b></div>
<div class="entry">Followed by {{.account.FollowersCount}}</div> <div class="entry">Followed by <b>{{.account.FollowersCount}}</b></div>
<div class="entry">Following {{.account.FollowingCount}}</div> <div class="entry">Following <b>{{.account.FollowingCount}}</b></div>
<div class="entry">Posted {{.account.StatusesCount}}</div> <div class="entry">Posted <b>{{.account.StatusesCount}}</b></div>
</div> </div>
<h2>Recent public posts by @{{.account.Username}}</h2> </div>
<h2 id="recent">Recent public toots</h2>
<div class="thread"> <div class="thread">
{{range .statuses}} {{range .statuses}}
<div class="toot expanded"> <div class="toot expanded">

View File

@@ -1,4 +1,4 @@
<a href="{{.Account.URL}}" class="avatar"><img src="{{.Account.Avatar}}"></a> <a href="{{.Account.URL}}" class="avatar"><img src="{{.Account.Avatar}}" alt=""></a>
<a href="{{.Account.URL}}" class="displayname">{{if .Account.DisplayName}}{{.Account.DisplayName}}{{else}}{{.Account.Username}}{{end}}</a> <a href="{{.Account.URL}}" class="displayname">{{if .Account.DisplayName}}{{.Account.DisplayName}}{{else}}{{.Account.Username}}{{end}}</a>
<a href="{{.Account.URL}}" class="username">@{{.Account.Username}}</a> <a href="{{.Account.URL}}" class="username">@{{.Account.Username}}</a>
<div class="text"> <div class="text">