summaryrefslogtreecommitdiff
path: root/web
diff options
context:
space:
mode:
Diffstat (limited to 'web')
-rw-r--r--web/source/css/profile.css29
-rw-r--r--web/source/settings/components/profile.tsx8
-rw-r--r--web/source/settings/style.css23
-rw-r--r--web/source/settings/views/user/profile.tsx44
-rw-r--r--web/template/profile.tmpl86
5 files changed, 148 insertions, 42 deletions
diff --git a/web/source/css/profile.css b/web/source/css/profile.css
index a966d768a..3f7f43d0d 100644
--- a/web/source/css/profile.css
+++ b/web/source/css/profile.css
@@ -82,18 +82,37 @@
margin-top: calc(-1 * $overlap);
gap: 0 1rem;
- .avatar {
+ .avatar-image-wrapper {
grid-area: avatar;
- height: $avatar-size;
- width: $avatar-size;
+
border: 0.2rem solid $avatar-border;
border-radius: $br;
- overflow: hidden; /* prevents image extending beyond rounded borders */
+
+ /*
+ Wrapper always same
+ size + proportions no
+ matter image inside.
+ */
+ height: $avatar-size;
+ width: $avatar-size;
- img {
+ .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;
}
}
diff --git a/web/source/settings/components/profile.tsx b/web/source/settings/components/profile.tsx
index 4a5157378..24cb3c4c2 100644
--- a/web/source/settings/components/profile.tsx
+++ b/web/source/settings/components/profile.tsx
@@ -27,9 +27,11 @@ export default function FakeProfile({ avatar, header, display_name, username, ro
<img src={header} alt={header ? `header image for ${username}` : "None set"} />
</div>
<div className="basic-info" aria-hidden="true">
- <a className="avatar" href={avatar}>
- <img src={avatar} alt={avatar ? `avatar image for ${username}` : "None set"} />
- </a>
+ <div className="avatar-image-wrapper">
+ <a href={avatar}>
+ <img className="avatar" src={avatar} alt={avatar ? `avatar image for ${username}` : "None set"} />
+ </a>
+ </div>
<dl className="namerole">
<dt className="sr-only">Display name</dt>
<dd className="displayname text-cutoff">{display_name.trim().length > 0 ? display_name : username}</dd>
diff --git a/web/source/settings/style.css b/web/source/settings/style.css
index cdae6b972..f9c098ace 100644
--- a/web/source/settings/style.css
+++ b/web/source/settings/style.css
@@ -400,12 +400,13 @@ section.with-sidebar > form {
width: 24rem;
}
}
-
- .file-input-with-image-description {
- display: flex;
- flex-direction: column;
- justify-content: space-around;
- }
+}
+
+.file-input-with-image-description {
+ display: flex;
+ flex-direction: column;
+ justify-content: space-around;
+ gap: 0.5rem;
}
/*
@@ -422,11 +423,13 @@ section.with-sidebar > form {
}
.user-profile {
+ .profile {
+ max-width: 42rem;
+ }
+
.overview {
- display: grid;
- max-width: 60rem;
- grid-template-columns: 70% 30%;
- grid-template-rows: auto;
+ display: flex;
+ flex-direction: column;
gap: 1rem;
.files {
diff --git a/web/source/settings/views/user/profile.tsx b/web/source/settings/views/user/profile.tsx
index 17827ce9e..f4088b353 100644
--- a/web/source/settings/views/user/profile.tsx
+++ b/web/source/settings/views/user/profile.tsx
@@ -93,7 +93,9 @@ function UserProfileForm({ data: profile }) {
const form = {
avatar: useFileInput("avatar", { withPreview: true }),
+ avatarDescription: useTextInput("avatar_description", { source: profile }),
header: useFileInput("header", { withPreview: true }),
+ headerDescription: useTextInput("header_description", { source: profile }),
displayName: useTextInput("display_name", { source: profile }),
note: useTextInput("note", { source: profile, valueSelector: (p) => p.source?.note }),
bot: useBoolInput("bot", { source: profile }),
@@ -131,21 +133,33 @@ function UserProfileForm({ data: profile }) {
username={profile.username}
role={profile.role}
/>
- <div className="files">
- <div>
- <FileInput
- label="Header"
- field={form.header}
- accept="image/*"
- />
- </div>
- <div>
- <FileInput
- label="Avatar"
- field={form.avatar}
- accept="image/*"
- />
- </div>
+
+ <div className="file-input-with-image-description">
+ <FileInput
+ label="Header"
+ field={form.header}
+ accept="image/png, image/jpeg, image/webp, image/gif"
+ />
+ <TextInput
+ field={form.headerDescription}
+ label="Header image description"
+ placeholder="A green field with pink flowers."
+ autoCapitalize="sentences"
+ />
+ </div>
+
+ <div className="file-input-with-image-description">
+ <FileInput
+ label="Avatar (1:1 images look best)"
+ field={form.avatar}
+ accept="image/png, image/jpeg, image/webp, image/gif"
+ />
+ <TextInput
+ field={form.avatarDescription}
+ label="Avatar image description"
+ placeholder="A cute drawing of a smiling sloth."
+ autoCapitalize="sentences"
+ />
</div>
<div className="theme">
diff --git a/web/template/profile.tmpl b/web/template/profile.tmpl
index f0467e004..256bbdccf 100644
--- a/web/template/profile.tmpl
+++ b/web/template/profile.tmpl
@@ -35,6 +35,78 @@
{{- end }}
{{- end -}}
+{{- define "defaultAvatarDimension" -}}
+{{- /* 136 is the default width/height for 8.5rem avatars, double it to get a good look when expanded. */ -}}
+272
+{{- end -}}
+
+{{- define "avatarWidth" -}}
+{{- with .account }}
+ {{- if isNil .AvatarAttachment -}}
+ {{- template "defaultAvatarDimension" . -}}
+ {{- else -}}
+ {{- /* Use the avatar's proper dimensions. */ -}}
+ {{- .AvatarAttachment.Meta.Original.Width -}}
+ {{- end -}}
+{{- end }}
+{{- end -}}
+
+{{- define "avatarHeight" -}}
+{{- with .account }}
+ {{- if isNil .AvatarAttachment -}}
+ {{- template "defaultAvatarDimension" . -}}
+ {{- else -}}
+ {{- /* Use the avatar's proper dimensions. */ -}}
+ {{- .AvatarAttachment.Meta.Original.Height -}}
+ {{- end -}}
+{{- end }}
+{{- end -}}
+
+{{- define "avatarAlt" -}}
+ Avatar for {{ .account.Username -}}
+ {{- if .account.AvatarDescription }}
+ {{- /* Add the avatar's image description. */ -}}
+ : {{ .account.AvatarDescription -}}
+ {{- end -}}
+{{- end -}}
+
+{{- define "headerAlt" -}}
+ Header for {{ .account.Username -}}
+ {{- if .account.HeaderDescription }}
+ {{- /* Add the header's image description. */ -}}
+ : {{ .account.HeaderDescription -}}
+ {{- end -}}
+{{- end -}}
+
+{{- define "avatar" -}}
+{{- with . }}
+<div
+ class="media photoswipe-gallery odd single avatar-image-wrapper"
+ role="group"
+>
+ <a
+ class="photoswipe-slide"
+ href="{{- .account.Avatar -}}"
+ target="_blank"
+ data-pswp-width="{{- template "avatarWidth" . -}}px"
+ data-pswp-height="{{- template "avatarHeight" . -}}px"
+ data-cropped="true"
+ alt="{{- template "avatarAlt" . -}}"
+ title="{{- template "avatarAlt" . -}}"
+ >
+ <img
+ class="avatar"
+ src="{{- .account.Avatar -}}"
+ alt="{{- template "avatarAlt" . -}}"
+ title="{{- template "avatarAlt" . -}}"
+ width="{{- template "avatarWidth" . -}}"
+ height="{{- template "avatarHeight" . -}}"
+ />
+ </a>
+</div>
+{{- end }}
+{{- end -}}
+
{{- with . }}
<main class="profile">
<h2 class="sr-only">Profile for {{ .account.Username -}}</h2>
@@ -45,18 +117,14 @@
<div class="header-image-wrapper">
<img
src="{{- .account.Header -}}"
- alt="Header for {{ .account.Username -}}"
- title="Header for {{ .account.Username -}}"
+ alt="{{- template "headerAlt" . -}}"
+ title="{{- template "headerAlt" . -}}"
/>
</div>
<div class="basic-info">
- <a class="avatar" href="{{- .account.Avatar -}}">
- <img
- src="{{- .account.Avatar -}}"
- alt="Avatar for {{ .account.Username -}}"
- title="Avatar for {{ .account.Username -}}"
- />
- </a>
+ {{- with . }}
+ {{- include "avatar" . | indent 3 }}
+ {{- end }}
<dl class="namerole">
<dt class="sr-only">Display name</dt>
<dd class="displayname text-cutoff">