Skip to content

Commit 24f5331

Browse files
authored
Merge branch 'main' into rb/validate-redirect-uri
2 parents 3344494 + 68d9f36 commit 24f5331

File tree

12 files changed

+80
-9
lines changed

12 files changed

+80
-9
lines changed

options/locale/locale_en-US.ini

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -765,6 +765,7 @@ uploaded_avatar_not_a_image = The uploaded file is not an image.
765765
uploaded_avatar_is_too_big = The uploaded file size (%d KiB) exceeds the maximum size (%d KiB).
766766
update_avatar_success = Your avatar has been updated.
767767
update_user_avatar_success = The user's avatar has been updated.
768+
cropper_prompt = You can edit the image before saving. The edited image will be saved as PNG.
768769

769770
change_password = Update Password
770771
old_password = Current Password

package-lock.json

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
"chartjs-adapter-dayjs-4": "1.0.4",
2222
"chartjs-plugin-zoom": "2.0.1",
2323
"clippie": "4.1.3",
24+
"cropperjs": "1.6.2",
2425
"css-loader": "7.1.2",
2526
"dayjs": "1.11.13",
2627
"dropzone": "6.0.0-beta.2",

templates/user/settings/profile.tmpl

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,11 @@
127127
<input id="new-avatar" name="avatar" type="file" accept="image/png,image/jpeg,image/gif,image/webp">
128128
</div>
129129

130+
<div class="field tw-pl-4 cropper-panel tw-hidden">
131+
<div>{{ctx.Locale.Tr "settings.cropper_prompt"}}</div>
132+
<div class="cropper-wrapper"><img class="cropper-source" src alt></div>
133+
</div>
134+
130135
<div class="field">
131136
<button class="ui primary button">{{ctx.Locale.Tr "settings.update_avatar"}}</button>
132137
<button class="ui red button link-action" data-url="{{.Link}}/avatar/delete">{{ctx.Locale.Tr "settings.delete_current_avatar"}}</button>

web_src/css/features/cropper.css

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
@import "cropperjs/dist/cropper.css";
2+
3+
.page-content.user.profile .cropper-panel .cropper-wrapper {
4+
max-width: 400px;
5+
max-height: 400px;
6+
}

web_src/css/index.css

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
@import "./features/codeeditor.css";
4141
@import "./features/projects.css";
4242
@import "./features/tribute.css";
43+
@import "./features/cropper.css";
4344
@import "./features/console.css";
4445

4546
@import "./markup/content.css";
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import {showElem} from '../../utils/dom.ts';
2+
3+
type CropperOpts = {
4+
container: HTMLElement,
5+
imageSource: HTMLImageElement,
6+
fileInput: HTMLInputElement,
7+
}
8+
9+
export async function initCompCropper({container, fileInput, imageSource}: CropperOpts) {
10+
const {default: Cropper} = await import(/* webpackChunkName: "cropperjs" */'cropperjs');
11+
let currentFileName = '';
12+
let currentFileLastModified = 0;
13+
const cropper = new Cropper(imageSource, {
14+
aspectRatio: 1,
15+
viewMode: 2,
16+
autoCrop: false,
17+
crop() {
18+
const canvas = cropper.getCroppedCanvas();
19+
canvas.toBlob((blob) => {
20+
const croppedFileName = currentFileName.replace(/\.[^.]{3,4}$/, '.png');
21+
const croppedFile = new File([blob], croppedFileName, {type: 'image/png', lastModified: currentFileLastModified});
22+
const dataTransfer = new DataTransfer();
23+
dataTransfer.items.add(croppedFile);
24+
fileInput.files = dataTransfer.files;
25+
});
26+
},
27+
});
28+
29+
fileInput.addEventListener('input', (e: Event & {target: HTMLInputElement}) => {
30+
const files = e.target.files;
31+
if (files?.length > 0) {
32+
currentFileName = files[0].name;
33+
currentFileLastModified = files[0].lastModified;
34+
const fileURL = URL.createObjectURL(files[0]);
35+
imageSource.src = fileURL;
36+
cropper.replace(fileURL);
37+
showElem(container);
38+
}
39+
});
40+
}

web_src/js/features/repo-settings-branches.test.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import {beforeEach, describe, expect, test, vi} from 'vitest';
2-
import {initRepoBranchesSettings} from './repo-settings-branches.ts';
2+
import {initRepoSettingsBranchesDrag} from './repo-settings-branches.ts';
33
import {POST} from '../modules/fetch.ts';
44
import {createSortable} from '../modules/sortable.ts';
55

@@ -31,7 +31,7 @@ describe('Repository Branch Settings', () => {
3131
});
3232

3333
test('should initialize sortable for protected branches list', () => {
34-
initRepoBranchesSettings();
34+
initRepoSettingsBranchesDrag();
3535

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

48-
initRepoBranchesSettings();
48+
initRepoSettingsBranchesDrag();
4949

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

62-
initRepoBranchesSettings();
62+
initRepoSettingsBranchesDrag();
6363

6464
expect(POST).toHaveBeenCalledWith(
6565
'some/repo/branches/priority',

web_src/js/features/repo-settings-branches.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import {POST} from '../modules/fetch.ts';
33
import {showErrorToast} from '../modules/toast.ts';
44
import {queryElemChildren} from '../utils/dom.ts';
55

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

web_src/js/features/repo-settings.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import {minimatch} from 'minimatch';
33
import {createMonaco} from './codeeditor.ts';
44
import {onInputDebounce, queryElems, toggleElem} from '../utils/dom.ts';
55
import {POST} from '../modules/fetch.ts';
6-
import {initRepoBranchesSettings} from './repo-settings-branches.ts';
6+
import {initRepoSettingsBranchesDrag} from './repo-settings-branches.ts';
77

88
const {appSubUrl, csrfToken} = window.config;
99

@@ -155,5 +155,5 @@ export function initRepoSettings() {
155155
initRepoSettingsCollaboration();
156156
initRepoSettingsSearchTeamBox();
157157
initRepoSettingsGitHook();
158-
initRepoBranchesSettings();
158+
initRepoSettingsBranchesDrag();
159159
}

0 commit comments

Comments
 (0)