mirror of
1
Fork 0

[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
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
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

@ -1,24 +1,24 @@
/* /*
GoToSocial GoToSocial
Copyright (C) 2021-2022 GoToSocial Authors admin@gotosocial.org Copyright (C) 2021-2022 GoToSocial Authors admin@gotosocial.org
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details. GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
/* /*
This stylesheets defines (color) variables to be used by other stylesheets on the page This stylesheets defines (color) variables to be used by other stylesheets on the page
postcss-custom-prop-vars will transpile these to css --variables postcss-custom-prop-vars will transpile these to css --variables
*/ */
$bg: #525c66; $bg: #525c66;

View File

@ -1,21 +1,24 @@
/* /*
GoToSocial GoToSocial
Copyright (C) 2021-2022 GoToSocial Authors admin@gotosocial.org Copyright (C) 2021-2022 GoToSocial Authors admin@gotosocial.org
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details. GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License You should have received a copy of the GNU Affero General Public License
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;
@ -197,16 +200,16 @@ section.error {
flex-direction: row; flex-direction: row;
align-items: center; align-items: center;
span { span {
font-size: 2em; font-size: 2em;
} }
pre { pre {
border: 1px solid #ff000080; border: 1px solid #ff000080;
margin-left: 1em; margin-left: 1em;
padding: 0 0.7em; padding: 0 0.7em;
border-radius: 0.5em; border-radius: 0.5em;
background-color: #ff000010; background-color: #ff000010;
font-size: 1.3em; font-size: 1.3em;
white-space: pre-wrap; white-space: pre-wrap;
} }
} }

View File

@ -1,131 +1,143 @@
/* /*
GoToSocial GoToSocial
Copyright (C) 2021-2022 GoToSocial Authors admin@gotosocial.org Copyright (C) 2021-2022 GoToSocial Authors admin@gotosocial.org
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details. GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
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;
flex-wrap: wrap; grid-template-columns: 1fr;
justify-content: space-around; flex-wrap: wrap;
gap: 0.5rem; justify-content: space-around;
margin-bottom: 0.2rem; gap: 0.5rem;
margin-bottom: 0.2rem;
border-radius: $br;
.basic { box-shadow: $boxshadow;
display: flex;
flex-direction: column;
flex: 1 1 25em;
gap: 0.5rem;
a { .headerimage {
position: relative; height: 100%;
z-index: 1; aspect-ratio: 3 / 1;
color: inherit; overflow: hidden;
text-decoration: none; box-shadow: $boxshadow;
}
.avatar-container { img {
position: relative; width: 100%;
width: 100%; height: 100%;
max-width: 25em; object-fit: cover;
border-radius: $br $br 0 0;
}
}
.avatar { .basic {
position: absolute; margin-top: -7rem;
top: 0; padding: 0 1rem;
left: 0;
bottom: 0;
right: 0;
img { display: grid;
object-fit: cover; grid-template-columns: auto 1fr;
border-radius: 10px; grid-template-rows: 6.5rem auto;
width: 100%;
height: 100%;
}
}
}
.avatar-container:before { .avatar {
content: ""; box-sizing: border-box;
float: left; height: 8.5rem;
padding-top: 100%; 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%;
}
}
.displayname { a {
font-weight: bold; position: relative;
font-size: 1.6rem; z-index: 1;
align-self: start; color: inherit;
} text-decoration: none;
} padding: 0.5rem;
}
.detailed { .displayname {
display: flex; align-self: end;
flex-direction: column; font-weight: bold;
flex: 1 1 25em; font-size: 2rem;
line-height: 2.2rem;
}
h2 { .username {
margin-top: 0; padding-top: 0.25rem;
} color: $acc1;
font-weight: bold;
}
}
.bio { .detailed {
margin: 0; padding: 0 1rem;
display: flex;
flex-direction: column;
flex: 1 1 25em;
a { h2 {
color: $acc1; margin-top: 0;
text-decoration: underline; }
}
} .bio {
} margin: 0;
a {
color: $acc1;
text-decoration: underline;
}
}
}
} }
.accountstats { .accountstats {
position: relative; background: $bg_lighter3;
background: $bg_darker3; display: flex;
padding: 0.5rem; flex-wrap: wrap;
display: flex; justify-content: space-between;
flex-wrap: wrap; padding: 0 1.2rem;
justify-content: space-evenly; border-radius: 0 0 $br $br;
gap: 0.5rem;
margin-bottom: 0.2rem;
.entry { .entry {
background: $bg_lighter3; padding: 1rem 0;
padding: 0.5rem; text-align: center;
flex-grow: 1; }
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

@ -1,19 +1,19 @@
/* /*
GoToSocial GoToSocial
Copyright (C) 2021-2022 GoToSocial Authors admin@gotosocial.org Copyright (C) 2021-2022 GoToSocial Authors admin@gotosocial.org
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details. GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
main { main {
@ -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 class="accountstats">
<div class="entry">Joined <b>{{.account.CreatedAt | timestampShort}}</b></div>
<div class="entry">Followed by <b>{{.account.FollowersCount}}</b></div>
<div class="entry">Following <b>{{.account.FollowingCount}}</b></div>
<div class="entry">Posted <b>{{.account.StatusesCount}}</b></div>
</div>
</div> </div>
<div class="accountstats"> <h2 id="recent">Recent public toots</h2>
<div class="entry">Joined {{.account.CreatedAt | timestampShort}}</div>
<div class="entry">Followed by {{.account.FollowersCount}}</div>
<div class="entry">Following {{.account.FollowingCount}}</div>
<div class="entry">Posted {{.account.StatusesCount}}</div>
</div>
<h2>Recent public posts by @{{.account.Username}}</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">