* [feature] Allow user to choose "gallery" style web layout * find a bug and squish it up and all day long you'll have good luck * just a sec * [performance] reindex public timeline + tinker with query a bit * fiddling * should be good now * last bit of finagling, i'm done now i prommy * panic normallypull/3945/head
|
After Width: | Height: | Size: 947 KiB |
|
After Width: | Height: | Size: 793 KiB |
@ -0,0 +1,85 @@
|
||||
// GoToSocial
|
||||
// Copyright (C) GoToSocial Authors admin@gotosocial.org
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
//
|
||||
// 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
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// 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/>.
|
||||
|
||||
package migrations |
||||
|
||||
import ( |
||||
"context" |
||||
|
||||
"github.com/superseriousbusiness/gotosocial/internal/log" |
||||
"github.com/uptrace/bun" |
||||
) |
||||
|
||||
func init() { |
||||
up := func(ctx context.Context, db *bun.DB) error { |
||||
return db.RunInTx(ctx, nil, func(ctx context.Context, tx bun.Tx) error { |
||||
|
||||
// Add new column to settings.
|
||||
if _, err := tx. |
||||
NewAddColumn(). |
||||
Table("account_settings"). |
||||
ColumnExpr( |
||||
"? SMALLINT NOT NULL DEFAULT ?", |
||||
bun.Ident("web_layout"), 1, |
||||
). |
||||
Exec(ctx); err != nil { |
||||
return err |
||||
} |
||||
|
||||
// Drop existing statuses web index as it's out of date.
|
||||
log.Info(ctx, "updating statuses_profile_web_view_idx, this may take a while, please wait!") |
||||
if _, err := tx. |
||||
NewDropIndex(). |
||||
Index("statuses_profile_web_view_idx"). |
||||
IfExists(). |
||||
Exec(ctx); err != nil { |
||||
return err |
||||
} |
||||
|
||||
// Note: "attachments" field is not included in
|
||||
// the index below as SQLite is fussy about using it,
|
||||
// and it prevents this index from being used
|
||||
// properly in non media-only queries.
|
||||
if _, err := tx. |
||||
NewCreateIndex(). |
||||
Table("statuses"). |
||||
Index("statuses_profile_web_view_idx"). |
||||
Column( |
||||
"account_id", |
||||
"visibility", |
||||
"in_reply_to_uri", |
||||
"boost_of_id", |
||||
"federated", |
||||
). |
||||
ColumnExpr("? DESC", bun.Ident("id")). |
||||
IfNotExists(). |
||||
Exec(ctx); err != nil { |
||||
return err |
||||
} |
||||
|
||||
return nil |
||||
}) |
||||
} |
||||
|
||||
down := func(ctx context.Context, db *bun.DB) error { |
||||
return nil |
||||
} |
||||
|
||||
if err := Migrations.Register(up, down); err != nil { |
||||
panic(err) |
||||
} |
||||
} |
||||
|
After Width: | Height: | Size: 324 B |
|
After Width: | Height: | Size: 42 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 636 B |
|
After Width: | Height: | Size: 406 B |
|
After Width: | Height: | Size: 1.8 MiB |
|
After Width: | Height: | Size: 9.8 KiB |
|
After Width: | Height: | Size: 761 KiB |
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 284 KiB |
|
After Width: | Height: | Size: 24 KiB |
|
After Width: | Height: | Size: 396 KiB |
|
After Width: | Height: | Size: 26 KiB |
|
After Width: | Height: | Size: 134 KiB |
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 372 KiB |
|
After Width: | Height: | Size: 51 KiB |
|
After Width: | Height: | Size: 104 KiB |
|
After Width: | Height: | Size: 27 KiB |
|
After Width: | Height: | Size: 501 KiB |
|
After Width: | Height: | Size: 23 KiB |
|
After Width: | Height: | Size: 358 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 79 KiB |
|
After Width: | Height: | Size: 5.2 KiB |
@ -0,0 +1,207 @@
|
||||
/* |
||||
GoToSocial |
||||
Copyright (C) GoToSocial Authors admin@gotosocial.org |
||||
SPDX-License-Identifier: AGPL-3.0-or-later |
||||
|
||||
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 |
||||
the Free Software Foundation, either version 3 of the License, or |
||||
(at your option) any later version. |
||||
|
||||
This program is distributed in the hope that it will be useful, |
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
GNU Affero General Public License for more details. |
||||
|
||||
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/>. |
||||
*/ |
||||
|
||||
@import "photoswipe/dist/photoswipe.css"; |
||||
@import "photoswipe-dynamic-caption-plugin/photoswipe-dynamic-caption-plugin.css"; |
||||
@import "plyr/dist/plyr.css"; |
||||
|
||||
.media-wrapper { |
||||
height: 100%; |
||||
width: 100%; |
||||
box-sizing: border-box; |
||||
border: 0.15rem solid $gray1; |
||||
border-radius: $br; |
||||
position: relative; |
||||
overflow: hidden; |
||||
z-index: 2; |
||||
|
||||
img { |
||||
width: 100%; |
||||
height: 100%; |
||||
object-fit: cover; |
||||
} |
||||
|
||||
details { |
||||
position: absolute; |
||||
height: 100%; |
||||
width: 100%; |
||||
|
||||
&[open] summary { |
||||
height: auto; |
||||
width: auto; |
||||
margin: 1rem; |
||||
padding: 0; |
||||
|
||||
.show, video, img { |
||||
display: none; |
||||
} |
||||
|
||||
.eye.button .hide { |
||||
display: inline-block; |
||||
grid-column: 1 / span 3; |
||||
grid-row: 1 / span 2; |
||||
} |
||||
} |
||||
|
||||
summary { |
||||
position: absolute; |
||||
height: 100%; |
||||
width: 100%; |
||||
z-index: 3; |
||||
overflow: hidden; |
||||
|
||||
display: grid; |
||||
padding: 1rem; |
||||
grid-template-columns: 1fr auto 1fr; |
||||
grid-template-rows: 1fr 1fr; |
||||
grid-template-areas: |
||||
"eye sensitive ." |
||||
". sensitive ."; |
||||
|
||||
&::-webkit-details-marker { |
||||
display: none; /* Safari */ |
||||
} |
||||
|
||||
.eye.button { |
||||
grid-area: eye; |
||||
align-self: start; |
||||
justify-self: start; |
||||
margin: 0; |
||||
padding: 0.4rem; |
||||
|
||||
.fa-fw { |
||||
line-height: $fa-fw; |
||||
} |
||||
|
||||
.hide { |
||||
display: none; |
||||
} |
||||
} |
||||
|
||||
.show.sensitive { |
||||
grid-area: sensitive; |
||||
align-self: center; |
||||
|
||||
text-overflow: ellipsis; |
||||
overflow: hidden; |
||||
white-space: nowrap; |
||||
|
||||
.button { |
||||
cursor: pointer; |
||||
align-self: center; |
||||
} |
||||
} |
||||
|
||||
video, img { |
||||
z-index: -1; |
||||
position: absolute; |
||||
height: calc(100% + 1.2rem); |
||||
width: calc(100% + 1.2rem); |
||||
top: -0.6rem; |
||||
left: -0.6rem; |
||||
filter: blur(1.2rem); |
||||
} |
||||
} |
||||
|
||||
video.plyr-video, .plyr { |
||||
position: absolute; |
||||
height: 100%; |
||||
width: 100%; |
||||
object-fit: contain; |
||||
background: $gray1; |
||||
} |
||||
|
||||
.unknown-attachment { |
||||
.placeholder { |
||||
width: 100%; |
||||
height: 100%; |
||||
padding: 0.8rem; |
||||
border: 0.2rem dashed $white2; |
||||
|
||||
display: flex; |
||||
flex-direction: column; |
||||
align-items: center; |
||||
gap: 0.25rem; |
||||
|
||||
color: $white2; |
||||
|
||||
.placeholder-external-link { |
||||
align-self: end; |
||||
font-size: 2.5rem; |
||||
} |
||||
|
||||
.placeholder-icon { |
||||
width: 100%; |
||||
font-size: 3.5rem; |
||||
text-align: center; |
||||
margin-top: auto; |
||||
} |
||||
|
||||
.placeholder-link-to { |
||||
width: 100%; |
||||
text-align: center; |
||||
margin-bottom: auto; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
.pswp__button--open-post-link { |
||||
display: flex; |
||||
align-items: center; |
||||
justify-content: center; |
||||
|
||||
span > i { |
||||
background: $status-bg; |
||||
color: $fg; |
||||
border-radius: 25%; |
||||
} |
||||
} |
||||
|
||||
.plyr--video { |
||||
flex-direction: column-reverse; |
||||
|
||||
.plyr__video-wrapper { |
||||
position: relative; |
||||
} |
||||
|
||||
.plyr__controls { |
||||
align-self: stretch; |
||||
position: initial; |
||||
padding: 0.1rem; |
||||
padding-top: 0.2rem; |
||||
} |
||||
|
||||
.plyr__control { |
||||
box-shadow: none; |
||||
} |
||||
|
||||
.plyr__control--overlaid { |
||||
top: calc(50% - 18px); |
||||
} |
||||
} |
||||
|
||||
.pswp__content { |
||||
padding: 2rem; |
||||
|
||||
.plyr { |
||||
max-height: 100%; |
||||
} |
||||
} |
||||
@ -0,0 +1,343 @@
|
||||
/* |
||||
GoToSocial |
||||
Copyright (C) GoToSocial Authors admin@gotosocial.org |
||||
SPDX-License-Identifier: AGPL-3.0-or-later |
||||
|
||||
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 |
||||
the Free Software Foundation, either version 3 of the License, or |
||||
(at your option) any later version. |
||||
|
||||
This program is distributed in the hope that it will be useful, |
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
GNU Affero General Public License for more details. |
||||
|
||||
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/>. |
||||
*/ |
||||
|
||||
.profile .profile-header { |
||||
background: $profile-bg; |
||||
border-radius: $br; |
||||
overflow: hidden; |
||||
margin-bottom: 1rem; |
||||
|
||||
.moved-to { |
||||
padding: 1rem; |
||||
text-align: center; |
||||
} |
||||
|
||||
.header-image-wrapper { |
||||
position: relative; |
||||
padding-top: 33.33%; /* aspect-ratio 1/3 */ |
||||
|
||||
img { |
||||
position: absolute; |
||||
top: 0; |
||||
left: 0; |
||||
right: 0; |
||||
width: 100%; |
||||
height: 100%; |
||||
object-fit: cover; |
||||
} |
||||
} |
||||
|
||||
/* |
||||
Basic info container has the user's avatar, display- and username, and role |
||||
It's partially overlapped over the header image, by a negative margin-top. |
||||
*/ |
||||
$avatar-size: 8.5rem; |
||||
$name-size: 3rem; |
||||
$username-size: 2rem; |
||||
$overlap: calc($avatar-size - $name-size - $username-size); |
||||
|
||||
.basic-info { |
||||
position: relative; |
||||
display: grid; |
||||
box-sizing: border-box; |
||||
grid-template-columns: $avatar-size auto 1fr; |
||||
grid-template-rows: $overlap $name-size auto; |
||||
grid-template-areas: |
||||
"avatar . ." |
||||
"avatar namerole namerole" |
||||
"avatar namerole namerole"; |
||||
|
||||
margin: 1rem; |
||||
margin-top: calc(-1 * $overlap); |
||||
gap: 0 1rem; |
||||
|
||||
.avatar-image-wrapper { |
||||
grid-area: avatar; |
||||
|
||||
border: 0.2rem solid $avatar-border; |
||||
border-radius: $br; |
||||
|
||||
/* |
||||
Wrapper always same |
||||
size + proportions no |
||||
matter image inside. |
||||
*/ |
||||
height: $avatar-size; |
||||
width: $avatar-size; |
||||
|
||||
.avatar { |
||||
/* |
||||
Fit 100% of the wrapper. |
||||
*/ |
||||
height: 100%; |
||||
width: 100%; |
||||
|
||||
/* |
||||
Normalize non-square images. |
||||
*/ |
||||
object-fit: cover; |
||||
|
||||
/* |
||||
Prevent image extending |
||||
beyond rounded borders. |
||||
*/ |
||||
border-radius: $br-inner; |
||||
} |
||||
} |
||||
|
||||
.namerole { |
||||
grid-area: namerole; |
||||
|
||||
display: grid; |
||||
gap: 0 1rem; |
||||
box-sizing: border-box; |
||||
grid-template-columns: 1fr auto; |
||||
grid-template-rows: $name-size auto; |
||||
grid-template-areas: |
||||
"displayname displayname" |
||||
"username role"; |
||||
|
||||
.displayname { |
||||
grid-area: displayname; |
||||
line-height: $name-size; |
||||
font-size: 1.5rem; |
||||
font-weight: bold; |
||||
} |
||||
|
||||
.bot-username-wrapper { |
||||
display: flex; |
||||
gap: 0.5rem; |
||||
grid-area: username; |
||||
align-items: center; |
||||
|
||||
.bot-legend-wrapper { |
||||
display: flex; |
||||
gap: 0.25rem; |
||||
align-items: center; |
||||
|
||||
background: $bg; |
||||
color: $fg; |
||||
|
||||
border-radius: $br; |
||||
padding: 0.1rem 0.4rem 0.2rem 0.4rem; |
||||
|
||||
font-variant: small-caps; |
||||
font-weight: bold; |
||||
|
||||
cursor: default; |
||||
|
||||
.bot-icon { |
||||
/* |
||||
FA icon is weirdly |
||||
aligned so tweak it |
||||
*/ |
||||
margin-top: 0.25rem; |
||||
} |
||||
} |
||||
|
||||
.username { |
||||
min-width: 0; |
||||
line-height: $username-size; |
||||
|
||||
font-size: 1rem; |
||||
font-weight: bold; |
||||
color: $fg-accent; |
||||
user-select: all; |
||||
} |
||||
} |
||||
|
||||
.role { |
||||
background: $bg; |
||||
color: $fg; |
||||
border: 0.13rem solid $bg; |
||||
|
||||
grid-area: role; |
||||
align-self: center; |
||||
justify-self: start; |
||||
border-radius: $br; |
||||
padding: 0.3rem; |
||||
|
||||
line-height: 1.1rem; |
||||
font-size: 0.9rem; |
||||
font-variant: small-caps; |
||||
font-weight: bold; |
||||
|
||||
&.admin { |
||||
color: $role-admin; |
||||
border-color: $role-admin; |
||||
} |
||||
|
||||
&.moderator { |
||||
color: $role-mod; |
||||
border-color: $role-mod; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
.profile .about-user { |
||||
flex: 35 14rem; |
||||
border-radius: $br; |
||||
overflow: hidden; |
||||
|
||||
.col-header { |
||||
margin-bottom: -0.25rem; |
||||
} |
||||
|
||||
dt { |
||||
font-weight: bold; |
||||
} |
||||
|
||||
.fields { |
||||
background: $profile-bg; |
||||
display: flex; |
||||
flex-direction: column; |
||||
padding: 0 0.5rem; |
||||
padding-top: 0.25rem; |
||||
|
||||
.field { |
||||
padding: 0.25rem; |
||||
display: flex; |
||||
flex-direction: column; |
||||
border-bottom: 0.1rem solid $gray2; |
||||
|
||||
> dt, > dd { |
||||
word-break: break-word; |
||||
} |
||||
|
||||
&:first-child { |
||||
border-top: 0.1rem solid $gray2; |
||||
} |
||||
} |
||||
} |
||||
|
||||
.bio { |
||||
background: $profile-bg; |
||||
padding: 1rem 0.75rem; |
||||
padding-bottom: 1.25rem; |
||||
} |
||||
|
||||
.accountstats { |
||||
background: $bg-accent; |
||||
padding: 0.75rem; |
||||
|
||||
display: flex; |
||||
flex-direction: column; |
||||
gap: 0.25rem; |
||||
|
||||
.stats-item { |
||||
display: flex; |
||||
dt { |
||||
width: 7rem; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
/* |
||||
RSS icon isn't really part of the profile header exactly, |
||||
but also it sort of is, and we want it styled the same for |
||||
both microblog and gallery view anyway, so include it here. |
||||
*/ |
||||
.rss-icon { |
||||
display: block; |
||||
margin: -0.25rem 0; |
||||
|
||||
.fa { |
||||
font-size: 2rem; |
||||
object-fit: contain; |
||||
vertical-align: middle; |
||||
color: $orange2; |
||||
/* |
||||
Can't size a single-color background, so we use |
||||
a linear-gradient that's effectively white. |
||||
*/ |
||||
background: linear-gradient(to right, $white1 100%, transparent 0) no-repeat center center; |
||||
background-size: 1.2rem 1.4rem; |
||||
/* light mode */ |
||||
@media (prefers-color-scheme: light) { |
||||
background: linear-gradient(to right, $white 100%, transparent 0) no-repeat center center; |
||||
background-size: 1.2rem 1.4rem; |
||||
} |
||||
} |
||||
} |
||||
|
||||
/* |
||||
Tablet-ish-kinda size. |
||||
*/ |
||||
@media screen and (max-width: 750px) { |
||||
.profile .profile-header { |
||||
.basic-info { |
||||
grid-template-columns: auto 1fr; |
||||
grid-template-rows: $avatar-size $name-size auto; |
||||
grid-template-areas: |
||||
"avatar avatar" |
||||
"namerole namerole" |
||||
"namerole namerole"; |
||||
|
||||
/* |
||||
Make display name a bit smaller |
||||
so there's more chance of being |
||||
able to read everything. |
||||
*/ |
||||
.namerole { |
||||
.displayname { |
||||
font-size: 1.2rem; |
||||
line-height: 2rem; |
||||
margin-top: 0.5rem; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
/* |
||||
Phone-ish-kinda size. |
||||
*/ |
||||
@media screen and (max-width: 500px) { |
||||
.profile |
||||
.profile-header |
||||
.basic-info |
||||
.namerole { |
||||
/* |
||||
Line up in smallest possible |
||||
horizontal space to avoid overflow. |
||||
*/ |
||||
display: flex; |
||||
flex-direction: column; |
||||
gap: 0.5rem; |
||||
|
||||
/* |
||||
Don't hug the right anymore |
||||
(good life advice in general). |
||||
*/ |
||||
.role { |
||||
align-self: flex-start; |
||||
} |
||||
|
||||
/* |
||||
Allow this to wrap in case |
||||
of a really skinny screen. |
||||
*/ |
||||
.bot-username-wrapper { |
||||
flex-wrap: wrap; |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,44 @@
|
||||
/* |
||||
GoToSocial |
||||
Copyright (C) GoToSocial Authors admin@gotosocial.org |
||||
SPDX-License-Identifier: AGPL-3.0-or-later |
||||
|
||||
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 |
||||
the Free Software Foundation, either version 3 of the License, or |
||||
(at your option) any later version. |
||||
|
||||
This program is distributed in the hope that it will be useful, |
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
GNU Affero General Public License for more details. |
||||
|
||||
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/>. |
||||
*/ |
||||
|
||||
@import "./_media-wrapper.css"; |
||||
|
||||
.media { |
||||
grid-column: span 3; |
||||
display: grid; |
||||
grid-template-columns: 50% 50%; |
||||
grid-auto-rows: 10rem; |
||||
overflow: hidden; |
||||
|
||||
&.single .media-wrapper { |
||||
grid-column: span 2; |
||||
} |
||||
|
||||
&.odd .media-wrapper:first-child, |
||||
&.double .media-wrapper { |
||||
grid-row: span 2; |
||||
} |
||||
|
||||
@media screen and (max-width: 42rem) { |
||||
.media-wrapper { |
||||
grid-column: span 2; |
||||
grid-row: span 2; |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,108 @@
|
||||
/* |
||||
GoToSocial |
||||
Copyright (C) GoToSocial Authors admin@gotosocial.org |
||||
SPDX-License-Identifier: AGPL-3.0-or-later |
||||
|
||||
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 |
||||
the Free Software Foundation, either version 3 of the License, or |
||||
(at your option) any later version. |
||||
|
||||
This program is distributed in the hope that it will be useful, |
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
GNU Affero General Public License for more details. |
||||
|
||||
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/>. |
||||
*/ |
||||
|
||||
@import "./_profile-header.css"; |
||||
@import "./_media-wrapper.css"; |
||||
|
||||
.page { |
||||
/* |
||||
Profile gallery can be wider than default. |
||||
*/ |
||||
grid-template-columns: 1fr min(95%, 65rem) 1fr; |
||||
} |
||||
|
||||
.profile { |
||||
.about-user { |
||||
margin-bottom: 1rem; |
||||
|
||||
.accountstats { |
||||
flex-direction: row; |
||||
justify-content: space-between; |
||||
|
||||
.stats-item { |
||||
gap: 0.5rem; |
||||
width: 25%; |
||||
justify-content: space-around; |
||||
|
||||
dt { |
||||
width: fit-content; |
||||
margin-left: auto; |
||||
} |
||||
|
||||
dd { |
||||
margin-right: auto; |
||||
} |
||||
} |
||||
|
||||
@media screen and (max-width: 750px) { |
||||
flex-direction: column; |
||||
.stats-item { |
||||
width: fit-content; |
||||
dt { |
||||
width: 7rem; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
.media-galleries-wrapper { |
||||
display: flex; |
||||
flex-direction: column; |
||||
gap: 1rem; |
||||
min-width: 0%; |
||||
|
||||
.media-gallery { |
||||
margin-top: 0.15rem; |
||||
margin-bottom: 0.15rem; |
||||
|
||||
display: grid; |
||||
gap: 0.15rem; |
||||
|
||||
/* Desktop-ish width, show 3 cols of media */ |
||||
grid-template-columns: repeat(3, 1fr); |
||||
|
||||
@media screen and (max-width: 55rem) { |
||||
/* Tablet-ish width, switch to 2 cols */ |
||||
grid-template-columns: repeat(2, 1fr); |
||||
} |
||||
|
||||
@media screen and (max-width: 36rem) { |
||||
/* Mobile-ish width, switch to 1 col */ |
||||
grid-template-columns: repeat(1, 1fr); |
||||
} |
||||
|
||||
.media-wrapper { |
||||
aspect-ratio: 4/3; |
||||
border: 0; |
||||
border-radius: 0; |
||||
background: $bg; |
||||
} |
||||
} |
||||
|
||||
.backnextlinks { |
||||
display: flex; |
||||
justify-content: space-between; |
||||
|
||||
.next { |
||||
margin-left: auto; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,87 @@
|
||||
{{- /* |
||||
// GoToSocial |
||||
// Copyright (C) GoToSocial Authors admin@gotosocial.org |
||||
// SPDX-License-Identifier: AGPL-3.0-or-later |
||||
// |
||||
// 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 |
||||
// the Free Software Foundation, either version 3 of the License, or |
||||
// (at your option) any later version. |
||||
// |
||||
// This program is distributed in the hope that it will be useful, |
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
// GNU Affero General Public License for more details. |
||||
// |
||||
// 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/>. |
||||
*/ -}} |
||||
|
||||
{{- with . }} |
||||
<main class="profile h-card"> |
||||
{{- with . }} |
||||
{{- include "profile_header.tmpl" . | indent 1 }} |
||||
{{- end }} |
||||
{{- with . }} |
||||
{{- include "profile_about_user.tmpl" . | indent 1 }} |
||||
{{- end }} |
||||
<div |
||||
class="media-galleries-wrapper" |
||||
role="region" |
||||
aria-label="Media by {{ .account.Username -}}" |
||||
> |
||||
{{- if .pinned_statuses }} |
||||
<section class="pinned h-feed" aria-labelledby="pinned"> |
||||
<div class="col-header"> |
||||
<h3 class="p-name" id="pinned">Pinned media</h3> |
||||
<a href="#recent">jump to recent</a> |
||||
</div> |
||||
<div |
||||
class="media-gallery photoswipe-gallery" |
||||
role="group" |
||||
> |
||||
{{- range $index, $attachment := .pinnedGalleryItems }} |
||||
{{- includeIndex "status_attachment.tmpl" $attachment $index | indent 4 }} |
||||
{{- end }} |
||||
</div> |
||||
</section> |
||||
{{- end }} |
||||
<section class="recent h-feed" aria-labelledby="recent"> |
||||
<div class="col-header"> |
||||
<h3 id="recent p-name" tabindex="-1">Recent media</h3> |
||||
{{- if .rssFeed }} |
||||
<a href="{{- .rssFeed -}}" class="rss-icon" aria-label="RSS feed"> |
||||
<i class="fa fa-rss-square" aria-hidden="true"></i> |
||||
</a> |
||||
{{- end }} |
||||
</div> |
||||
{{- if not .galleryItems }} |
||||
<div data-nosnippet class="nothinghere"> |
||||
{{- if .show_back_to_top }} |
||||
Reached the end of visible media! |
||||
{{- else }} |
||||
Nothing to see here! {{ .account.Username }} has either not posted any public media yet, or has opted not to make posts visible via the World Wide Web. |
||||
{{- end }} |
||||
</div> |
||||
{{- else }} |
||||
<div |
||||
class="media-gallery photoswipe-gallery" |
||||
role="group" |
||||
> |
||||
{{- range $index, $attachment := .galleryItems }} |
||||
{{- includeIndex "status_attachment.tmpl" $attachment $index | indent 4 }} |
||||
{{- end }} |
||||
</div> |
||||
{{- end }} |
||||
<nav class="backnextlinks"> |
||||
{{- if .show_back_to_top }} |
||||
<a href="/@{{- .account.Username -}}">Back to top</a> |
||||
{{- end }} |
||||
{{- if .statuses_next }} |
||||
<a href="{{- .statuses_next -}}" class="next">Show older</a> |
||||
{{- end }} |
||||
</nav> |
||||
</section> |
||||
</div> |
||||
</main> |
||||
{{- end }} |
||||
@ -0,0 +1,56 @@
|
||||
{{- /* |
||||
// GoToSocial |
||||
// Copyright (C) GoToSocial Authors admin@gotosocial.org |
||||
// SPDX-License-Identifier: AGPL-3.0-or-later |
||||
// |
||||
// 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 |
||||
// the Free Software Foundation, either version 3 of the License, or |
||||
// (at your option) any later version. |
||||
// |
||||
// This program is distributed in the hope that it will be useful, |
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
// GNU Affero General Public License for more details. |
||||
// |
||||
// 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/>. |
||||
*/ -}} |
||||
|
||||
{{- with . }} |
||||
<section class="about-user" role="region" aria-labelledby="about-header"> |
||||
<div class="col-header"> |
||||
<h3 id="about-header">About<span class="sr-only"> {{- .account.Username -}}</span></h3> |
||||
</div> |
||||
{{- if .account.Fields }} |
||||
{{- include "profile_fields.tmpl" . | indent 1 }} |
||||
{{- end }} |
||||
<h4 class="sr-only">Bio</h4> |
||||
<div class="bio p-note"> |
||||
{{- if .account.Note }} |
||||
{{ emojify .account.Emojis (noescape .account.Note) }} |
||||
{{- else }} |
||||
<p>This GoToSocial user hasn't written a bio yet!</p> |
||||
{{- end }} |
||||
</div> |
||||
<h4 class="sr-only">Stats</h4> |
||||
<dl class="accountstats"> |
||||
<div class="stats-item"> |
||||
<dt class="joineddt text-cutoff">Joined</dt> |
||||
<dd class="joineddd text-cutoff"><time datetime="{{- .account.CreatedAt -}}">{{- .account.CreatedAt | timestampVague -}}</time></dd> |
||||
</div> |
||||
<div class="stats-item"> |
||||
<dt class="postsdt text-cutoff">Posts</dt> |
||||
<dd class="postsdd text-cutoff">{{- .account.StatusesCount -}}</dd> |
||||
</div> |
||||
<div class="stats-item"> |
||||
<dt class="followeddt text-cutoff">Followed by</dt> |
||||
<dd class="followeddd text-cutoff">{{- if .account.HideCollections -}}<i>hidden</i>{{- else -}}{{- .account.FollowersCount -}}{{- end -}}</dd> |
||||
</div> |
||||
<div class="stats-item"> |
||||
<dt class="followingdt text-cutoff">Following</dt> |
||||
<dd class="followingdd text-cutoff">{{- if .account.HideCollections -}}<i>hidden</i>{{- else -}}{{- .account.FollowingCount -}}{{- end -}}</dd> |
||||
</div> |
||||
</dl> |
||||
</section> |
||||
{{- end }} |
||||
@ -0,0 +1,179 @@
|
||||
{{- /* |
||||
// GoToSocial |
||||
// Copyright (C) GoToSocial Authors admin@gotosocial.org |
||||
// SPDX-License-Identifier: AGPL-3.0-or-later |
||||
// |
||||
// 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 |
||||
// the Free Software Foundation, either version 3 of the License, or |
||||
// (at your option) any later version. |
||||
// |
||||
// This program is distributed in the hope that it will be useful, |
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
// GNU Affero General Public License for more details. |
||||
// |
||||
// 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/>. |
||||
*/ -}} |
||||
|
||||
{{- define "imagePreview" }} |
||||
<img |
||||
src="{{- .PreviewURL -}}" |
||||
loading="lazy" |
||||
{{- if .Description }} |
||||
alt="{{- .Description -}}" |
||||
title="{{- .Description -}}" |
||||
{{- end }} |
||||
width="{{- .Meta.Original.Width -}}" |
||||
height="{{- .Meta.Original.Height -}}" |
||||
/> |
||||
{{- end }} |
||||
|
||||
{{- define "videoPreview" }} |
||||
<img |
||||
src="{{- .PreviewURL -}}" |
||||
loading="lazy" |
||||
{{- if .Description }} |
||||
alt="{{- .Description -}}" |
||||
title="{{- .Description -}}" |
||||
{{- end }} |
||||
width="{{- .Meta.Small.Width -}}" |
||||
height="{{- .Meta.Small.Height -}}" |
||||
/> |
||||
{{- end }} |
||||
|
||||
{{- define "audioPreview" }} |
||||
{{- if and .PreviewURL .Meta.Small.Width }} |
||||
<img |
||||
src="{{- .PreviewURL -}}" |
||||
loading="lazy" |
||||
{{- if .Description }} |
||||
alt="{{- .Description -}}" |
||||
title="{{- .Description -}}" |
||||
{{- end }} |
||||
width="{{- .Meta.Small.Width -}}" |
||||
height="{{- .Meta.Small.Height -}}" |
||||
/> |
||||
{{- else }} |
||||
<img |
||||
src="/assets/logo.webp" |
||||
loading="lazy" |
||||
{{- if .Description }} |
||||
alt="{{- .Description -}}" |
||||
title="{{- .Description -}}" |
||||
{{- end }} |
||||
width="518" |
||||
height="460" |
||||
/> |
||||
{{- end }} |
||||
{{- end }} |
||||
|
||||
{{- with . }} |
||||
<div class="media-wrapper"> |
||||
<details class="{{- .Item.Type -}}-spoiler media-spoiler" {{- if not .Item.Sensitive }} open{{- end -}}> |
||||
<summary> |
||||
<div class="show sensitive button" aria-hidden="true">Show sensitive</div> |
||||
<span class="eye button" role="button" tabindex="0" aria-label="Toggle media"> |
||||
<i class="hide fa fa-fw fa-eye-slash" aria-hidden="true"></i> |
||||
<i class="show fa fa-fw fa-eye" aria-hidden="true"></i> |
||||
</span> |
||||
{{- if or (eq .Item.Type "video") (eq .Item.Type "gifv") }} |
||||
{{- include "videoPreview" .Item | indent 3 }} |
||||
{{- else if eq .Item.Type "image" }} |
||||
{{- include "imagePreview" .Item | indent 3 }} |
||||
{{- else if eq .Item.Type "audio" }} |
||||
{{- include "audioPreview" .Item | indent 3 }} |
||||
{{- end }} |
||||
</summary> |
||||
{{- if or (eq .Item.Type "video") (eq .Item.Type "gifv") }} |
||||
<video |
||||
{{- if eq .Item.Type "video" }} |
||||
preload="none" |
||||
{{- else }} |
||||
preload="auto" |
||||
muted |
||||
{{- end }} |
||||
class="plyr-video photoswipe-slide{{- if eq .Item.Type "gifv" }} gifv{{ end }}" |
||||
controls |
||||
playsinline |
||||
data-pswp-index="{{- .Index -}}" |
||||
data-pswp-parent-status="{{- .Item.ParentStatusLink -}}" |
||||
data-pswp-attachment-id="{{- .Item.ID -}}" |
||||
poster="{{- .Item.PreviewURL -}}" |
||||
data-pswp-width="{{- .Item.Meta.Original.Width -}}px" |
||||
data-pswp-height="{{- .Item.Meta.Original.Height -}}px" |
||||
{{- if .Item.Description }} |
||||
alt="{{- .Item.Description -}}" |
||||
title="{{- .Item.Description -}}" |
||||
{{- end }} |
||||
> |
||||
<source type="{{- .Item.MIMEType -}}" src="{{- .Item.URL -}}"/> |
||||
</video> |
||||
{{- else if eq .Item.Type "audio" }} |
||||
<video |
||||
preload="none" |
||||
class="plyr-video photoswipe-slide" |
||||
controls |
||||
playsinline |
||||
data-pswp-index="{{- .Index -}}" |
||||
data-pswp-parent-status="{{- .Item.ParentStatusLink -}}" |
||||
data-pswp-attachment-id="{{- .Item.ID -}}" |
||||
{{- if and .Item.PreviewURL .Item.Meta.Small.Width }} |
||||
poster="{{- .Item.PreviewURL -}}" |
||||
data-pswp-width="{{- .Item.Meta.Small.Width -}}px" |
||||
data-pswp-height="{{- .Item.Meta.Small.Height -}}px" |
||||
{{- else }} |
||||
poster="/assets/logo.webp" |
||||
width="518px" |
||||
height="460px" |
||||
{{- end }} |
||||
{{- if .Item.Description }} |
||||
alt="{{- .Item.Description -}}" |
||||
title="{{- .Item.Description -}}" |
||||
{{- end }} |
||||
> |
||||
<source type="{{- .Item.MIMEType -}}" src="{{- .Item.URL -}}"/> |
||||
</video> |
||||
{{- else if eq .Item.Type "image" }} |
||||
<a |
||||
class="photoswipe-slide" |
||||
data-pswp-index="{{- .Index -}}" |
||||
data-pswp-parent-status="{{- .Item.ParentStatusLink -}}" |
||||
data-pswp-attachment-id="{{- .Item.ID -}}" |
||||
href="{{- .Item.URL -}}" |
||||
target="_blank" |
||||
data-pswp-width="{{- .Item.Meta.Original.Width -}}px" |
||||
data-pswp-height="{{- .Item.Meta.Original.Height -}}px" |
||||
data-cropped="true" |
||||
{{- if .Item.Description }} |
||||
alt="{{- .Item.Description -}}" |
||||
title="{{- .Item.Description -}}" |
||||
{{- end }} |
||||
> |
||||
{{- with .Item }} |
||||
{{- include "imagePreview" . | indent 3 }} |
||||
{{- end }} |
||||
</a> |
||||
{{- else }} |
||||
<a |
||||
class="unknown-attachment" |
||||
href="{{- .Item.RemoteURL -}}" |
||||
rel="nofollow noreferrer noopener" |
||||
target="_blank" |
||||
{{- if .Item.Description }} |
||||
title="Open external media: {{ .Item.Description -}} {{- .Item.RemoteURL -}}" |
||||
{{- else }} |
||||
title="Open external media. {{- .Item.RemoteURL -}}" |
||||
{{- end }} |
||||
> |
||||
<div class="placeholder" aria-hidden="true"> |
||||
<i class="placeholder-external-link fa fa-external-link"></i> |
||||
<i class="placeholder-icon fa fa-file-text"></i> |
||||
<div class="placeholder-link-to">External media</div> |
||||
</div> |
||||
</a> |
||||
{{- end }} |
||||
</details> |
||||
</div> |
||||
{{- end }} |
||||
@ -1,195 +0,0 @@
|
||||
{{- /* |
||||
// GoToSocial |
||||
// Copyright (C) GoToSocial Authors admin@gotosocial.org |
||||
// SPDX-License-Identifier: AGPL-3.0-or-later |
||||
// |
||||
// 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 |
||||
// the Free Software Foundation, either version 3 of the License, or |
||||
// (at your option) any later version. |
||||
// |
||||
// This program is distributed in the hope that it will be useful, |
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
// GNU Affero General Public License for more details. |
||||
// |
||||
// 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/>. |
||||
*/ -}} |
||||
|
||||
{{- /* |
||||
Template for rendering a gallery of status media attachments. |
||||
To use this template, pass a web view status into it. |
||||
*/ -}} |
||||
|
||||
{{- define "imagePreview" }} |
||||
<img |
||||
src="{{- .PreviewURL -}}" |
||||
loading="lazy" |
||||
{{- if .Description }} |
||||
alt="{{- .Description -}}" |
||||
title="{{- .Description -}}" |
||||
{{- end }} |
||||
width="{{- .Meta.Original.Width -}}" |
||||
height="{{- .Meta.Original.Height -}}" |
||||
/> |
||||
{{- end }} |
||||
|
||||
{{- define "videoPreview" }} |
||||
<img |
||||
src="{{- .PreviewURL -}}" |
||||
loading="lazy" |
||||
{{- if .Description }} |
||||
alt="{{- .Description -}}" |
||||
title="{{- .Description -}}" |
||||
{{- end }} |
||||
width="{{- .Meta.Small.Width -}}" |
||||
height="{{- .Meta.Small.Height -}}" |
||||
/> |
||||
{{- end }} |
||||
|
||||
{{- define "audioPreview" }} |
||||
{{- if and .PreviewURL .Meta.Small.Width }} |
||||
<img |
||||
src="{{- .PreviewURL -}}" |
||||
loading="lazy" |
||||
{{- if .Description }} |
||||
alt="{{- .Description -}}" |
||||
title="{{- .Description -}}" |
||||
{{- end }} |
||||
width="{{- .Meta.Small.Width -}}" |
||||
height="{{- .Meta.Small.Height -}}" |
||||
/> |
||||
{{- else }} |
||||
<img |
||||
src="/assets/logo.webp" |
||||
loading="lazy" |
||||
{{- if .Description }} |
||||
alt="{{- .Description -}}" |
||||
title="{{- .Description -}}" |
||||
{{- end }} |
||||
width="518" |
||||
height="460" |
||||
/> |
||||
{{- end }} |
||||
{{- end }} |
||||
|
||||
{{- /* Produces something like "1 attachment", "2 attachments", etc */ -}} |
||||
{{- define "attachmentsLength" -}} |
||||
{{- (len .) }}{{- if eq (len .) 1 }} attachment{{- else }} attachments{{- end -}} |
||||
{{- end -}} |
||||
|
||||
{{- /* Produces something like "media photoswipe-gallery odd single" */ -}} |
||||
{{- define "galleryClass" -}} |
||||
media photoswipe-gallery {{ (len .) | oddOrEven }} {{ if eq (len .) 1 }}single{{ else if eq (len .) 2 }}double{{ end }} |
||||
{{- end -}} |
||||
|
||||
{{- with .MediaAttachments }} |
||||
<div |
||||
class="{{- template "galleryClass" . -}}" |
||||
role="group" |
||||
aria-label="{{- template "attachmentsLength" . -}}" |
||||
> |
||||
{{- range $index, $media := . }} |
||||
<div class="media-wrapper"> |
||||
<details class="{{- $media.Type -}}-spoiler media-spoiler" {{- if not $media.Sensitive }} open{{- end -}}> |
||||
<summary> |
||||
<div class="show sensitive button" aria-hidden="true">Show sensitive media</div> |
||||
<span class="eye button" role="button" tabindex="0" aria-label="Toggle media"> |
||||
<i class="hide fa fa-fw fa-eye-slash" aria-hidden="true"></i> |
||||
<i class="show fa fa-fw fa-eye" aria-hidden="true"></i> |
||||
</span> |
||||
{{- if or (eq .Type "video") (eq .Type "gifv") }} |
||||
{{- include "videoPreview" $media | indent 4 }} |
||||
{{- else if eq .Type "image" }} |
||||
{{- include "imagePreview" $media | indent 4 }} |
||||
{{- else if eq .Type "audio" }} |
||||
{{- include "audioPreview" $media | indent 4 }} |
||||
{{- end }} |
||||
</summary> |
||||
{{- if or (eq .Type "video") (eq .Type "gifv") }} |
||||
<video |
||||
{{- if eq .Type "video" }} |
||||
preload="none" |
||||
{{- else }} |
||||
preload="auto" |
||||
muted |
||||
{{- end }} |
||||
class="plyr-video photoswipe-slide{{- if eq .Type "gifv" }} gifv{{ end }}" |
||||
controls |
||||
playsinline |
||||
data-pswp-index="{{- $index -}}" |
||||
poster="{{- .PreviewURL -}}" |
||||
data-pswp-width="{{- $media.Meta.Small.Width -}}px" |
||||
data-pswp-height="{{- $media.Meta.Small.Height -}}px" |
||||
{{- if .Description }} |
||||
alt="{{- $media.Description -}}" |
||||
title="{{- $media.Description -}}" |
||||
{{- end }} |
||||
> |
||||
<source type="{{- $media.MIMEType -}}" src="{{- $media.URL -}}"/> |
||||
</video> |
||||
{{- else if eq .Type "audio" }} |
||||
<video |
||||
preload="none" |
||||
class="plyr-video photoswipe-slide" |
||||
controls |
||||
playsinline |
||||
data-pswp-index="{{- $index -}}" |
||||
{{- if and $media.PreviewURL $media.Meta.Small.Width }} |
||||
poster="{{- .PreviewURL -}}" |
||||
data-pswp-width="{{- $media.Meta.Small.Width -}}px" |
||||
data-pswp-height="{{- $media.Meta.Small.Height -}}px" |
||||
{{- else }} |
||||
poster="/assets/logo.webp" |
||||
width="518px" |
||||
height="460px" |
||||
{{- end }} |
||||
{{- if .Description }} |
||||
alt="{{- $media.Description -}}" |
||||
title="{{- $media.Description -}}" |
||||
{{- end }} |
||||
> |
||||
<source type="{{- $media.MIMEType -}}" src="{{- $media.URL -}}"/> |
||||
</video> |
||||
{{- else if eq .Type "image" }} |
||||
<a |
||||
class="photoswipe-slide" |
||||
href="{{- $media.URL -}}" |
||||
target="_blank" |
||||
data-pswp-width="{{- $media.Meta.Original.Width -}}px" |
||||
data-pswp-height="{{- $media.Meta.Original.Height -}}px" |
||||
data-cropped="true" |
||||
{{- if .Description }} |
||||
alt="{{- $media.Description -}}" |
||||
title="{{- $media.Description -}}" |
||||
{{- end }} |
||||
> |
||||
{{- with $media }} |
||||
{{- include "imagePreview" . | indent 4 }} |
||||
{{- end }} |
||||
</a> |
||||
{{- else }} |
||||
<a |
||||
class="unknown-attachment" |
||||
href="{{- $media.RemoteURL -}}" |
||||
rel="nofollow noreferrer noopener" |
||||
target="_blank" |
||||
{{- if .Description }} |
||||
title="Open external media: {{ $media.Description -}} {{- $media.RemoteURL -}}" |
||||
{{- else }} |
||||
title="Open external media. {{- $media.RemoteURL -}}" |
||||
{{- end }} |
||||
> |
||||
<div class="placeholder" aria-hidden="true"> |
||||
<i class="placeholder-external-link fa fa-external-link"></i> |
||||
<i class="placeholder-icon fa fa-file-text"></i> |
||||
<div class="placeholder-link-to">External media</div> |
||||
</div> |
||||
</a> |
||||
{{- end }} |
||||
</details> |
||||
</div> |
||||
{{- end }} |
||||
</div> |
||||
{{- end }} |
||||