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
- + + + - +
+ +
+
+ + + + + + + + +
@@ -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); +}