wip
This commit is contained in:
parent
2a8920f8c3
commit
44212a31c9
|
@ -12026,7 +12026,7 @@ export interface Locale extends ILocale {
|
||||||
*/
|
*/
|
||||||
"opacity": string;
|
"opacity": string;
|
||||||
/**
|
/**
|
||||||
* 大きさ
|
* サイズ
|
||||||
*/
|
*/
|
||||||
"scale": string;
|
"scale": string;
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -3221,7 +3221,7 @@ _watermarkEditor:
|
||||||
title: "ウォーターマークの編集"
|
title: "ウォーターマークの編集"
|
||||||
repeat: "敷き詰める"
|
repeat: "敷き詰める"
|
||||||
opacity: "不透明度"
|
opacity: "不透明度"
|
||||||
scale: "大きさ"
|
scale: "サイズ"
|
||||||
text: "テキスト"
|
text: "テキスト"
|
||||||
position: "位置"
|
position: "位置"
|
||||||
type: "タイプ"
|
type: "タイプ"
|
||||||
|
|
|
@ -56,6 +56,9 @@ import { selectFile } from '@/utility/drive.js';
|
||||||
import { misskeyApi } from '@/utility/misskey-api.js';
|
import { misskeyApi } from '@/utility/misskey-api.js';
|
||||||
import { prefer } from '@/preferences.js';
|
import { prefer } from '@/preferences.js';
|
||||||
import { deepClone } from '@/utility/clone.js';
|
import { deepClone } from '@/utility/clone.js';
|
||||||
|
import { ensureSignin } from '@/i.js';
|
||||||
|
|
||||||
|
const $i = ensureSignin();
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
preset: WatermarkPreset | null;
|
preset: WatermarkPreset | null;
|
||||||
|
@ -67,17 +70,17 @@ const preset = reactive(deepClone(props.preset) ?? {
|
||||||
layers: [{
|
layers: [{
|
||||||
id: uuid(),
|
id: uuid(),
|
||||||
type: 'text',
|
type: 'text',
|
||||||
text: 'sample',
|
text: `(c) @${$i.username}`,
|
||||||
alignX: 'right',
|
alignX: 'right',
|
||||||
alignY: 'bottom',
|
alignY: 'bottom',
|
||||||
scale: 0.5,
|
scale: 0.3,
|
||||||
opacity: 0.5,
|
opacity: 0.75,
|
||||||
repeat: false,
|
repeat: false,
|
||||||
}],
|
}],
|
||||||
} satisfies WatermarkPreset);
|
} satisfies WatermarkPreset);
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
(ev: 'ok'): void;
|
(ev: 'ok', preset: WatermarkPreset): void;
|
||||||
(ev: 'cancel'): void;
|
(ev: 'cancel'): void;
|
||||||
(ev: 'closed'): void;
|
(ev: 'closed'): void;
|
||||||
}>();
|
}>();
|
||||||
|
@ -126,6 +129,24 @@ onUnmounted(() => {
|
||||||
renderer = null;
|
renderer = null;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
async function save() {
|
||||||
|
const { canceled, result: name } = await os.inputText({
|
||||||
|
title: i18n.ts.name,
|
||||||
|
default: preset.name,
|
||||||
|
});
|
||||||
|
if (canceled) return;
|
||||||
|
|
||||||
|
preset.name = name || '';
|
||||||
|
|
||||||
|
dialog.value?.close();
|
||||||
|
if (renderer != null) {
|
||||||
|
renderer.destroy();
|
||||||
|
renderer = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
emit('ok', preset);
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style module>
|
<style module>
|
||||||
|
|
|
@ -0,0 +1,113 @@
|
||||||
|
<!--
|
||||||
|
SPDX-FileCopyrightText: syuilo and misskey-project
|
||||||
|
SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
-->
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<MkFolder :defaultOpen="false">
|
||||||
|
<template #icon><i class="ti ti-pencil"></i></template>
|
||||||
|
<template #label>{{ i18n.ts.preset }}: {{ preset.name === '' ? '(' + i18n.ts.noName + ')' : preset.name }}</template>
|
||||||
|
<template #footer>
|
||||||
|
<div class="_buttons">
|
||||||
|
<MkButton @click="edit"><i class="ti ti-pencil"></i> {{ i18n.ts.edit }}</MkButton>
|
||||||
|
<MkButton danger iconOnly style="margin-left: auto;" @click="del"><i class="ti ti-trash"></i></MkButton>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<canvas ref="canvasEl" :class="$style.previewCanvas"></canvas>
|
||||||
|
</div>
|
||||||
|
</MkFolder>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { defineAsyncComponent, onMounted, onUnmounted, ref, useTemplateRef, watch } from 'vue';
|
||||||
|
import type { WatermarkPreset } from '@/utility/watermarker.js';
|
||||||
|
import MkButton from '@/components/MkButton.vue';
|
||||||
|
import * as os from '@/os.js';
|
||||||
|
import { i18n } from '@/i18n.js';
|
||||||
|
import { deepClone } from '@/utility/clone.js';
|
||||||
|
import MkFolder from '@/components/MkFolder.vue';
|
||||||
|
import { Watermarker } from '@/utility/watermarker.js';
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
preset: WatermarkPreset;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const emit = defineEmits<{
|
||||||
|
(ev: 'updatePreset', preset: WatermarkPreset): void,
|
||||||
|
(ev: 'del'): void,
|
||||||
|
}>();
|
||||||
|
|
||||||
|
async function edit() {
|
||||||
|
const { dispose } = os.popup(defineAsyncComponent(() => import('@/components/MkWatermarkEditorDialog.vue')), {
|
||||||
|
preset: deepClone(props.preset),
|
||||||
|
}, {
|
||||||
|
ok: (preset: WatermarkPreset) => {
|
||||||
|
emit('updatePreset', preset);
|
||||||
|
},
|
||||||
|
closed: () => dispose(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function del(ev: MouseEvent) {
|
||||||
|
os.popupMenu([{
|
||||||
|
text: i18n.ts.delete,
|
||||||
|
action: () => {
|
||||||
|
emit('del');
|
||||||
|
},
|
||||||
|
}], ev.currentTarget ?? ev.target);
|
||||||
|
}
|
||||||
|
|
||||||
|
const canvasEl = useTemplateRef('canvasEl');
|
||||||
|
|
||||||
|
const sampleImage = new Image();
|
||||||
|
sampleImage.src = '/client-assets/sample/3-2.jpg';
|
||||||
|
|
||||||
|
let renderer: Watermarker | null = null;
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
sampleImage.onload = async () => {
|
||||||
|
watch(canvasEl, async () => {
|
||||||
|
if (canvasEl.value == null) return;
|
||||||
|
|
||||||
|
renderer = new Watermarker({
|
||||||
|
canvas: canvasEl.value,
|
||||||
|
width: 1500,
|
||||||
|
height: 1000,
|
||||||
|
preset: props.preset,
|
||||||
|
originalImage: sampleImage,
|
||||||
|
});
|
||||||
|
|
||||||
|
await renderer.bakeTextures();
|
||||||
|
|
||||||
|
renderer.render();
|
||||||
|
}, { immediate: true });
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
|
if (renderer != null) {
|
||||||
|
renderer.destroy();
|
||||||
|
renderer = null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
watch(() => props.preset, async () => {
|
||||||
|
if (renderer != null) {
|
||||||
|
renderer.updatePreset(props.preset);
|
||||||
|
renderer.render();
|
||||||
|
}
|
||||||
|
}, { deep: true });
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" module>
|
||||||
|
.previewCanvas {
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
max-height: 200px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
object-fit: contain;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -58,7 +58,17 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<template #icon><i class="ti ti-copyright"></i></template>
|
<template #icon><i class="ti ti-copyright"></i></template>
|
||||||
<template #label><SearchLabel>{{ i18n.ts.watermark }}</SearchLabel></template>
|
<template #label><SearchLabel>{{ i18n.ts.watermark }}</SearchLabel></template>
|
||||||
|
|
||||||
<MkButton iconOnly @click="addWatermarkPreset"><i class="ti ti-plus"></i></MkButton>
|
<div class="_gaps_s">
|
||||||
|
<XWatermarkItem
|
||||||
|
v-for="(preset, i) in prefer.r.watermarkPresets.value"
|
||||||
|
:key="preset.id"
|
||||||
|
:preset="preset"
|
||||||
|
@updatePreset="onUpdateWatermarkPreset(preset.id, $event)"
|
||||||
|
@del="onDeleteWatermarkPreset(preset.id)"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<MkButton iconOnly rounded style="margin: 0 auto;" @click="addWatermarkPreset"><i class="ti ti-plus"></i></MkButton>
|
||||||
|
</div>
|
||||||
</MkFolder>
|
</MkFolder>
|
||||||
</SearchMarker>
|
</SearchMarker>
|
||||||
|
|
||||||
|
@ -93,6 +103,8 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
import { computed, defineAsyncComponent, ref } from 'vue';
|
import { computed, defineAsyncComponent, ref } from 'vue';
|
||||||
import * as Misskey from 'misskey-js';
|
import * as Misskey from 'misskey-js';
|
||||||
import tinycolor from 'tinycolor2';
|
import tinycolor from 'tinycolor2';
|
||||||
|
import XWatermarkItem from './drive.WatermarkItem.vue';
|
||||||
|
import type { WatermarkPreset } from '@/utility/watermarker.js';
|
||||||
import FormLink from '@/components/form/link.vue';
|
import FormLink from '@/components/form/link.vue';
|
||||||
import MkSwitch from '@/components/MkSwitch.vue';
|
import MkSwitch from '@/components/MkSwitch.vue';
|
||||||
import FormSection from '@/components/form/section.vue';
|
import FormSection from '@/components/form/section.vue';
|
||||||
|
@ -166,10 +178,34 @@ function chooseUploadFolder() {
|
||||||
function addWatermarkPreset() {
|
function addWatermarkPreset() {
|
||||||
const { dispose } = os.popup(defineAsyncComponent(() => import('@/components/MkWatermarkEditorDialog.vue')), {
|
const { dispose } = os.popup(defineAsyncComponent(() => import('@/components/MkWatermarkEditorDialog.vue')), {
|
||||||
}, {
|
}, {
|
||||||
|
ok: (preset: WatermarkPreset) => {
|
||||||
|
prefer.commit('watermarkPresets', [...prefer.s.watermarkPresets, preset]);
|
||||||
|
},
|
||||||
closed: () => dispose(),
|
closed: () => dispose(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function onUpdateWatermarkPreset(id: string, preset: WatermarkPreset) {
|
||||||
|
const index = prefer.s.watermarkPresets.findIndex(p => p.id === id);
|
||||||
|
if (index !== -1) {
|
||||||
|
prefer.commit('watermarkPresets', [
|
||||||
|
...prefer.s.watermarkPresets.slice(0, index),
|
||||||
|
preset,
|
||||||
|
...prefer.s.watermarkPresets.slice(index + 1),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function onDeleteWatermarkPreset(id: string) {
|
||||||
|
const index = prefer.s.watermarkPresets.findIndex(p => p.id === id);
|
||||||
|
if (index !== -1) {
|
||||||
|
prefer.commit('watermarkPresets', [
|
||||||
|
...prefer.s.watermarkPresets.slice(0, index),
|
||||||
|
...prefer.s.watermarkPresets.slice(index + 1),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function saveProfile() {
|
function saveProfile() {
|
||||||
misskeyApi('i/update', {
|
misskeyApi('i/update', {
|
||||||
alwaysMarkNsfw: !!alwaysMarkNsfw.value,
|
alwaysMarkNsfw: !!alwaysMarkNsfw.value,
|
||||||
|
|
Loading…
Reference in New Issue