summaryrefslogtreecommitdiff
path: root/packages/frontend/src/components/MkImageEffectorFxForm.vue
diff options
context:
space:
mode:
authorかっこかり <67428053+kakkokari-gtyih@users.noreply.github.com>2025-08-09 14:11:19 +0900
committerGitHub <noreply@github.com>2025-08-09 14:11:19 +0900
commit785b85ee462ac6f3af416be1d3ed68f3e478118b (patch)
tree81c738be824246664274cd5aca1955e5e9a27f91 /packages/frontend/src/components/MkImageEffectorFxForm.vue
parentfix: カラムの名前が正しくリスト/チャンネルの名前にな... (diff)
downloadmisskey-785b85ee462ac6f3af416be1d3ed68f3e478118b.tar.gz
misskey-785b85ee462ac6f3af416be1d3ed68f3e478118b.tar.bz2
misskey-785b85ee462ac6f3af416be1d3ed68f3e478118b.zip
enhance(frontend): 画像エフェクトのUI改善 (#16191)
* enhance(frontend): 画像エフェクトの改善 * enhance: i18n colorClampAdvanced * fix: missing translation * enhance: i18n blockNoise * fix lint * fix: narrow down fx defs types * fix * fix: watermark用エフェクトは別で定義し直す * fix lint * ImageEffectorをwatermarkに隠蔽 * watermark関連の定義を完全に分離 * refactor * fix * ぼかし効果 -> スムージング * refactor: remove unnecessary `as const` * Update Changelog
Diffstat (limited to 'packages/frontend/src/components/MkImageEffectorFxForm.vue')
-rw-r--r--packages/frontend/src/components/MkImageEffectorFxForm.vue95
1 files changed, 95 insertions, 0 deletions
diff --git a/packages/frontend/src/components/MkImageEffectorFxForm.vue b/packages/frontend/src/components/MkImageEffectorFxForm.vue
new file mode 100644
index 0000000000..d7ab620132
--- /dev/null
+++ b/packages/frontend/src/components/MkImageEffectorFxForm.vue
@@ -0,0 +1,95 @@
+<!--
+SPDX-FileCopyrightText: syuilo and misskey-project
+SPDX-License-Identifier: AGPL-3.0-only
+-->
+
+<template>
+<div class="_gaps">
+ <div v-for="v, k in paramDefs" :key="k">
+ <MkSwitch
+ v-if="v.type === 'boolean'"
+ v-model="params[k]">
+ <template #label>{{ v.label ?? k }}</template>
+ <template v-if="v.caption != null" #caption>{{ v.caption }}</template>
+ </MkSwitch>
+ <MkRange
+ v-else-if="v.type === 'number'"
+ v-model="params[k]"
+ continuousUpdate
+ :min="v.min"
+ :max="v.max"
+ :step="v.step"
+ :textConverter="v.toViewValue"
+ @thumbDoubleClicked="() => {
+ params[k] = v.default;
+ }"
+ >
+ <template #label>{{ v.label ?? k }}</template>
+ <template v-if="v.caption != null" #caption>{{ v.caption }}</template>
+ </MkRange>
+ <MkRadios v-else-if="v.type === 'number:enum'" v-model="params[k]">
+ <template #label>{{ v.label ?? k }}</template>
+ <template v-if="v.caption != null" #caption>{{ v.caption }}</template>
+ <option v-for="item in v.enum" :value="item.value">
+ <i v-if="item.icon" :class="item.icon"></i>
+ <template v-else>{{ item.label }}</template>
+ </option>
+ </MkRadios>
+ <div v-else-if="v.type === 'seed'">
+ <MkRange v-model="params[k]" continuousUpdate type="number" :min="0" :max="10000" :step="1">
+ <template #label>{{ v.label ?? k }}</template>
+ <template v-if="v.caption != null" #caption>{{ v.caption }}</template>
+ </MkRange>
+ </div>
+ <MkInput v-else-if="v.type === 'color'" :modelValue="getHex(params[k])" type="color" @update:modelValue="v => { const c = getRgb(v); if (c != null) params[k] = c; }">
+ <template #label>{{ v.label ?? k }}</template>
+ <template v-if="v.caption != null" #caption>{{ v.caption }}</template>
+ </MkInput>
+ </div>
+ <div v-if="Object.keys(paramDefs).length === 0" :class="$style.nothingToConfigure">
+ {{ i18n.ts._imageEffector.nothingToConfigure }}
+ </div>
+</div>
+</template>
+
+<script setup lang="ts">
+import MkInput from '@/components/MkInput.vue';
+import MkRadios from '@/components/MkRadios.vue';
+import MkSwitch from '@/components/MkSwitch.vue';
+import MkRange from '@/components/MkRange.vue';
+import { i18n } from '@/i18n.js';
+import type { ImageEffectorRGB, ImageEffectorFxParamDefs } from '@/utility/image-effector/ImageEffector.js';
+
+defineProps<{
+ paramDefs: ImageEffectorFxParamDefs;
+}>();
+
+const params = defineModel<Record<string, any>>({ required: true });
+
+function getHex(c: ImageEffectorRGB) {
+ return `#${c.map(x => (x * 255).toString(16).padStart(2, '0')).join('')}`;
+}
+
+function getRgb(hex: string | number): ImageEffectorRGB | null {
+ if (
+ typeof hex === 'number' ||
+ typeof hex !== 'string' ||
+ !/^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/.test(hex)
+ ) {
+ return null;
+ }
+
+ const m = hex.slice(1).match(/[0-9a-fA-F]{2}/g);
+ if (m == null) return [0, 0, 0];
+ return m.map(x => parseInt(x, 16) / 255) as ImageEffectorRGB;
+}
+</script>
+
+<style module>
+.nothingToConfigure {
+ opacity: 0.7;
+ text-align: center;
+ font-size: 14px;
+ padding: 0 10px;
+}
+</style>