mirror of
https://github.com/misskey-dev/misskey.git
synced 2024-12-27 10:20:27 +01:00
UX調整
This commit is contained in:
parent
9fd07c0823
commit
499a6d3598
7 changed files with 108 additions and 20 deletions
30
locales/index.d.ts
vendored
30
locales/index.d.ts
vendored
|
@ -1906,14 +1906,22 @@ export interface Locale extends ILocale {
|
|||
* ウォーターマーク
|
||||
*/
|
||||
"watermark": string;
|
||||
/**
|
||||
* ウォーターマークをつけますか?
|
||||
*/
|
||||
"watermarkConfirm": string;
|
||||
/**
|
||||
* ウォーターマークをつける
|
||||
*/
|
||||
"useWatermark": string;
|
||||
/**
|
||||
* 画像にウォーターマークを追加します
|
||||
* 画像のアップロード時にデフォルトでウォーターマークをつけるようにします。
|
||||
*/
|
||||
"useWatermarkDescription": string;
|
||||
/**
|
||||
* デフォルトの値にかかわらず、アップロードメニューの「ウォーターマークをつける」スイッチを操作して、一回限りの設定を適用することができます。
|
||||
*/
|
||||
"useWatermarkInfo": string;
|
||||
/**
|
||||
* すべての通知を既読にする
|
||||
*/
|
||||
|
@ -5282,6 +5290,14 @@ export interface Locale extends ILocale {
|
|||
* 注意事項を理解した上でオンにします。
|
||||
*/
|
||||
"acknowledgeNotesAndEnable": string;
|
||||
/**
|
||||
* 常に確認する
|
||||
*/
|
||||
"alwaysConfirm": string;
|
||||
/**
|
||||
* デフォルトの設定を適用する
|
||||
*/
|
||||
"useDefaultSettings": string;
|
||||
"_accountSettings": {
|
||||
/**
|
||||
* コンテンツの表示にログインを必須にする
|
||||
|
@ -10662,6 +10678,10 @@ export interface Locale extends ILocale {
|
|||
"sent": string;
|
||||
};
|
||||
"_watermarkEditor": {
|
||||
/**
|
||||
* ウォーターマークをカスタマイズ
|
||||
*/
|
||||
"title": string;
|
||||
/**
|
||||
* このファイルは対応していません
|
||||
*/
|
||||
|
@ -10678,6 +10698,10 @@ export interface Locale extends ILocale {
|
|||
* プレビューが正常に表示されることを確認してから保存してください
|
||||
*/
|
||||
"settingInvalidWarnDescription": string;
|
||||
/**
|
||||
* ウォーターマーク用画像のファイルサイズが大きいと、処理の際にウォーターマークを読み込む時間が長くなり、アップロードに時間がかかるようになります。あらかじめ解像度を低くしたり、ファイルを圧縮したりしておくことを推奨します。
|
||||
*/
|
||||
"useSmallFile": string;
|
||||
/**
|
||||
* 描画モード
|
||||
*/
|
||||
|
@ -10698,6 +10722,10 @@ export interface Locale extends ILocale {
|
|||
* 通常はオンで問題ありません。ウォーターマークを回転させた際に余白が不自然になった場合はオフにしてみてください。
|
||||
*/
|
||||
"preserveBoundingRectDescription": string;
|
||||
/**
|
||||
* クリップボード経由でのアップロード時の動作
|
||||
*/
|
||||
"clipboardUploadBehavior": string;
|
||||
};
|
||||
}
|
||||
declare const locales: {
|
||||
|
|
|
@ -472,8 +472,10 @@ notFound: "見つかりません"
|
|||
notFoundDescription: "指定されたURLに該当するページはありませんでした。"
|
||||
uploadFolder: "既定アップロード先"
|
||||
watermark: "ウォーターマーク"
|
||||
watermarkConfirm: "ウォーターマークをつけますか?"
|
||||
useWatermark: "ウォーターマークをつける"
|
||||
useWatermarkDescription: "画像にウォーターマークを追加します"
|
||||
useWatermarkDescription: "画像のアップロード時にデフォルトでウォーターマークをつけるようにします。"
|
||||
useWatermarkInfo: "デフォルトの値にかかわらず、アップロードメニューの「ウォーターマークをつける」スイッチを操作して、一回限りの設定を適用することができます。"
|
||||
markAsReadAllNotifications: "すべての通知を既読にする"
|
||||
markAsReadAllUnreadNotes: "すべての投稿を既読にする"
|
||||
markAsReadAllTalkMessages: "すべてのチャットを既読にする"
|
||||
|
@ -1316,6 +1318,8 @@ lockdown: "ロックダウン"
|
|||
pleaseSelectAccount: "アカウントを選択してください"
|
||||
availableRoles: "利用可能なロール"
|
||||
acknowledgeNotesAndEnable: "注意事項を理解した上でオンにします。"
|
||||
alwaysConfirm: "常に確認する"
|
||||
useDefaultSettings: "デフォルトの設定を適用する"
|
||||
|
||||
_accountSettings:
|
||||
requireSigninToViewContents: "コンテンツの表示にログインを必須にする"
|
||||
|
@ -2843,12 +2847,15 @@ _followRequest:
|
|||
sent: "送った申請"
|
||||
|
||||
_watermarkEditor:
|
||||
title: "ウォーターマークをカスタマイズ"
|
||||
driveFileTypeWarn: "このファイルは対応していません"
|
||||
driveFileTypeWarnDescription: "画像ファイルを選択してください"
|
||||
settingInvalidWarn: "設定が不十分です"
|
||||
settingInvalidWarnDescription: "プレビューが正常に表示されることを確認してから保存してください"
|
||||
useSmallFile: "ウォーターマーク用画像のファイルサイズが大きいと、処理の際にウォーターマークを読み込む時間が長くなり、アップロードに時間がかかるようになります。あらかじめ解像度を低くしたり、ファイルを圧縮したりしておくことを推奨します。"
|
||||
repeatSetting: "描画モード"
|
||||
repeat: "全体を埋め尽くす"
|
||||
padding: "余白"
|
||||
preserveBoundingRect: "回転した分の面積を確保する"
|
||||
preserveBoundingRectDescription: "通常はオンで問題ありません。ウォーターマークを回転させた際に余白が不自然になった場合はオフにしてみてください。"
|
||||
clipboardUploadBehavior: "クリップボード経由でのアップロード時の動作"
|
||||
|
|
|
@ -442,10 +442,10 @@ function replaceFile(file: Misskey.entities.DriveFile, newFile: Misskey.entities
|
|||
files.value[files.value.findIndex(x => x.id === file.id)] = newFile;
|
||||
}
|
||||
|
||||
function upload(file: File, name?: string): void {
|
||||
function upload(file: File, name?: string, watermark?: boolean): void {
|
||||
if (props.mock) return;
|
||||
|
||||
uploadFile(file, defaultStore.state.uploadFolder, name).then(res => {
|
||||
uploadFile(file, defaultStore.state.uploadFolder, name, undefined, watermark).then(res => {
|
||||
files.value.push(res);
|
||||
});
|
||||
}
|
||||
|
@ -587,6 +587,8 @@ async function onPaste(ev: ClipboardEvent) {
|
|||
if (props.mock) return;
|
||||
if (!ev.clipboardData) return;
|
||||
|
||||
let shouldApplyWatermark: boolean | undefined = undefined;
|
||||
|
||||
for (const { item, i } of Array.from(ev.clipboardData.items, (data, x) => ({ item: data, i: x }))) {
|
||||
if (item.kind === 'file') {
|
||||
const file = item.getAsFile();
|
||||
|
@ -594,7 +596,20 @@ async function onPaste(ev: ClipboardEvent) {
|
|||
const lio = file.name.lastIndexOf('.');
|
||||
const ext = lio >= 0 ? file.name.slice(lio) : '';
|
||||
const formatted = `${formatTimeString(new Date(file.lastModified), defaultStore.state.pastedFileName).replace(/{{number}}/g, `${i + 1}`)}${ext}`;
|
||||
upload(file, formatted);
|
||||
|
||||
if (file.type.startsWith('image/')) {
|
||||
if (shouldApplyWatermark == null && defaultStore.state.clipboardWatermarkBehavior === 'confirm') {
|
||||
const { canceled } = await os.confirm({
|
||||
type: 'info',
|
||||
text: i18n.ts.watermarkConfirm,
|
||||
okText: i18n.ts.yes,
|
||||
cancelText: i18n.ts.no,
|
||||
});
|
||||
shouldApplyWatermark = !canceled;
|
||||
}
|
||||
}
|
||||
|
||||
upload(file, formatted, shouldApplyWatermark);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
@ok="save()"
|
||||
@closed="emit('closed')"
|
||||
>
|
||||
<template #header><i class="ti ti-ripple"></i> {{ i18n.ts.watermark }}</template>
|
||||
<template #header><i class="ti ti-ripple"></i> {{ i18n.ts._watermarkEditor.title }}</template>
|
||||
|
||||
<div :class="$style.watermarkEditorRoot">
|
||||
<div :class="$style.watermarkEditorInputRoot">
|
||||
|
@ -26,10 +26,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</div>
|
||||
</div>
|
||||
<div :class="$style.watermarkEditorSettings" class="_gaps">
|
||||
<MkSwitch v-model="useWatermark">
|
||||
<template #label>{{ i18n.ts.useWatermark }}</template>
|
||||
<template #caption>{{ i18n.ts.useWatermarkDescription }}</template>
|
||||
</MkSwitch>
|
||||
<MkInfo warn>{{ i18n.ts._watermarkEditor.useSmallFile }}</MkInfo>
|
||||
|
||||
<div>
|
||||
<div :class="$style.formLabel">{{ i18n.ts.watermark }}</div>
|
||||
|
@ -107,6 +104,7 @@ import MkRadios from '@/components/MkRadios.vue';
|
|||
import MkSwitch from '@/components/MkSwitch.vue';
|
||||
import MkInput from '@/components/MkInput.vue';
|
||||
import MkRange from '@/components/MkRange.vue';
|
||||
import MkInfo from '@/components/MkInfo.vue';
|
||||
import XAnchorSelector from '@/components/MkWatermarkEditorDialog.anchor.vue';
|
||||
import XPaddingView from '@/components/MkWatermarkEditorDialog.padding.vue';
|
||||
|
||||
|
@ -135,7 +133,6 @@ function cancel() {
|
|||
//#endregion
|
||||
|
||||
//#region 設定
|
||||
const useWatermark = computed(defaultStore.makeGetterSetter('useWatermark'));
|
||||
const watermarkConfig = ref<WatermarkUserConfig>(defaultStore.state.watermarkConfig ?? {
|
||||
opacity: 0.2,
|
||||
repeat: true,
|
||||
|
@ -279,11 +276,11 @@ function chooseFile(ev: MouseEvent) {
|
|||
const canvasLoading = ref(true);
|
||||
const canvasEl = useTemplateRef('canvasEl');
|
||||
onMounted(() => {
|
||||
watch([useWatermark, watermarkConfig], ([useWatermarkTo, watermarkConfigTo]) => {
|
||||
watch(watermarkConfig, (watermarkConfigTo) => {
|
||||
canvasLoading.value = true;
|
||||
if (canvasEl.value) {
|
||||
// @/scripts/watermark.ts の DEFAULT_ASPECT_RATIO と同じ縦横比の画像を使用すること
|
||||
applyWatermark('/client-assets/hill.webp', canvasEl.value, useWatermarkTo && canPreview(watermarkConfigTo) ? watermarkConfigTo : null).then(() => {
|
||||
applyWatermark('/client-assets/hill.webp', canvasEl.value, canPreview(watermarkConfigTo) ? watermarkConfigTo : null).then(() => {
|
||||
canvasLoading.value = false;
|
||||
});
|
||||
}
|
||||
|
|
|
@ -41,11 +41,34 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
<template #icon><i class="ti ti-file-shredder"></i></template>
|
||||
{{ i18n.ts.drivecleaner }}
|
||||
</FormLink>
|
||||
<FormLink @click="openWatermarkEditor">
|
||||
<MkFolder>
|
||||
<template #icon><i class="ti ti-ripple"></i></template>
|
||||
{{ i18n.ts.watermark }}
|
||||
<template #suffix>{{ defaultStore.reactiveState.useWatermark.value ? i18n.ts.enabled : i18n.ts.disabled }}</template>
|
||||
</FormLink>
|
||||
<template #label>{{ i18n.ts.watermark }}</template>
|
||||
|
||||
<div>
|
||||
<div class="_gaps">
|
||||
<MkInfo>{{ i18n.ts.useWatermarkInfo }}</MkInfo>
|
||||
|
||||
<MkSwitch v-model="useWatermark">
|
||||
<template #label>{{ i18n.ts.useWatermark }}</template>
|
||||
<template #caption>{{ i18n.ts.useWatermarkDescription }}</template>
|
||||
</MkSwitch>
|
||||
|
||||
<MkSelect v-model="clipboardWatermarkBehavior">
|
||||
<template #label>{{ i18n.ts._watermarkEditor.clipboardUploadBehavior }}</template>
|
||||
<option value="confirm">{{ i18n.ts.alwaysConfirm }}</option>
|
||||
<option value="default">{{ i18n.ts.useDefaultSettings }}</option>
|
||||
</MkSelect>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
||||
<FormLink @click="openWatermarkEditor">
|
||||
<template #icon><i class="ti ti-pencil"></i></template>
|
||||
{{ i18n.ts._watermarkEditor.title }}
|
||||
</FormLink>
|
||||
</div>
|
||||
</MkFolder>
|
||||
<MkSwitch v-model="keepOriginalUploading">
|
||||
<template #label>{{ i18n.ts.keepOriginalUploading }}</template>
|
||||
<template #caption>{{ i18n.ts.keepOriginalUploadingDescription }}</template>
|
||||
|
@ -67,10 +90,13 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, defineAsyncComponent, ref } from 'vue';
|
||||
import { computed, defineAsyncComponent, ref, watch } from 'vue';
|
||||
import * as Misskey from 'misskey-js';
|
||||
import tinycolor from 'tinycolor2';
|
||||
import FormLink from '@/components/form/link.vue';
|
||||
import MkFolder from '@/components/MkFolder.vue';
|
||||
import MkInfo from '@/components/MkInfo.vue';
|
||||
import MkSelect from '@/components/MkSelect.vue';
|
||||
import MkSwitch from '@/components/MkSwitch.vue';
|
||||
import FormSection from '@/components/form/section.vue';
|
||||
import MkKeyValue from '@/components/MkKeyValue.vue';
|
||||
|
@ -83,6 +109,7 @@ import MkChart from '@/components/MkChart.vue';
|
|||
import { i18n } from '@/i18n.js';
|
||||
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
||||
import { signinRequired } from '@/account.js';
|
||||
import { reloadAsk } from '@/scripts/reload-ask';
|
||||
|
||||
const $i = signinRequired();
|
||||
|
||||
|
@ -105,9 +132,19 @@ const meterStyle = computed(() => {
|
|||
};
|
||||
});
|
||||
|
||||
const useWatermark = computed(defaultStore.makeGetterSetter('useWatermark'));
|
||||
const clipboardWatermarkBehavior = computed(defaultStore.makeGetterSetter('clipboardWatermarkBehavior'));
|
||||
|
||||
const keepOriginalUploading = computed(defaultStore.makeGetterSetter('keepOriginalUploading'));
|
||||
const keepOriginalFilename = computed(defaultStore.makeGetterSetter('keepOriginalFilename'));
|
||||
|
||||
watch([
|
||||
useWatermark,
|
||||
clipboardWatermarkBehavior,
|
||||
], () => {
|
||||
reloadAsk({ unison: true, reason: i18n.ts.reloadRequiredToApplySettings });
|
||||
});
|
||||
|
||||
misskeyApi('drive').then(info => {
|
||||
capacity.value = info.capacity;
|
||||
usage.value = info.usage;
|
||||
|
|
|
@ -33,7 +33,7 @@ const mimeTypeMap = {
|
|||
|
||||
export function uploadFile(
|
||||
file: File,
|
||||
folder?: string | Misskey.entities.DriveFolder,
|
||||
folder?: string | null | Misskey.entities.DriveFolder,
|
||||
name?: string,
|
||||
keepOriginal: boolean = defaultStore.state.keepOriginalUploading,
|
||||
watermark: boolean = defaultStore.state.useWatermark,
|
||||
|
@ -70,7 +70,7 @@ export function uploadFile(
|
|||
uploads.value.push(ctx);
|
||||
|
||||
let _file: Blob = file;
|
||||
|
||||
|
||||
if (_file.type.startsWith('image/') && watermark && canPreview(defaultStore.state.watermarkConfig)) {
|
||||
_file = await getWatermarkAppliedImage(_file, defaultStore.state.watermarkConfig);
|
||||
}
|
||||
|
|
|
@ -479,6 +479,10 @@ export const defaultStore = markRaw(new Storage('base', {
|
|||
where: 'device',
|
||||
default: false,
|
||||
},
|
||||
clipboardWatermarkBehavior: {
|
||||
where: 'device',
|
||||
default: 'default' as 'default' | 'confirm',
|
||||
},
|
||||
watermarkConfig: {
|
||||
where: 'account',
|
||||
default: null as WatermarkUserConfig | null,
|
||||
|
|
Loading…
Reference in a new issue