Allow changing header + profile pictures

This commit is contained in:
Lim Chee Aun 2025-02-20 11:51:17 +08:00
parent 87ea4372b1
commit e9d68a00c8
3 changed files with 208 additions and 20 deletions

View file

@ -51,7 +51,8 @@
border-radius: var(--posting-stats-size);
overflow: hidden;
margin: 8px 0;
box-shadow: inset 0 0 0 1px var(--outline-color),
box-shadow:
inset 0 0 0 1px var(--outline-color),
inset 0 0 0 1.5px var(--bg-blur-color);
background-color: var(--bg-color);
background-repeat: no-repeat;
@ -85,7 +86,8 @@
vertical-align: middle;
margin: 0 4px 2px;
/* border: 1px solid var(--outline-color); */
box-shadow: inset 0 0 0 1px var(--outline-color),
box-shadow:
inset 0 0 0 1px var(--outline-color),
inset 0 0 0 1.5px var(--bg-blur-color);
&.posting-stats-legend-item-originals {
@ -246,7 +248,9 @@
display: flex;
align-items: center;
gap: 8px;
text-shadow: -8px 0 12px -6px var(--bg-color), 8px 0 12px -6px var(--bg-color),
text-shadow:
-8px 0 12px -6px var(--bg-color),
8px 0 12px -6px var(--bg-color),
-8px 0 24px var(--header-color-3, --bg-color),
8px 0 24px var(--header-color-4, --bg-color);
animation: fade-in 0.3s both ease-in-out 0.1s;
@ -743,9 +747,9 @@
--shadow-offset: 16px;
--shadow-blur: 32px;
--shadow-spread: calc(var(--shadow-blur) * -0.75);
box-shadow: calc(var(--shadow-offset) * -1) var(--shadow-offset)
var(--shadow-blur) var(--shadow-spread)
var(--header-color-1, var(--drop-shadow-color)),
box-shadow:
calc(var(--shadow-offset) * -1) var(--shadow-offset) var(--shadow-blur)
var(--shadow-spread) var(--header-color-1, var(--drop-shadow-color)),
var(--shadow-offset) var(--shadow-offset) var(--shadow-blur)
var(--shadow-spread) var(--header-color-2, var(--drop-shadow-color));
}
@ -805,7 +809,7 @@
}
label {
input,
input:not([type='file']),
textarea {
display: block;
width: 100%;
@ -818,6 +822,55 @@
}
}
.edit-profile-media-container {
margin-block: 8px;
}
.edit-profile-media-field {
display: grid;
grid-template-columns: 80px 2em 80px;
gap: 8px;
margin-top: 8px;
align-items: center;
justify-items: center;
.icon {
opacity: 0.75;
}
.edit-media {
width: 80px;
height: 80px;
border-radius: 4px;
overflow: hidden;
border: 1px solid var(--outline-color);
/* checkerboard background */
background-image:
linear-gradient(45deg, var(--img-bg-color) 25%, transparent 25%),
linear-gradient(-45deg, var(--img-bg-color) 25%, transparent 25%),
linear-gradient(45deg, transparent 75%, var(--img-bg-color) 75%),
linear-gradient(-45deg, transparent 75%, var(--img-bg-color) 75%);
background-size: 10px 10px;
background-position:
0 0,
0 5px,
5px -5px,
-5px 0px;
&:hover {
box-shadow: 0 0 0 2px var(--link-light-color);
cursor: pointer;
}
img {
object-fit: contain;
width: 100%;
height: 100%;
vertical-align: top;
}
}
}
table {
width: 100%;

View file

@ -2090,11 +2090,21 @@ function PrivateNoteSheet({
);
}
const SUPPORTED_IMAGE_FORMATS = [
'image/jpeg',
'image/png',
'image/gif',
'image/webp',
];
const SUPPORTED_IMAGE_FORMATS_STR = SUPPORTED_IMAGE_FORMATS.join(',');
function EditProfileSheet({ onClose = () => {} }) {
const { t } = useLingui();
const { masto } = api();
const [uiState, setUIState] = useState('loading');
const [account, setAccount] = useState(null);
const [headerPreview, setHeaderPreview] = useState(null);
const [avatarPreview, setAvatarPreview] = useState(null);
useEffect(() => {
(async () => {
@ -2110,10 +2120,19 @@ function EditProfileSheet({ onClose = () => {} }) {
}, []);
console.log('EditProfileSheet', account);
const { displayName, source } = account || {};
const { displayName, source, avatar, header } = account || {};
const { note, fields } = source || {};
const fieldsAttributesRef = useRef(null);
const avatarMediaAttachments = [
...(avatar ? [{ type: 'image', url: avatar }] : []),
...(avatarPreview ? [{ type: 'image', url: avatarPreview }] : []),
];
const headerMediaAttachments = [
...(header ? [{ type: 'image', url: header }] : []),
...(headerPreview ? [{ type: 'image', url: headerPreview }] : []),
];
return (
<div class="sheet" id="edit-profile-container">
{!!onClose && (
@ -2136,6 +2155,8 @@ function EditProfileSheet({ onClose = () => {} }) {
onSubmit={(e) => {
e.preventDefault();
const formData = new FormData(e.target);
const header = formData.get('header');
const avatar = formData.get('avatar');
const displayName = formData.get('display_name');
const note = formData.get('note');
const fieldsAttributesFields =
@ -2163,6 +2184,8 @@ function EditProfileSheet({ onClose = () => {} }) {
(async () => {
try {
const newAccount = await masto.v1.accounts.updateCredentials({
header,
avatar,
displayName,
note,
fieldsAttributes,
@ -2179,6 +2202,110 @@ function EditProfileSheet({ onClose = () => {} }) {
})();
}}
>
<div class="edit-profile-media-container">
<label>
<Trans>Header picture</Trans>{' '}
<input
type="file"
name="header"
accept={SUPPORTED_IMAGE_FORMATS_STR}
onChange={(e) => {
const file = e.target.files[0];
if (file) {
const blob = URL.createObjectURL(file);
setHeaderPreview(blob);
}
}}
/>
</label>
<div class="edit-profile-media-field">
{header ? (
<div
class="edit-media"
tabIndex="0"
onClick={() => {
states.showMediaModal = {
mediaAttachments: headerMediaAttachments,
index: 0,
};
}}
>
<img src={header} alt="" />
</div>
) : (
<div class="edit-media"></div>
)}
{headerPreview && (
<>
<Icon icon="arrow-right" />
<div
class="edit-media"
tabIndex="0"
onClick={() => {
states.showMediaModal = {
mediaAttachments: headerMediaAttachments,
index: 1,
};
}}
>
<img src={headerPreview} alt="" />
</div>
</>
)}
</div>
</div>
<div class="edit-profile-media-container">
<label>
<Trans>Profile picture</Trans>{' '}
<input
type="file"
name="avatar"
accept={SUPPORTED_IMAGE_FORMATS_STR}
onChange={(e) => {
const file = e.target.files[0];
if (file) {
const blob = URL.createObjectURL(file);
setAvatarPreview(blob);
}
}}
/>
</label>
<div class="edit-profile-media-field">
{avatar ? (
<div
class="edit-media"
tabIndex="0"
onClick={() => {
states.showMediaModal = {
mediaAttachments: avatarMediaAttachments,
index: 0,
};
}}
>
<img src={avatar} alt="" />
</div>
) : (
<div class="edit-media"></div>
)}
{avatarPreview && (
<>
<Icon icon="arrow-right" />
<div
class="edit-media"
tabIndex="0"
onClick={() => {
states.showMediaModal = {
mediaAttachments: avatarMediaAttachments,
index: 1,
};
}}
>
<img src={avatarPreview} alt="" />
</div>
</>
)}
</div>
</div>
<p>
<label>
<Trans>Name</Trans>{' '}

32
src/locales/en.po generated
View file

@ -386,7 +386,7 @@ msgid "Report <0>@{username}</0>…"
msgstr ""
#: src/components/account-info.jsx:1611
#: src/components/account-info.jsx:2126
#: src/components/account-info.jsx:2145
msgid "Edit profile"
msgstr ""
@ -416,7 +416,7 @@ msgstr ""
#: src/components/account-info.jsx:1831
#: src/components/account-info.jsx:1886
#: src/components/account-info.jsx:2020
#: src/components/account-info.jsx:2121
#: src/components/account-info.jsx:2140
#: src/components/account-sheet.jsx:38
#: src/components/compose.jsx:859
#: src/components/compose.jsx:2580
@ -485,7 +485,7 @@ msgid "Unable to update private note."
msgstr "Unable to update private note."
#: src/components/account-info.jsx:2078
#: src/components/account-info.jsx:2249
#: src/components/account-info.jsx:2376
msgid "Cancel"
msgstr ""
@ -493,32 +493,40 @@ msgstr ""
msgid "Save & close"
msgstr ""
#: src/components/account-info.jsx:2177
#: src/components/account-info.jsx:2200
msgid "Unable to update profile."
msgstr "Unable to update profile."
#: src/components/account-info.jsx:2184
#: src/components/account-info.jsx:2207
msgid "Header picture"
msgstr "Header picture"
#: src/components/account-info.jsx:2259
msgid "Profile picture"
msgstr "Profile picture"
#: src/components/account-info.jsx:2311
#: src/components/list-add-edit.jsx:105
msgid "Name"
msgstr ""
#: src/components/account-info.jsx:2197
#: src/components/account-info.jsx:2324
msgid "Bio"
msgstr ""
#: src/components/account-info.jsx:2210
#: src/components/account-info.jsx:2337
msgid "Extra fields"
msgstr ""
#: src/components/account-info.jsx:2216
#: src/components/account-info.jsx:2343
msgid "Label"
msgstr ""
#: src/components/account-info.jsx:2219
#: src/components/account-info.jsx:2346
msgid "Content"
msgstr ""
#: src/components/account-info.jsx:2252
#: src/components/account-info.jsx:2379
#: src/components/list-add-edit.jsx:150
#: src/components/shortcuts-settings.jsx:715
#: src/pages/filters.jsx:554
@ -526,11 +534,11 @@ msgstr ""
msgid "Save"
msgstr ""
#: src/components/account-info.jsx:2306
#: src/components/account-info.jsx:2433
msgid "username"
msgstr ""
#: src/components/account-info.jsx:2310
#: src/components/account-info.jsx:2437
msgid "server domain name"
msgstr ""