Skip to content

Commit

Permalink
Add cropping support when modifying the user/org/repo avatar (go-gite…
Browse files Browse the repository at this point in the history
…a#33498)

Fixed go-gitea#33321

---------

Co-authored-by: wxiaoguang <[email protected]>
  • Loading branch information
kerwin612 and wxiaoguang authored Feb 6, 2025
1 parent 943cc4f commit 40426ad
Show file tree
Hide file tree
Showing 11 changed files with 35 additions and 28 deletions.
3 changes: 1 addition & 2 deletions templates/admin/user/edit.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -195,8 +195,7 @@
</div>

<div class="inline field tw-pl-4">
<label for="avatar">{{ctx.Locale.Tr "settings.choose_new_avatar"}}</label>
<input name="avatar" type="file" accept="image/png,image/jpeg,image/gif,image/webp">
{{template "shared/avatar_upload_crop" dict "LabelText" (ctx.Locale.Tr "settings.choose_new_avatar")}}
</div>

<div class="field">
Expand Down
4 changes: 1 addition & 3 deletions templates/org/settings/options.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -89,10 +89,8 @@
<form class="ui form" action="{{.Link}}/avatar" method="post" enctype="multipart/form-data">
{{.CsrfTokenHtml}}
<div class="inline field">
<label for="avatar">{{ctx.Locale.Tr "settings.choose_new_avatar"}}</label>
<input name="avatar" type="file" accept="image/png,image/jpeg,image/gif,image/webp">
{{template "shared/avatar_upload_crop" dict "LabelText" (ctx.Locale.Tr "settings.choose_new_avatar")}}
</div>

<div class="field">
<button class="ui primary button">{{ctx.Locale.Tr "settings.update_avatar"}}</button>
<button class="ui red button link-action" data-url="{{.Link}}/avatar/delete">{{ctx.Locale.Tr "settings.delete_current_avatar"}}</button>
Expand Down
3 changes: 1 addition & 2 deletions templates/repo/settings/options.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,7 @@
<form class="ui form" action="{{.Link}}/avatar" method="post" enctype="multipart/form-data">
{{.CsrfTokenHtml}}
<div class="inline field">
<label for="avatar">{{ctx.Locale.Tr "settings.choose_new_avatar"}}</label>
<input name="avatar" type="file" accept="image/png,image/jpeg,image/gif,image/webp">
{{template "shared/avatar_upload_crop" dict "LabelText" (ctx.Locale.Tr "settings.choose_new_avatar")}}
</div>
<div class="field">
<button class="ui primary button">{{ctx.Locale.Tr "settings.update_avatar"}}</button>
Expand Down
8 changes: 8 additions & 0 deletions templates/shared/avatar_upload_crop.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{{- /* we do not need to set for/id here, global aria init code will add them automatically */ -}}
<label>{{.LabelText}}</label>
<input class="avatar-file-with-cropper" name="avatar" type="file" accept="image/png,image/jpeg,image/gif,image/webp">
{{- /* the cropper-panel must be next sibling of the input "avatar" */ -}}
<div class="cropper-panel tw-hidden">
<div class="tw-my-2">{{ctx.Locale.Tr "settings.cropper_prompt"}}</div>
<div class="cropper-wrapper"><img class="cropper-source" src alt></div>
</div>
8 changes: 1 addition & 7 deletions templates/user/settings/profile.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -124,13 +124,7 @@
</div>

<div class="inline field tw-pl-4">
<label for="new-avatar">{{ctx.Locale.Tr "settings.choose_new_avatar"}}</label>
<input id="new-avatar" name="avatar" type="file" accept="image/png,image/jpeg,image/gif,image/webp">
</div>

<div class="field tw-pl-4 cropper-panel tw-hidden">
<div>{{ctx.Locale.Tr "settings.cropper_prompt"}}</div>
<div class="cropper-wrapper"><img class="cropper-source" src alt></div>
{{template "shared/avatar_upload_crop" dict "LabelText" (ctx.Locale.Tr "settings.choose_new_avatar")}}
</div>

<div class="field">
Expand Down
2 changes: 1 addition & 1 deletion web_src/css/features/cropper.css
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
@import "cropperjs/dist/cropper.css";

.page-content.user.profile .cropper-panel .cropper-wrapper {
.avatar-file-with-cropper + .cropper-panel .cropper-wrapper {
max-width: 400px;
max-height: 400px;
}
5 changes: 4 additions & 1 deletion web_src/js/features/admin/common.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import $ from 'jquery';
import {checkAppUrl} from '../common-page.ts';
import {hideElem, showElem, toggleElem} from '../../utils/dom.ts';
import {hideElem, queryElems, showElem, toggleElem} from '../../utils/dom.ts';
import {POST} from '../../modules/fetch.ts';
import {initAvatarUploaderWithCropper} from '../comp/Cropper.ts';

const {appSubUrl} = window.config;

Expand Down Expand Up @@ -258,4 +259,6 @@ export function initAdminCommon(): void {
window.location.href = this.getAttribute('data-redirect');
});
}

queryElems(document, '.avatar-file-with-cropper', initAvatarUploaderWithCropper);
}
5 changes: 4 additions & 1 deletion web_src/js/features/common-organization.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {initCompLabelEdit} from './comp/LabelEdit.ts';
import {toggleElem} from '../utils/dom.ts';
import {queryElems, toggleElem} from '../utils/dom.ts';
import {initAvatarUploaderWithCropper} from './comp/Cropper.ts';

export function initCommonOrganization() {
if (!document.querySelectorAll('.organization').length) {
Expand All @@ -13,4 +14,6 @@ export function initCommonOrganization() {

// Labels
initCompLabelEdit('.page-content.organization.settings.labels');

queryElems(document, '.avatar-file-with-cropper', initAvatarUploaderWithCropper);
}
9 changes: 8 additions & 1 deletion web_src/js/features/comp/Cropper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ type CropperOpts = {
fileInput: HTMLInputElement,
}

export async function initCompCropper({container, fileInput, imageSource}: CropperOpts) {
async function initCompCropper({container, fileInput, imageSource}: CropperOpts) {
const {default: Cropper} = await import(/* webpackChunkName: "cropperjs" */'cropperjs');
let currentFileName = '';
let currentFileLastModified = 0;
Expand Down Expand Up @@ -38,3 +38,10 @@ export async function initCompCropper({container, fileInput, imageSource}: Cropp
}
});
}

export async function initAvatarUploaderWithCropper(fileInput: HTMLInputElement) {
const panel = fileInput.nextElementSibling as HTMLElement;
if (!panel?.matches('.cropper-panel')) throw new Error('Missing cropper panel for avatar uploader');
const imageSource = panel.querySelector<HTMLImageElement>('.cropper-source');
await initCompCropper({container: panel, fileInput, imageSource});
}
3 changes: 3 additions & 0 deletions web_src/js/features/repo-settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {minimatch} from 'minimatch';
import {createMonaco} from './codeeditor.ts';
import {onInputDebounce, queryElems, toggleElem} from '../utils/dom.ts';
import {POST} from '../modules/fetch.ts';
import {initAvatarUploaderWithCropper} from './comp/Cropper.ts';
import {initRepoSettingsBranchesDrag} from './repo-settings-branches.ts';

const {appSubUrl, csrfToken} = window.config;
Expand Down Expand Up @@ -156,4 +157,6 @@ export function initRepoSettings() {
initRepoSettingsSearchTeamBox();
initRepoSettingsGitHook();
initRepoSettingsBranchesDrag();

queryElems(document, '.avatar-file-with-cropper', initAvatarUploaderWithCropper);
}
13 changes: 3 additions & 10 deletions web_src/js/features/user-settings.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,10 @@
import {hideElem, showElem} from '../utils/dom.ts';
import {initCompCropper} from './comp/Cropper.ts';

function initUserSettingsAvatarCropper() {
const fileInput = document.querySelector<HTMLInputElement>('#new-avatar');
const container = document.querySelector<HTMLElement>('.user.settings.profile .cropper-panel');
const imageSource = container.querySelector<HTMLImageElement>('.cropper-source');
initCompCropper({container, fileInput, imageSource});
}
import {hideElem, queryElems, showElem} from '../utils/dom.ts';
import {initAvatarUploaderWithCropper} from './comp/Cropper.ts';

export function initUserSettings() {
if (!document.querySelector('.user.settings.profile')) return;

initUserSettingsAvatarCropper();
queryElems(document, '.avatar-file-with-cropper', initAvatarUploaderWithCropper);

const usernameInput = document.querySelector<HTMLInputElement>('#username');
if (!usernameInput) return;
Expand Down

0 comments on commit 40426ad

Please sign in to comment.