[feature] Add image descriptions for default avatar + header; don't allow editing default desc (#3473)

This commit is contained in:
tobi 2024-10-21 14:04:50 +02:00 committed by GitHub
commit 8a93300ac4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
22 changed files with 198 additions and 25 deletions

View file

@ -19,6 +19,7 @@
import React from "react";
import Loading from "./loading";
import { Error as ErrorC } from "./error";
import { useVerifyCredentialsQuery, useLogoutMutation } from "../lib/query/oauth";
import { useInstanceV1Query } from "../lib/query/gts-api";
@ -29,16 +30,20 @@ export default function UserLogoutCard() {
if (isLoading) {
return <Loading />;
} else {
return (
<div className="account-card">
<img className="avatar" src={profile.avatar} alt="" />
<h3 className="text-cutoff">{profile.display_name?.length > 0 ? profile.display_name : profile.acct}</h3>
<span className="text-cutoff">@{profile.username}@{instance?.account_domain}</span>
<a onClick={logoutQuery} href="#" aria-label="Log out" title="Log out" className="logout">
<i className="fa fa-fw fa-sign-out" aria-hidden="true" />
</a>
</div>
);
}
if (!profile) {
return <ErrorC error={new Error("account was undefined")} />;
}
return (
<div className="account-card">
<img className="avatar" src={profile.avatar} alt="" />
<h3 className="text-cutoff">{profile.display_name?.length > 0 ? profile.display_name : profile.acct}</h3>
<span className="text-cutoff">@{profile.username}@{instance?.account_domain}</span>
<a onClick={logoutQuery} href="#" aria-label="Log out" title="Log out" className="logout">
<i className="fa fa-fw fa-sign-out" aria-hidden="true" />
</a>
</div>
);
}

View file

@ -26,6 +26,7 @@ import {
authorize as oauthAuthorize,
} from "../../../redux/oauth";
import { RootState } from '../../../redux/store';
import { Account } from '../../types/account';
export interface OauthTokenRequestBody {
client_id: string;
@ -58,7 +59,7 @@ const SETTINGS_URL = (getSettingsURL());
// https://redux-toolkit.js.org/rtk-query/usage/customizing-queries#performing-multiple-requests-with-a-single-query
const extended = gtsApi.injectEndpoints({
endpoints: (build) => ({
verifyCredentials: build.query<any, void>({
verifyCredentials: build.query<Account, void>({
providesTags: (_res, error) =>
error == undefined ? ["Auth"] : [],
async queryFn(_arg, api, _extraOpts, fetchWithBQ) {

View file

@ -53,8 +53,12 @@ export interface Account {
url: string,
avatar: string,
avatar_static: string,
avatar_description?: string,
avatar_media_id?: string,
header: string,
header_static: string,
header_description?: string,
header_media_id?: string,
followers_count: number,
following_count: number,
statuses_count: number,
@ -68,7 +72,7 @@ export interface Account {
}
export interface AccountSource {
fields: any[];
fields: any;
follow_requests_count: number;
language: string;
note: string;

View file

@ -441,6 +441,11 @@ section.with-sidebar > form {
.profile {
max-width: 42rem;
}
.file-input-with-image-description {
max-width: 100%;
width: 100%;
}
.overview {
display: flex;

View file

@ -20,7 +20,7 @@
import React from "react";
import { useVerifyCredentialsQuery } from "../../../lib/query/oauth";
import Loading from "../../../components/loading";
import { Error } from "../../../components/error";
import { Error as ErrorC } from "../../../components/error";
import BasicSettings from "./basic-settings";
import InteractionPolicySettings from "./interaction-policy-settings";
@ -38,7 +38,11 @@ export default function PostSettings() {
}
if (isError) {
return <Error error={error} />;
return <ErrorC error={error} />;
}
if (!account) {
return <ErrorC error={new Error("account was undefined")} />;
}
return (

View file

@ -45,6 +45,7 @@ import { useAccountThemesQuery } from "../../lib/query/user";
import { useUpdateCredentialsMutation } from "../../lib/query/user";
import { useVerifyCredentialsQuery } from "../../lib/query/oauth";
import { useInstanceV1Query } from "../../lib/query/gts-api";
import { Account } from "../../lib/types/account";
export default function UserProfile() {
return (
@ -55,7 +56,11 @@ export default function UserProfile() {
);
}
function UserProfileForm({ data: profile }) {
interface UserProfileFormProps {
data: Account;
}
function UserProfileForm({ data: profile }: UserProfileFormProps) {
/*
User profile update form keys
- bool bot
@ -132,6 +137,9 @@ function UserProfileForm({ data: profile }) {
}
});
const noAvatarSet = !profile.avatar_media_id;
const noHeaderSet = !profile.header_media_id;
return (
<form className="user-profile" onSubmit={submitForm}>
<h1>Profile</h1>
@ -145,33 +153,37 @@ function UserProfileForm({ data: profile }) {
role={profile.role}
/>
<div className="file-input-with-image-description">
<fieldset className="file-input-with-image-description">
<legend>Header</legend>
<FileInput
label="Header"
label="Upload file"
field={form.header}
accept="image/png, image/jpeg, image/webp, image/gif"
/>
<TextInput
field={form.headerDescription}
label="Header image description"
label="Image description; only settable if not using default header"
placeholder="A green field with pink flowers."
autoCapitalize="sentences"
disabled={noHeaderSet && !form.header.value}
/>
</div>
</fieldset>
<div className="file-input-with-image-description">
<fieldset className="file-input-with-image-description">
<legend>Avatar</legend>
<FileInput
label="Avatar (1:1 images look best)"
label="Upload file (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"
label="Image description; only settable if not using default avatar"
placeholder="A cute drawing of a smiling sloth."
autoCapitalize="sentences"
disabled={noAvatarSet && !form.avatar.value}
/>
</div>
</fieldset>
<div className="theme">
<div>