From 7997ecb8cc41a91f7f5a70f8b7a9684941fc1242 Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Tue, 13 May 2025 18:45:27 +0900 Subject: [PATCH] wip --- .../src/components/MkCropperDialog.vue | 6 ++-- .../src/components/MkUploaderDialog.vue | 30 +++++++++++++++---- packages/frontend/src/os.ts | 2 +- 3 files changed, 29 insertions(+), 9 deletions(-) diff --git a/packages/frontend/src/components/MkCropperDialog.vue b/packages/frontend/src/components/MkCropperDialog.vue index 5c3ca4ba51..7f592fba79 100644 --- a/packages/frontend/src/components/MkCropperDialog.vue +++ b/packages/frontend/src/components/MkCropperDialog.vue @@ -39,7 +39,7 @@ import { i18n } from '@/i18n.js'; const props = defineProps<{ imageFile: File | Blob; - aspectRatio: number; + aspectRatio: number | null; uploadFolder?: string | null; }>(); @@ -99,8 +99,8 @@ onMounted(() => { const selection = cropper.getCropperSelection()!; selection.themeColor = tinycolor(computedStyle.getPropertyValue('--MI_THEME-accent')).toHexString(); - selection.aspectRatio = props.aspectRatio; - selection.initialAspectRatio = props.aspectRatio; + if (props.aspectRatio != null) selection.aspectRatio = props.aspectRatio; + selection.initialAspectRatio = props.aspectRatio ?? 1; selection.outlined = true; window.setTimeout(() => { diff --git a/packages/frontend/src/components/MkUploaderDialog.vue b/packages/frontend/src/components/MkUploaderDialog.vue index a1119b947f..aa1ce2e2c2 100644 --- a/packages/frontend/src/components/MkUploaderDialog.vue +++ b/packages/frontend/src/components/MkUploaderDialog.vue @@ -96,14 +96,18 @@ import { isWebpSupported } from '@/utility/isWebpSupported.js'; import { uploadFile } from '@/utility/upload.js'; import * as os from '@/os.js'; -const $i = ensureSignin(); - -const compressionSupportedTypes = [ +const COMPRESSION_SUPPORTED_TYPES = [ 'image/jpeg', 'image/png', 'image/webp', 'image/svg+xml', -] as const; +]; + +const CROPPING_SUPPORTED_TYPES = [ + 'image/jpeg', + 'image/png', + 'image/webp', +]; const mimeTypeMap = { 'image/webp': 'webp', @@ -211,6 +215,21 @@ async function done() { function showMenu(ev: MouseEvent, item: typeof items.value[0]) { const menu: MenuItem[] = []; + if (CROPPING_SUPPORTED_TYPES.includes(item.file.type) && !item.waiting && !item.uploading && !item.uploaded) { + menu.push({ + icon: 'ti ti-crop', + text: i18n.ts.cropImage, + action: async () => { + const cropped = await os.cropImageFile(item.file, { aspectRatio: null }); + items.value.splice(items.value.indexOf(item), 1, { + ...item, + file: markRaw(cropped), + thumbnail: window.URL.createObjectURL(cropped), + }); + }, + }); + } + if (!item.waiting && !item.uploading && !item.uploaded) { menu.push({ icon: 'ti ti-x', @@ -231,7 +250,7 @@ async function upload() { // エラーハンドリングなどを考慮してシ item.waiting = true; item.uploadFailed = false; - const shouldCompress = item.compressedImage == null && compressionLevel.value !== 0 && compressionSettings.value && compressionSupportedTypes.includes(item.file.type) && !(await isAnimated(item.file)); + const shouldCompress = item.compressedImage == null && compressionLevel.value !== 0 && compressionSettings.value && COMPRESSION_SUPPORTED_TYPES.includes(item.file.type) && !(await isAnimated(item.file)); if (shouldCompress) { const config = { @@ -275,6 +294,7 @@ async function upload() { // エラーハンドリングなどを考慮してシ throw err; }).finally(() => { item.uploading = false; + item.waiting = false; }); item.uploaded = driveFile; diff --git a/packages/frontend/src/os.ts b/packages/frontend/src/os.ts index 3b6887a169..652dc52365 100644 --- a/packages/frontend/src/os.ts +++ b/packages/frontend/src/os.ts @@ -656,7 +656,7 @@ export async function pickEmoji(src: HTMLElement, opts: ComponentProps { return new Promise(resolve => { const { dispose } = popup(defineAsyncComponent(() => import('@/components/MkCropperDialog.vue')), {