Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow cropping an avatar before setting it #32565

Merged
merged 32 commits into from
Nov 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
12bfbf7
Fixed #31990
kerwin612 Nov 19, 2024
6628d67
Update profile.tmpl
kerwin612 Nov 19, 2024
0e1bb40
Merge branch 'main' into patch-17
kerwin612 Nov 20, 2024
dca4bb1
Merge branch 'main' into patch-17
kerwin612 Nov 20, 2024
c715200
Merge branch 'main' into patch-17
kerwin612 Nov 20, 2024
8863e92
code optimization
kerwin612 Nov 20, 2024
bfdb076
code optimization
kerwin612 Nov 20, 2024
651ee60
merge remote
kerwin612 Nov 20, 2024
19791a4
code optimization
kerwin612 Nov 20, 2024
6124e0f
Update locale_en-US.ini
kerwin612 Nov 20, 2024
c6919bb
fixed lint error
kerwin612 Nov 20, 2024
0b3b900
Merge branch 'main' into patch-17
kerwin612 Nov 21, 2024
e6b3a3f
Update web_src/js/features/comp/Cropper.ts
kerwin612 Nov 21, 2024
36945d7
Update web_src/js/features/comp/Cropper.ts
kerwin612 Nov 21, 2024
692fcff
Update web_src/js/features/comp/Cropper.ts
kerwin612 Nov 21, 2024
cd598bf
code optimization
kerwin612 Nov 21, 2024
50a4ceb
Merge branch 'main' into patch-17
kerwin612 Nov 25, 2024
53e9c63
Merge branch 'main' into patch-17
kerwin612 Nov 26, 2024
b64b368
Merge branch 'main' into patch-17
kerwin612 Nov 27, 2024
4d81186
Merge branch 'main' into patch-17
kerwin612 Nov 27, 2024
36cf69a
Remove CSS nesting
kerwin612 Nov 27, 2024
132f1a4
Remove global init
kerwin612 Nov 27, 2024
ea2a23c
Optimize the styling for mobile devices
kerwin612 Nov 27, 2024
5f893c3
improve
wxiaoguang Nov 27, 2024
08d4c92
Update web_src/js/features/comp/Cropper.ts
kerwin612 Nov 27, 2024
4fc5a8d
Update web_src/js/features/comp/Cropper.ts
kerwin612 Nov 27, 2024
9d1513b
rename a repo init function by the way and fix ts error
wxiaoguang Nov 27, 2024
82d0e9d
Update options/locale/locale_en-US.ini
kerwin612 Nov 28, 2024
55e06c1
Update web_src/js/features/user-settings.ts
kerwin612 Nov 28, 2024
57aecec
Merge branch 'main' into patch-17
kerwin612 Nov 28, 2024
7f49bb9
Revert 55e06c19b0ddb6ab8310fb8fcc36c7ef50bcc8a1
kerwin612 Nov 28, 2024
bff1595
Merge branch 'main' into patch-17
GiteaBot Nov 28, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions options/locale/locale_en-US.ini
Original file line number Diff line number Diff line change
Expand Up @@ -765,6 +765,7 @@ uploaded_avatar_not_a_image = The uploaded file is not an image.
uploaded_avatar_is_too_big = The uploaded file size (%d KiB) exceeds the maximum size (%d KiB).
update_avatar_success = Your avatar has been updated.
update_user_avatar_success = The user's avatar has been updated.
cropper_prompt = You can edit the image before saving. The edited image will be saved as PNG.

change_password = Update Password
old_password = Current Password
Expand Down
7 changes: 7 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
"chartjs-adapter-dayjs-4": "1.0.4",
"chartjs-plugin-zoom": "2.0.1",
"clippie": "4.1.3",
"cropperjs": "1.6.2",
"css-loader": "7.1.2",
"dayjs": "1.11.13",
"dropzone": "6.0.0-beta.2",
Expand Down
5 changes: 5 additions & 0 deletions templates/user/settings/profile.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,11 @@
<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 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
6 changes: 6 additions & 0 deletions web_src/css/features/cropper.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
@import "cropperjs/dist/cropper.css";

.page-content.user.profile .cropper-panel .cropper-wrapper {
max-width: 400px;
max-height: 400px;
}
kerwin612 marked this conversation as resolved.
Show resolved Hide resolved
1 change: 1 addition & 0 deletions web_src/css/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
@import "./features/codeeditor.css";
@import "./features/projects.css";
@import "./features/tribute.css";
@import "./features/cropper.css";
@import "./features/console.css";

@import "./markup/content.css";
Expand Down
40 changes: 40 additions & 0 deletions web_src/js/features/comp/Cropper.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import {showElem} from '../../utils/dom.ts';

type CropperOpts = {
container: HTMLElement,
imageSource: HTMLImageElement,
fileInput: HTMLInputElement,
}

export async function initCompCropper({container, fileInput, imageSource}: CropperOpts) {
const {default: Cropper} = await import(/* webpackChunkName: "cropperjs" */'cropperjs');
let currentFileName = '';
let currentFileLastModified = 0;
const cropper = new Cropper(imageSource, {
aspectRatio: 1,
viewMode: 2,
autoCrop: false,
crop() {
const canvas = cropper.getCroppedCanvas();
canvas.toBlob((blob) => {
const croppedFileName = currentFileName.replace(/\.[^.]{3,4}$/, '.png');
const croppedFile = new File([blob], croppedFileName, {type: 'image/png', lastModified: currentFileLastModified});
const dataTransfer = new DataTransfer();
dataTransfer.items.add(croppedFile);
fileInput.files = dataTransfer.files;
});
},
});

fileInput.addEventListener('input', (e: Event & {target: HTMLInputElement}) => {
const files = e.target.files;
if (files?.length > 0) {
currentFileName = files[0].name;
currentFileLastModified = files[0].lastModified;
const fileURL = URL.createObjectURL(files[0]);
imageSource.src = fileURL;
cropper.replace(fileURL);
showElem(container);
}
});
}
8 changes: 4 additions & 4 deletions web_src/js/features/repo-settings-branches.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {beforeEach, describe, expect, test, vi} from 'vitest';
import {initRepoBranchesSettings} from './repo-settings-branches.ts';
import {initRepoSettingsBranchesDrag} from './repo-settings-branches.ts';
import {POST} from '../modules/fetch.ts';
import {createSortable} from '../modules/sortable.ts';

Expand Down Expand Up @@ -31,7 +31,7 @@ describe('Repository Branch Settings', () => {
});

test('should initialize sortable for protected branches list', () => {
initRepoBranchesSettings();
initRepoSettingsBranchesDrag();

expect(createSortable).toHaveBeenCalledWith(
document.querySelector('#protected-branches-list'),
Expand All @@ -45,7 +45,7 @@ describe('Repository Branch Settings', () => {
test('should not initialize if protected branches list is not present', () => {
document.body.innerHTML = '';

initRepoBranchesSettings();
initRepoSettingsBranchesDrag();

expect(createSortable).not.toHaveBeenCalled();
});
Expand All @@ -59,7 +59,7 @@ describe('Repository Branch Settings', () => {
return {destroy: vi.fn()};
});

initRepoBranchesSettings();
initRepoSettingsBranchesDrag();

expect(POST).toHaveBeenCalledWith(
'some/repo/branches/priority',
Expand Down
2 changes: 1 addition & 1 deletion web_src/js/features/repo-settings-branches.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import {POST} from '../modules/fetch.ts';
import {showErrorToast} from '../modules/toast.ts';
import {queryElemChildren} from '../utils/dom.ts';

export function initRepoBranchesSettings() {
export function initRepoSettingsBranchesDrag() {
const protectedBranchesList = document.querySelector('#protected-branches-list');
if (!protectedBranchesList) return;

Expand Down
4 changes: 2 additions & 2 deletions web_src/js/features/repo-settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +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 {initRepoBranchesSettings} from './repo-settings-branches.ts';
import {initRepoSettingsBranchesDrag} from './repo-settings-branches.ts';

const {appSubUrl, csrfToken} = window.config;

Expand Down Expand Up @@ -155,5 +155,5 @@ export function initRepoSettings() {
initRepoSettingsCollaboration();
initRepoSettingsSearchTeamBox();
initRepoSettingsGitHook();
initRepoBranchesSettings();
initRepoSettingsBranchesDrag();
}
12 changes: 11 additions & 1 deletion web_src/js/features/user-settings.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,17 @@
import {hideElem, showElem} from '../utils/dom.ts';
import {initCompCropper} from './comp/Cropper.ts';

function initUserSettingsAvatarCropper() {
const fileInput = document.querySelector<HTMLInputElement>('#new-avatar');
delvh marked this conversation as resolved.
Show resolved Hide resolved
const container = document.querySelector<HTMLElement>('.user.settings.profile .cropper-panel');
const imageSource = container.querySelector<HTMLImageElement>('.cropper-source');
initCompCropper({container, fileInput, imageSource});
}

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

initUserSettingsAvatarCropper();

const usernameInput = document.querySelector('#username');
if (!usernameInput) return;
Expand Down
2 changes: 1 addition & 1 deletion web_src/js/modules/sortable.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type {SortableOptions, SortableEvent} from 'sortablejs';

export async function createSortable(el: HTMLElement, opts: {handle?: string} & SortableOptions = {}) {
export async function createSortable(el: Element, opts: {handle?: string} & SortableOptions = {}) {
// @ts-expect-error: wrong type derived by typescript
const {Sortable} = await import(/* webpackChunkName: "sortablejs" */'sortablejs');

Expand Down
Loading