diff --git a/packages/frontend/src/components/MkWatermarkEditorDialog.vue b/packages/frontend/src/components/MkWatermarkEditorDialog.vue index 30b73245cd..4e5f1cd503 100644 --- a/packages/frontend/src/components/MkWatermarkEditorDialog.vue +++ b/packages/frontend/src/components/MkWatermarkEditorDialog.vue @@ -114,9 +114,11 @@ import * as os from '@/os.js'; import { defaultStore } from '@/store.js'; import { i18n } from '@/i18n.js'; import { selectFile } from '@/scripts/select-file.js'; -import { applyWatermark, canPreview, WatermarkConfig } from '@/scripts/watermark.js'; +import { applyWatermark, canPreview } from '@/scripts/watermark.js'; import { misskeyApi } from '@/scripts/misskey-api.js'; +import type { WatermarkUserConfig } from '@/scripts/watermark.js'; + const emit = defineEmits<{ (ev: 'ok'): void; (ev: 'cancel'): void; @@ -134,7 +136,7 @@ function cancel() { //#region 設定 const useWatermark = computed(defaultStore.makeGetterSetter('useWatermark')); -const watermarkConfig = ref(defaultStore.state.watermarkConfig ?? { +const watermarkConfig = ref(defaultStore.state.watermarkConfig ?? { opacity: 0.2, repeat: true, rotate: 15, @@ -144,7 +146,8 @@ const anchor = computed({ get: () => watermarkConfig.value != null && 'anchor' in watermarkConfig.value ? watermarkConfig.value.anchor : null, set: (v) => { if (v == null || watermarkConfig.value?.repeat === true) { - watermarkConfig.value = { ...watermarkConfig.value, anchor: undefined }; + const { anchor, ...newValue } = watermarkConfig.value; + watermarkConfig.value = newValue; } else if (watermarkConfig.value?.repeat === false) { watermarkConfig.value = { ...watermarkConfig.value, anchor: v }; } @@ -167,7 +170,7 @@ const rotate = computed({ set: (v) => watermarkConfig.value = { ...watermarkConfig.value, rotate: v }, }); const preserveBoundingRect = computed({ - get: () => !('noBoundingBoxExpansion' in watermarkConfig.value ? watermarkConfig.value?.noBoundingBoxExpansion ?? false : false), + get: () => watermarkConfig.value?.noBoundingBoxExpansion ?? false, set: (v) => watermarkConfig.value = { ...watermarkConfig.value, noBoundingBoxExpansion: !v }, }); diff --git a/packages/frontend/src/scripts/watermark.ts b/packages/frontend/src/scripts/watermark.ts index 101007ce92..d4adaa82ca 100644 --- a/packages/frontend/src/scripts/watermark.ts +++ b/packages/frontend/src/scripts/watermark.ts @@ -20,6 +20,48 @@ export const watermarkAnchor = [ export type WatermarkAnchor = typeof watermarkAnchor[number]; +/** + * Storeへの保存やエディタで使用するための、条件別のプロパティを排除したバージョンの型。 + * `canPreview`で`WatermarkConfig`に変換可能かどうかを判定できる。 + * + * どちらかの型を変更したら、もう一方も変更すること。 + */ +export type WatermarkUserConfig = { + /** ドライブファイルのID */ + fileId?: string; + /** 画像URL */ + fileUrl?: string; + /** 親画像に対するウォーターマークの幅比率。ない場合は1。親画像が縦長の場合は幅の比率として、横長の場合は高さ比率として使用される */ + sizeRatio?: number; + /** 透明度 */ + opacity?: number; + /** 回転角度(度数) */ + rotate?: number; + /** パディング */ + padding?: { + top: number; + right: number; + bottom: number; + left: number; + }; + + /** 繰り返し */ + repeat?: boolean; + /** 画像の始祖点。repeatがtrueの場合は使用されないが、それ以外の場合は必須 */ + anchor?: WatermarkAnchor; + /** 回転の際に領域を自動で拡張するかどうか。repeatがtrueの場合は使用されない */ + noBoundingBoxExpansion?: boolean; + + /** @internal */ + __bypassMediaProxy?: boolean; +}; + +/** + * Canvasへの描画などで使用できる、動作に必要な値を網羅した型。 + * `WatermarkUserConfig`を`canPreview`でアサートすることで型を変換できる。 + * + * どちらかの型を変更したら、もう一方も変更すること。 + */ export type WatermarkConfig = { /** ドライブファイルのID */ fileId?: string; @@ -56,7 +98,7 @@ export type WatermarkConfig = { /** * プレビューに必要な値が全部揃っているかどうかを判定する */ -export function canPreview(config: Partial | null): config is WatermarkConfig { +export function canPreview(config: Partial | null): config is WatermarkConfig { return ( config != null && (config.fileUrl != null || config.fileId != null) && diff --git a/packages/frontend/src/store.ts b/packages/frontend/src/store.ts index 5cbb33e978..cf2d836af7 100644 --- a/packages/frontend/src/store.ts +++ b/packages/frontend/src/store.ts @@ -9,7 +9,7 @@ import { hemisphere } from '@@/js/intl-const.js'; import lightTheme from '@@/themes/l-light.json5'; import darkTheme from '@@/themes/d-green-lime.json5'; import type { SoundType } from '@/scripts/sound.js'; -import type { WatermarkConfig } from '@/scripts/watermark.js'; +import type { WatermarkUserConfig } from '@/scripts/watermark.js'; import { DEFAULT_DEVICE_KIND, type DeviceKind } from '@/scripts/device-kind.js'; import { miLocalStorage } from '@/local-storage.js'; import { Storage } from '@/pizzax.js'; @@ -481,7 +481,7 @@ export const defaultStore = markRaw(new Storage('base', { }, watermarkConfig: { where: 'account', - default: null as WatermarkConfig | null, + default: null as WatermarkUserConfig | null, }, sound_masterVolume: {