mirror of
https://github.com/go-gitea/gitea.git
synced 2025-02-20 11:43:57 +08:00
Add cropping support when modifying the user/org/repo avatar (#33498)
Fixed #33321 --------- Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
This commit is contained in:
parent
943cc4f989
commit
40426addfa
@ -195,8 +195,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="inline field tw-pl-4">
|
<div class="inline field tw-pl-4">
|
||||||
<label for="avatar">{{ctx.Locale.Tr "settings.choose_new_avatar"}}</label>
|
{{template "shared/avatar_upload_crop" dict "LabelText" (ctx.Locale.Tr "settings.choose_new_avatar")}}
|
||||||
<input name="avatar" type="file" accept="image/png,image/jpeg,image/gif,image/webp">
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="field">
|
<div class="field">
|
||||||
|
@ -89,10 +89,8 @@
|
|||||||
<form class="ui form" action="{{.Link}}/avatar" method="post" enctype="multipart/form-data">
|
<form class="ui form" action="{{.Link}}/avatar" method="post" enctype="multipart/form-data">
|
||||||
{{.CsrfTokenHtml}}
|
{{.CsrfTokenHtml}}
|
||||||
<div class="inline field">
|
<div class="inline field">
|
||||||
<label for="avatar">{{ctx.Locale.Tr "settings.choose_new_avatar"}}</label>
|
{{template "shared/avatar_upload_crop" dict "LabelText" (ctx.Locale.Tr "settings.choose_new_avatar")}}
|
||||||
<input name="avatar" type="file" accept="image/png,image/jpeg,image/gif,image/webp">
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<button class="ui primary button">{{ctx.Locale.Tr "settings.update_avatar"}}</button>
|
<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>
|
<button class="ui red button link-action" data-url="{{.Link}}/avatar/delete">{{ctx.Locale.Tr "settings.delete_current_avatar"}}</button>
|
||||||
|
@ -40,8 +40,7 @@
|
|||||||
<form class="ui form" action="{{.Link}}/avatar" method="post" enctype="multipart/form-data">
|
<form class="ui form" action="{{.Link}}/avatar" method="post" enctype="multipart/form-data">
|
||||||
{{.CsrfTokenHtml}}
|
{{.CsrfTokenHtml}}
|
||||||
<div class="inline field">
|
<div class="inline field">
|
||||||
<label for="avatar">{{ctx.Locale.Tr "settings.choose_new_avatar"}}</label>
|
{{template "shared/avatar_upload_crop" dict "LabelText" (ctx.Locale.Tr "settings.choose_new_avatar")}}
|
||||||
<input name="avatar" type="file" accept="image/png,image/jpeg,image/gif,image/webp">
|
|
||||||
</div>
|
</div>
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<button class="ui primary button">{{ctx.Locale.Tr "settings.update_avatar"}}</button>
|
<button class="ui primary button">{{ctx.Locale.Tr "settings.update_avatar"}}</button>
|
||||||
|
8
templates/shared/avatar_upload_crop.tmpl
Normal file
8
templates/shared/avatar_upload_crop.tmpl
Normal file
@ -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>
|
@ -124,13 +124,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="inline field tw-pl-4">
|
<div class="inline field tw-pl-4">
|
||||||
<label for="new-avatar">{{ctx.Locale.Tr "settings.choose_new_avatar"}}</label>
|
{{template "shared/avatar_upload_crop" dict "LabelText" (ctx.Locale.Tr "settings.choose_new_avatar")}}
|
||||||
<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>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="field">
|
<div class="field">
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
@import "cropperjs/dist/cropper.css";
|
@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-width: 400px;
|
||||||
max-height: 400px;
|
max-height: 400px;
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
import $ from 'jquery';
|
import $ from 'jquery';
|
||||||
import {checkAppUrl} from '../common-page.ts';
|
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 {POST} from '../../modules/fetch.ts';
|
||||||
|
import {initAvatarUploaderWithCropper} from '../comp/Cropper.ts';
|
||||||
|
|
||||||
const {appSubUrl} = window.config;
|
const {appSubUrl} = window.config;
|
||||||
|
|
||||||
@ -258,4 +259,6 @@ export function initAdminCommon(): void {
|
|||||||
window.location.href = this.getAttribute('data-redirect');
|
window.location.href = this.getAttribute('data-redirect');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
queryElems(document, '.avatar-file-with-cropper', initAvatarUploaderWithCropper);
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import {initCompLabelEdit} from './comp/LabelEdit.ts';
|
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() {
|
export function initCommonOrganization() {
|
||||||
if (!document.querySelectorAll('.organization').length) {
|
if (!document.querySelectorAll('.organization').length) {
|
||||||
@ -13,4 +14,6 @@ export function initCommonOrganization() {
|
|||||||
|
|
||||||
// Labels
|
// Labels
|
||||||
initCompLabelEdit('.page-content.organization.settings.labels');
|
initCompLabelEdit('.page-content.organization.settings.labels');
|
||||||
|
|
||||||
|
queryElems(document, '.avatar-file-with-cropper', initAvatarUploaderWithCropper);
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@ type CropperOpts = {
|
|||||||
fileInput: HTMLInputElement,
|
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');
|
const {default: Cropper} = await import(/* webpackChunkName: "cropperjs" */'cropperjs');
|
||||||
let currentFileName = '';
|
let currentFileName = '';
|
||||||
let currentFileLastModified = 0;
|
let currentFileLastModified = 0;
|
||||||
@ -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,6 +3,7 @@ import {minimatch} from 'minimatch';
|
|||||||
import {createMonaco} from './codeeditor.ts';
|
import {createMonaco} from './codeeditor.ts';
|
||||||
import {onInputDebounce, queryElems, toggleElem} from '../utils/dom.ts';
|
import {onInputDebounce, queryElems, toggleElem} from '../utils/dom.ts';
|
||||||
import {POST} from '../modules/fetch.ts';
|
import {POST} from '../modules/fetch.ts';
|
||||||
|
import {initAvatarUploaderWithCropper} from './comp/Cropper.ts';
|
||||||
import {initRepoSettingsBranchesDrag} from './repo-settings-branches.ts';
|
import {initRepoSettingsBranchesDrag} from './repo-settings-branches.ts';
|
||||||
|
|
||||||
const {appSubUrl, csrfToken} = window.config;
|
const {appSubUrl, csrfToken} = window.config;
|
||||||
@ -156,4 +157,6 @@ export function initRepoSettings() {
|
|||||||
initRepoSettingsSearchTeamBox();
|
initRepoSettingsSearchTeamBox();
|
||||||
initRepoSettingsGitHook();
|
initRepoSettingsGitHook();
|
||||||
initRepoSettingsBranchesDrag();
|
initRepoSettingsBranchesDrag();
|
||||||
|
|
||||||
|
queryElems(document, '.avatar-file-with-cropper', initAvatarUploaderWithCropper);
|
||||||
}
|
}
|
||||||
|
@ -1,17 +1,10 @@
|
|||||||
import {hideElem, showElem} from '../utils/dom.ts';
|
import {hideElem, queryElems, showElem} from '../utils/dom.ts';
|
||||||
import {initCompCropper} from './comp/Cropper.ts';
|
import {initAvatarUploaderWithCropper} 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});
|
|
||||||
}
|
|
||||||
|
|
||||||
export function initUserSettings() {
|
export function initUserSettings() {
|
||||||
if (!document.querySelector('.user.settings.profile')) return;
|
if (!document.querySelector('.user.settings.profile')) return;
|
||||||
|
|
||||||
initUserSettingsAvatarCropper();
|
queryElems(document, '.avatar-file-with-cropper', initAvatarUploaderWithCropper);
|
||||||
|
|
||||||
const usernameInput = document.querySelector<HTMLInputElement>('#username');
|
const usernameInput = document.querySelector<HTMLInputElement>('#username');
|
||||||
if (!usernameInput) return;
|
if (!usernameInput) return;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user