diff --git a/locales/index.d.ts b/locales/index.d.ts
index 9e89216fcc..6b76ed724a 100644
--- a/locales/index.d.ts
+++ b/locales/index.d.ts
@@ -12081,6 +12081,10 @@ export interface Locale extends ILocale {
* 画像
*/
"image": string;
+ /**
+ * 高度
+ */
+ "advanced": string;
};
"_imageEffector": {
/**
diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml
index 46ad18172d..17168a0bcf 100644
--- a/locales/ja-JP.yml
+++ b/locales/ja-JP.yml
@@ -3235,6 +3235,7 @@ _watermarkEditor:
position: "位置"
type: "タイプ"
image: "画像"
+ advanced: "高度"
_imageEffector:
title: "エフェクト"
diff --git a/packages/frontend/src/components/MkWatermarkEditorDialog.vue b/packages/frontend/src/components/MkWatermarkEditorDialog.vue
index 58cf6db73f..e5c93abfc9 100644
--- a/packages/frontend/src/components/MkWatermarkEditorDialog.vue
+++ b/packages/frontend/src/components/MkWatermarkEditorDialog.vue
@@ -30,13 +30,34 @@ SPDX-License-Identifier: AGPL-3.0-only
-
+
+ {{ i18n.ts._watermarkEditor.type }}
+
-
+
+
+
+
+
+
+ {{ i18n.ts._watermarkEditor.text }}
+ {{ i18n.ts._watermarkEditor.image }}
+
+
+ {{ i18n.ts.remove }}
+
+
+
+
+
+
+
@@ -53,7 +74,7 @@ import { i18n } from '@/i18n.js';
import MkModalWindow from '@/components/MkModalWindow.vue';
import MkSelect from '@/components/MkSelect.vue';
import MkButton from '@/components/MkButton.vue';
-import MkInput from '@/components/MkInput.vue';
+import MkFolder from '@/components/MkFolder.vue';
import XLayer from '@/components/MkWatermarkEditorDialog.Layer.vue';
import * as os from '@/os.js';
import { deepClone } from '@/utility/clone.js';
@@ -61,15 +82,8 @@ import { ensureSignin } from '@/i.js';
const $i = ensureSignin();
-const props = defineProps<{
- preset?: WatermarkPreset | null;
- image?: File | null;
-}>();
-
-const preset = reactive(deepClone(props.preset) ?? {
- id: uuid(),
- name: '',
- layers: [{
+function createTextLayer(): WatermarkPreset['layers'][number] {
+ return {
id: uuid(),
type: 'text',
text: `(c) @${$i.username}`,
@@ -77,8 +91,33 @@ const preset = reactive(deepClone(props.preset) ?? {
scale: 0.3,
opacity: 0.75,
repeat: false,
- }],
-} satisfies WatermarkPreset);
+ };
+}
+
+function createImageLayer(): WatermarkPreset['layers'][number] {
+ return {
+ id: uuid(),
+ type: 'image',
+ imageId: null,
+ imageUrl: null,
+ align: { x: 'right', y: 'bottom' },
+ scale: 0.3,
+ opacity: 0.75,
+ repeat: false,
+ cover: false,
+ };
+}
+
+const props = defineProps<{
+ preset?: WatermarkPreset | null;
+ image?: File | null;
+}>();
+
+const preset = reactive(deepClone(props.preset) ?? {
+ id: uuid(),
+ name: '',
+ layers: [createTextLayer()],
+});
const emit = defineEmits<{
(ev: 'ok', preset: WatermarkPreset): void;
@@ -98,29 +137,14 @@ async function cancel() {
dialog.value?.close();
}
-const type = ref(preset.layers[0].type);
+const type = ref(preset.layers.length > 1 ? 'advanced' : preset.layers[0].type);
watch(type, () => {
if (type.value === 'text') {
- preset.layers = [{
- id: uuid(),
- type: 'text',
- text: `(c) @${$i.username}`,
- align: { x: 'right', y: 'bottom' },
- scale: 0.3,
- opacity: 0.75,
- repeat: false,
- }];
+ preset.layers = [createTextLayer()];
} else if (type.value === 'image') {
- preset.layers = [{
- id: uuid(),
- type: 'image',
- imageId: null,
- imageUrl: null,
- align: { x: 'right', y: 'bottom' },
- scale: 0.3,
- opacity: 0.75,
- repeat: false,
- }];
+ preset.layers = [createImageLayer()];
+ } else if (type.value === 'advanced') {
+ // nop
}
});
@@ -241,6 +265,24 @@ async function save() {
emit('ok', preset);
}
+
+function addLayer(ev: MouseEvent) {
+ os.popupMenu([{
+ text: i18n.ts._watermarkEditor.text,
+ action: () => {
+ preset.layers.push(createTextLayer());
+ },
+ }, {
+ text: i18n.ts._watermarkEditor.image,
+ action: () => {
+ preset.layers.push(createImageLayer());
+ },
+ }], ev.currentTarget ?? ev.target);
+}
+
+function removeLayer(layer: WatermarkPreset['layers'][number]) {
+ preset.layers = preset.layers.filter(l => l.id !== layer.id);
+}