Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
d2371a9
enhance: refine uploadFile
kakkokari-gtyih May 24, 2025
d679d62
fix: missing locale
kakkokari-gtyih Jun 3, 2025
df315b1
refactor: harden types
kakkokari-gtyih Jun 3, 2025
a1ab2fa
refactor: シェーダーファイルをlazy-loadingできるように
kakkokari-gtyih Jun 3, 2025
66bffc3
fix(frontend): omit console.log in production environment
kakkokari-gtyih Jun 3, 2025
afcc37d
fix: glslのバージョン表記は最初の行になければならない
kakkokari-gtyih Jun 3, 2025
e06f37a
fix: シェーダーの読み込みが完了してからレンダリングを行うように
kakkokari-gtyih Jun 3, 2025
faefc9b
fix merge failure
kakkokari-gtyih Jun 3, 2025
609a2cb
fix: ウォーターマークのプリセットがない場合にdividerが2重に表示される問題を修正
kakkokari-gtyih Jun 3, 2025
86b4ae3
fix: アップローダーダイアログの機能設定でウォーターマークが無効な場合でもデフォルトのプリセットが適用されてしまう問題を修正
kakkokari-gtyih Jun 4, 2025
9e4a408
fix lint
kakkokari-gtyih Jun 4, 2025
c921aa5
Revert "fix: シェーダーの読み込みが完了してからレンダリングを行うように"
kakkokari-gtyih Jun 4, 2025
850a9ae
Revert "fix: glslのバージョン表記は最初の行になければならない"
kakkokari-gtyih Jun 4, 2025
4e5df65
Revert "refactor: シェーダーファイルをlazy-loadingできるように"
kakkokari-gtyih Jun 4, 2025
5d87c03
fix: ウォーターマークのFX定義を分ける
kakkokari-gtyih Jun 4, 2025
9d32895
Update packages/frontend/src/components/MkWatermarkEditorDialog.vue
syuilo Jun 4, 2025
e31d163
Update packages/frontend/src/components/MkWatermarkEditorDialog.vue
syuilo Jun 4, 2025
d11aad0
Update packages/frontend/src/components/MkWatermarkEditorDialog.vue
syuilo Jun 4, 2025
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
8 changes: 8 additions & 0 deletions locales/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12049,6 +12049,14 @@ export interface Locale extends ILocale {
* 保存せずに終了しますか?
*/
"quitWithoutSaveConfirm": string;
/**
* このファイルは対応していません
*/
"driveFileTypeWarn": string;
/**
* 画像ファイルを選択してください
*/
"driveFileTypeWarnDescription": string;
/**
* ウォーターマークの編集
*/
Expand Down
2 changes: 2 additions & 0 deletions locales/ja-JP.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3227,6 +3227,8 @@ defaultPreset: "デフォルトのプリセット"
_watermarkEditor:
tip: "画像にクレジット情報などのウォーターマークを追加することができます。"
quitWithoutSaveConfirm: "保存せずに終了しますか?"
driveFileTypeWarn: "このファイルは対応していません"
driveFileTypeWarnDescription: "画像ファイルを選択してください"
title: "ウォーターマークの編集"
cover: "全体に被せる"
repeat: "敷き詰める"
Expand Down
5 changes: 4 additions & 1 deletion packages/frontend/src/components/MkFormDialog.file.vue
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,10 @@ if (props.fileId) {
}

function selectButton(ev: MouseEvent) {
selectFile(ev.currentTarget ?? ev.target).then(async (file) => {
selectFile({
anchorElement: ev.currentTarget ?? ev.target,
multiple: false,
}).then(async (file) => {
if (!file) return;
if (props.validate && !await props.validate(file)) return;

Expand Down
3 changes: 2 additions & 1 deletion packages/frontend/src/components/MkImageEffectorDialog.vue
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ const dialog = useTemplateRef('dialog');
async function cancel() {
if (layers.length > 0) {
const { canceled } = await os.confirm({
type: 'warning',
text: i18n.ts._imageEffector.discardChangesConfirm,
});
if (canceled) return;
Expand Down Expand Up @@ -132,7 +133,7 @@ function onLayerDelete(layer: ImageEffectorLayer) {

const canvasEl = useTemplateRef('canvasEl');

let renderer: ImageEffector | null = null;
let renderer: ImageEffector<typeof FXS> | null = null;
let imageBitmap: ImageBitmap | null = null;

onMounted(async () => {
Expand Down
8 changes: 6 additions & 2 deletions packages/frontend/src/components/MkPostForm.vue
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ import { formatTimeString } from '@/utility/format-time-string.js';
import { Autocomplete } from '@/utility/autocomplete.js';
import * as os from '@/os.js';
import { misskeyApi } from '@/utility/misskey-api.js';
import { selectFiles } from '@/utility/drive.js';
import { selectFile } from '@/utility/drive.js';
import { store } from '@/store.js';
import MkInfo from '@/components/MkInfo.vue';
import { i18n } from '@/i18n.js';
Expand Down Expand Up @@ -437,7 +437,11 @@ function focus() {
function chooseFileFrom(ev) {
if (props.mock) return;

selectFiles(ev.currentTarget ?? ev.target, i18n.ts.attachFile).then(files_ => {
selectFile({
anchorElement: ev.currentTarget ?? ev.target,
multiple: true,
label: i18n.ts.attachFile,
}).then(files_ => {
for (const file of files_) {
files.value.push(file);
}
Expand Down
69 changes: 52 additions & 17 deletions packages/frontend/src/components/MkUploaderDialog.vue
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,16 @@ SPDX-License-Identifier: AGPL-3.0-only
</MkModalWindow>
</template>

<script lang="ts">
export type UploaderDialogFeatures = {
effect?: boolean;
watermark?: boolean;
crop?: boolean;
};
</script>

<script lang="ts" setup>
import { computed, defineAsyncComponent, markRaw, onMounted, onUnmounted, ref, triggerRef, useTemplateRef, watch } from 'vue';
import { computed, markRaw, onMounted, onUnmounted, ref, triggerRef, useTemplateRef, watch } from 'vue';
import * as Misskey from 'misskey-js';
import { genId } from '@/utility/id.js';
import { readAndCompressImage } from '@misskey-dev/browser-image-resizer';
Expand All @@ -91,7 +99,6 @@ import { i18n } from '@/i18n.js';
import { prefer } from '@/preferences.js';
import MkButton from '@/components/MkButton.vue';
import bytes from '@/filters/bytes.js';
import MkSelect from '@/components/MkSelect.vue';
import { isWebpSupported } from '@/utility/isWebpSupported.js';
import { uploadFile, UploadAbortedError } from '@/utility/drive.js';
import * as os from '@/os.js';
Expand Down Expand Up @@ -131,17 +138,26 @@ const props = withDefaults(defineProps<{
files: File[];
folderId?: string | null;
multiple?: boolean;
features?: UploaderDialogFeatures;
}>(), {
multiple: true,
});

const uploaderFeatures = computed<Required<UploaderDialogFeatures>>(() => {
return {
effect: props.features?.effect ?? true,
watermark: props.features?.watermark ?? true,
crop: props.features?.crop ?? true,
};
});

const emit = defineEmits<{
(ev: 'done', driveFiles: Misskey.entities.DriveFile[]): void;
(ev: 'canceled'): void;
(ev: 'closed'): void;
}>();

const items = ref<{
type UploaderItem = {
id: string;
name: string;
uploadName?: string;
Expand All @@ -152,13 +168,15 @@ const items = ref<{
uploaded: Misskey.entities.DriveFile | null;
uploadFailed: boolean;
aborted: boolean;
compressionLevel: number;
compressionLevel: 0 | 1 | 2 | 3;
compressedSize?: number | null;
preprocessedFile?: Blob | null;
file: File;
watermarkPresetId: string | null;
abort?: (() => void) | null;
}[]>([]);
};

const items = ref<UploaderItem[]>([]);

const dialog = useTemplateRef('dialog');

Expand Down Expand Up @@ -252,7 +270,7 @@ async function done() {
dialog.value?.close();
}

function showMenu(ev: MouseEvent, item: typeof items.value[0]) {
function showMenu(ev: MouseEvent, item: UploaderItem) {
const menu: MenuItem[] = [];

menu.push({
Expand All @@ -272,7 +290,13 @@ function showMenu(ev: MouseEvent, item: typeof items.value[0]) {
},
});

if (CROPPING_SUPPORTED_TYPES.includes(item.file.type) && !item.preprocessing && !item.uploading && !item.uploaded) {
if (
uploaderFeatures.value.crop &&
CROPPING_SUPPORTED_TYPES.includes(item.file.type) &&
!item.preprocessing &&
!item.uploading &&
!item.uploaded
) {
menu.push({
icon: 'ti ti-crop',
text: i18n.ts.cropImage,
Expand All @@ -292,7 +316,13 @@ function showMenu(ev: MouseEvent, item: typeof items.value[0]) {
});
}

if (IMAGE_EDITING_SUPPORTED_TYPES.includes(item.file.type) && !item.preprocessing && !item.uploading && !item.uploaded) {
if (
uploaderFeatures.value.effect &&
IMAGE_EDITING_SUPPORTED_TYPES.includes(item.file.type) &&
!item.preprocessing &&
!item.uploading &&
!item.uploaded
) {
menu.push({
icon: 'ti ti-sparkles',
text: i18n.ts._imageEffector.title + ' (BETA)',
Expand All @@ -318,7 +348,13 @@ function showMenu(ev: MouseEvent, item: typeof items.value[0]) {
});
}

if (WATERMARK_SUPPORTED_TYPES.includes(item.file.type) && !item.preprocessing && !item.uploading && !item.uploaded) {
if (
uploaderFeatures.value.watermark &&
WATERMARK_SUPPORTED_TYPES.includes(item.file.type) &&
!item.preprocessing &&
!item.uploading &&
!item.uploaded
) {
function changeWatermarkPreset(presetId: string | null) {
item.watermarkPresetId = presetId;
preprocess(item).then(() => {
Expand All @@ -338,13 +374,13 @@ function showMenu(ev: MouseEvent, item: typeof items.value[0]) {
}, {
type: 'divider',
}, ...prefer.s.watermarkPresets.map(preset => ({
type: 'radioOption',
type: 'radioOption' as const,
text: preset.name,
active: computed(() => item.watermarkPresetId === preset.id),
action: () => changeWatermarkPreset(preset.id),
})), {
type: 'divider',
}, {
})), ...(prefer.s.watermarkPresets.length > 0 ? [{
type: 'divider' as const,
}] : []), {
type: 'button',
icon: 'ti ti-plus',
text: i18n.ts.add,
Expand Down Expand Up @@ -397,8 +433,7 @@ function showMenu(ev: MouseEvent, item: typeof items.value[0]) {
text: i18n.ts.high,
active: computed(() => item.compressionLevel === 3),
action: () => changeCompressionLevel(3),
},
],
}],
});
}

Expand Down Expand Up @@ -590,9 +625,9 @@ function initializeFile(file: File) {
uploaded: null,
uploadFailed: false,
compressionLevel: prefer.s.defaultImageCompressionLevel,
watermarkPresetId: prefer.s.defaultWatermarkPresetId,
watermarkPresetId: uploaderFeatures.value.watermark ? prefer.s.defaultWatermarkPresetId : null,
file: markRaw(file),
};
} satisfies UploaderItem;
items.value.push(item);
preprocess(item).then(() => {
triggerRef(items);
Expand Down
17 changes: 12 additions & 5 deletions packages/frontend/src/components/MkWatermarkEditorDialog.Layer.vue
Original file line number Diff line number Diff line change
Expand Up @@ -262,10 +262,10 @@ SPDX-License-Identifier: AGPL-3.0-only
</template>

<script setup lang="ts">
import { ref, useTemplateRef, watch, onMounted, onUnmounted } from 'vue';
import { ref, onMounted } from 'vue';
import * as Misskey from 'misskey-js';
import type { WatermarkPreset } from '@/utility/watermark.js';
import { i18n } from '@/i18n.js';
import MkSelect from '@/components/MkSelect.vue';
import MkButton from '@/components/MkButton.vue';
import MkInput from '@/components/MkInput.vue';
import MkSwitch from '@/components/MkSwitch.vue';
Expand All @@ -275,11 +275,10 @@ import MkPositionSelector from '@/components/MkPositionSelector.vue';
import * as os from '@/os.js';
import { selectFile } from '@/utility/drive.js';
import { misskeyApi } from '@/utility/misskey-api.js';
import { prefer } from '@/preferences.js';

const layer = defineModel<WatermarkPreset['layers'][number]>('layer', { required: true });

const driveFile = ref();
const driveFile = ref<Misskey.entities.DriveFile | null>(null);
const driveFileError = ref(false);
onMounted(async () => {
if (layer.value.type === 'image' && layer.value.imageId != null) {
Expand All @@ -294,7 +293,15 @@ onMounted(async () => {
});

function chooseFile(ev: MouseEvent) {
selectFile(ev.currentTarget ?? ev.target, i18n.ts.selectFile).then((file) => {
selectFile({
anchorElement: ev.currentTarget ?? ev.target,
multiple: false,
label: i18n.ts.selectFile,
features: {
watermark: false,
},
}).then((file) => {
if (layer.value.type !== 'image') return;
if (!file.type.startsWith('image')) {
os.alert({
type: 'warning',
Expand Down
7 changes: 4 additions & 3 deletions packages/frontend/src/components/MkWatermarkEditorDialog.vue
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ function createStripeLayer(): WatermarkPreset['layers'][number] {
angle: 0.5,
frequency: 10,
threshold: 0.1,
black: false,
color: [1, 1, 1],
opacity: 0.75,
};
}
Expand All @@ -140,7 +140,7 @@ function createPolkadotLayer(): WatermarkPreset['layers'][number] {
majorOpacity: 0.75,
minorOpacity: 0.5,
minorDivisions: 4,
black: false,
color: [1, 1, 1],
opacity: 0.75,
};
}
Expand All @@ -151,7 +151,7 @@ function createCheckerLayer(): WatermarkPreset['layers'][number] {
type: 'checker',
angle: 0.5,
scale: 3,
black: false,
color: [1, 1, 1],
opacity: 0.75,
};
}
Expand All @@ -177,6 +177,7 @@ const dialog = useTemplateRef('dialog');

async function cancel() {
const { canceled } = await os.confirm({
type: 'question',
text: i18n.ts._watermarkEditor.quitWithoutSaveConfirm,
});
if (canceled) return;
Expand Down
3 changes: 3 additions & 0 deletions packages/frontend/src/os.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import type { ComponentProps as CP } from 'vue-component-type-helpers';
import type { Form, GetFormResultType } from '@/utility/form.js';
import type { MenuItem } from '@/types/menu.js';
import type { PostFormProps } from '@/types/post-form.js';
import type { UploaderDialogFeatures } from '@/components/MkUploaderDialog.vue';
import type MkRoleSelectDialog_TypeReferenceOnly from '@/components/MkRoleSelectDialog.vue';
import type MkEmojiPickerDialog_TypeReferenceOnly from '@/components/MkEmojiPickerDialog.vue';
import { misskeyApi } from '@/utility/misskey-api.js';
Expand Down Expand Up @@ -836,6 +837,7 @@ export function launchUploader(
options?: {
folderId?: string | null;
multiple?: boolean;
features?: UploaderDialogFeatures;
},
): Promise<Misskey.entities.DriveFile[]> {
return new Promise(async (res, rej) => {
Expand All @@ -844,6 +846,7 @@ export function launchUploader(
files: markRaw(files),
folderId: options?.folderId,
multiple: options?.multiple,
features: options?.features,
}, {
done: driveFiles => {
if (driveFiles.length === 0) return rej();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,10 @@ function setupGrid(): GridSetting {
{
bindTo: 'url', icon: 'ti-icons', type: 'image', editable: true, width: 'auto', validators: [required],
async customValueEditor(row, col, value, cellElement) {
const file = await selectFile(cellElement);
const file = await selectFile({
anchorElement: cellElement,
multiple: false,
});
gridItems.value[row.index].url = file.url;
gridItems.value[row.index].fileId = file.id;

Expand Down
5 changes: 4 additions & 1 deletion packages/frontend/src/pages/channel-editor.vue
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,10 @@ async function archive() {
}

function setBannerImage(evt) {
selectFile(evt.currentTarget ?? evt.target, null).then(file => {
selectFile({
anchorElement: evt.currentTarget ?? evt.target,
multiple: false,
}).then(file => {
bannerId.value = file.id;
});
}
Expand Down
6 changes: 5 additions & 1 deletion packages/frontend/src/pages/chat/room.form.vue
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,11 @@ function onKeydown(ev: KeyboardEvent) {
}

function chooseFile(ev: MouseEvent) {
selectFile(ev.currentTarget ?? ev.target, i18n.ts.selectFile).then(selectedFile => {
selectFile({
anchorElement: ev.currentTarget ?? ev.target,
multiple: false,
label: i18n.ts.selectFile,
}).then(selectedFile => {
file.value = selectedFile;
});
}
Expand Down
5 changes: 4 additions & 1 deletion packages/frontend/src/pages/custom-emojis-manager.vue
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,10 @@ const menu = (ev: MouseEvent) => {
icon: 'ti ti-upload',
text: i18n.ts.import,
action: async () => {
const file = await selectFile(ev.currentTarget ?? ev.target);
const file = await selectFile({
anchorElement: ev.currentTarget ?? ev.target,
multiple: false,
});
misskeyApi('admin/emoji/import-zip', {
fileId: file.id,
})
Expand Down
Loading
Loading