feat: double click to open nsfw media
This commit is contained in:
parent
16903fd918
commit
228f7b230b
|
@ -1246,6 +1246,7 @@ additionalPermissionsForFlash: "Allow to add permission to Play"
|
|||
thisFlashRequiresTheFollowingPermissions: "This Play requires the following permissions"
|
||||
doYouWantToAllowThisPlayToAccessYourAccount: "Do you want to allow this Play to access your account?"
|
||||
translateProfile: "Translate profile"
|
||||
nsfwOpenBehavior: "NSFW media open behavior"
|
||||
_vibrations:
|
||||
click: "When an element is clicked"
|
||||
note: "When a new note is posted on the timeline"
|
||||
|
@ -2521,3 +2522,6 @@ _imageCompressionMode:
|
|||
noResizeCompress: "Compression without resize"
|
||||
resizeCompressLossy: "Resize and lossy compression"
|
||||
noResizeCompressLossy: "Lossy compression without resize"
|
||||
_nsfwOpenBehavior:
|
||||
click: "Click to open"
|
||||
doubleClick: "Double click to open"
|
||||
|
|
5
locales/index.d.ts
vendored
5
locales/index.d.ts
vendored
|
@ -1251,6 +1251,7 @@ export interface Locale {
|
|||
"thisFlashRequiresTheFollowingPermissions": string;
|
||||
"doYouWantToAllowThisPlayToAccessYourAccount": string;
|
||||
"translateProfile": string;
|
||||
"nsfwOpenBehavior": string;
|
||||
"_vibrations": {
|
||||
"click": string;
|
||||
"note": string;
|
||||
|
@ -2708,6 +2709,10 @@ export interface Locale {
|
|||
};
|
||||
};
|
||||
};
|
||||
"_nsfwOpenBehavior": {
|
||||
"click": string;
|
||||
"doubleClick": string;
|
||||
};
|
||||
}
|
||||
declare const locales: {
|
||||
[lang: string]: Locale;
|
||||
|
|
|
@ -1248,6 +1248,7 @@ additionalPermissionsForFlash: "Playへの追加許可"
|
|||
thisFlashRequiresTheFollowingPermissions: "このPlayは以下の権限を要求しています"
|
||||
doYouWantToAllowThisPlayToAccessYourAccount: "このPlayによるアカウントへのアクセスを許可しますか?"
|
||||
translateProfile: "プロフィールを翻訳する"
|
||||
nsfwOpenBehavior: "閲覧注意の開き方"
|
||||
|
||||
_vibrations:
|
||||
click: "要素をクリックしたとき"
|
||||
|
@ -2603,3 +2604,7 @@ _externalResourceInstaller:
|
|||
_themeInstallFailed:
|
||||
title: "テーマのインストールに失敗しました"
|
||||
description: "テーマのインストール中に問題が発生しました。もう一度お試しください。エラーの詳細はJavascriptコンソールをご覧ください。"
|
||||
|
||||
_nsfwOpenBehavior:
|
||||
click: "タップして開く"
|
||||
doubleClick: "二回タップして開く"
|
||||
|
|
|
@ -1223,6 +1223,7 @@ additionalPermissionsForFlash: "Play에 대한 추가 권한"
|
|||
thisFlashRequiresTheFollowingPermissions: "이 Play는 다음 권한을 요구해요"
|
||||
doYouWantToAllowThisPlayToAccessYourAccount: "이 Play가 계정에 접근하도록 허용할까요?"
|
||||
translateProfile: "프로필 번역하기"
|
||||
nsfwOpenBehavior: "열람주의 여는 방법"
|
||||
_vibrations:
|
||||
click: "요소를 클릭했을 때"
|
||||
note: "타임라인에 새 노트가 올라왔을 때"
|
||||
|
@ -2447,3 +2448,6 @@ _externalResourceInstaller:
|
|||
_themeInstallFailed:
|
||||
title: "테마 설치에 실패했어요"
|
||||
description: "테마를 설치하는 동안 문제가 발생했어요. 다시 시도해 주세요. 오류에 대한 자세한 내용은 자바스크립트 콘솔을 참고해 주세요."
|
||||
_nsfwOpenBehavior:
|
||||
click: "탭하여 열기"
|
||||
doubleClick: "더블 탭 하여 열기"
|
||||
|
|
|
@ -4,10 +4,10 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
-->
|
||||
|
||||
<template>
|
||||
<div :class="[hide ? $style.hidden : $style.visible, (image.isSensitive && defaultStore.state.highlightSensitiveMedia) && $style.sensitive]" :style="darkMode ? '--c: rgb(255 255 255 / 2%);' : '--c: rgb(0 0 0 / 2%);'" @click="onclick">
|
||||
<div :data-is-hidden="hide ? 'true' : 'false'" :class="[hide ? $style.hidden : $style.visible, (image.isSensitive && defaultStore.state.highlightSensitiveMedia) && $style.sensitive]" :style="darkMode ? '--c: rgb(255 255 255 / 2%);' : '--c: rgb(0 0 0 / 2%);'" @click="onClick" @dblclick="onDblclick">
|
||||
<component
|
||||
:is="disableImageLink ? 'div' : 'a'"
|
||||
v-bind="disableImageLink ? {
|
||||
:is="(disableImageLink || hide) ? 'div' : 'a'"
|
||||
v-bind="(disableImageLink || hide) ? {
|
||||
title: image.name,
|
||||
class: $style.imageContainer,
|
||||
} : {
|
||||
|
@ -64,6 +64,7 @@ import { defaultStore } from '@/store.js';
|
|||
import { i18n } from '@/i18n.js';
|
||||
import * as os from '@/os.js';
|
||||
import { iAmModerator } from '@/account.js';
|
||||
import MkRippleEffect from '@/components/MkRippleEffect.vue';
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
image: Misskey.entities.DriveFile;
|
||||
|
@ -90,11 +91,24 @@ const url = $computed(() => (props.raw || defaultStore.state.loadRawImages)
|
|||
: props.image.thumbnailUrl,
|
||||
);
|
||||
|
||||
function onclick() {
|
||||
function onClick(ev: MouseEvent) {
|
||||
if (!props.controls) {
|
||||
return;
|
||||
}
|
||||
if (hide) {
|
||||
if (!hide) return;
|
||||
if (defaultStore.state.nsfwOpenBehavior === 'doubleClick') {
|
||||
os.popup(MkRippleEffect, { x: ev.clientX, y: ev.clientY }, {}, 'end');
|
||||
}
|
||||
if (defaultStore.state.nsfwOpenBehavior === 'click') {
|
||||
hide = false;
|
||||
}
|
||||
}
|
||||
|
||||
function onDblclick() {
|
||||
if (!props.controls) {
|
||||
return;
|
||||
}
|
||||
if (hide && defaultStore.state.nsfwOpenBehavior === 'doubleClick') {
|
||||
hide = false;
|
||||
}
|
||||
}
|
||||
|
@ -150,6 +164,7 @@ onUnmounted(() => {
|
|||
<style lang="scss" module>
|
||||
.hidden {
|
||||
position: relative;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
}
|
||||
|
||||
.sensitive {
|
||||
|
@ -205,6 +220,7 @@ onUnmounted(() => {
|
|||
|
||||
.visible {
|
||||
position: relative;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
//box-shadow: 0 0 0 1px var(--divider) inset;
|
||||
background: var(--bg);
|
||||
background-image: linear-gradient(45deg, var(--c) 16.67%, var(--bg) 16.67%, var(--bg) 50%, var(--c) 50%, var(--c) 66.67%, var(--bg) 66.67%, var(--bg) 100%);
|
||||
|
|
|
@ -214,6 +214,14 @@ onMounted(() => {
|
|||
itemData.thumbCropped = true;
|
||||
});
|
||||
|
||||
// prevent to open hidden media
|
||||
lightbox.addFilter('clickedIndex', (clickedIndex) => {
|
||||
if ((gallery.value?.children[clickedIndex] as HTMLElement|undefined)?.dataset.isHidden === 'true') {
|
||||
return -1;
|
||||
}
|
||||
return clickedIndex;
|
||||
});
|
||||
|
||||
lightbox.on('uiRegister', () => {
|
||||
lightbox.pswp.ui.registerElement({
|
||||
name: 'altText',
|
||||
|
|
|
@ -93,6 +93,12 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
<option value="force">{{ i18n.ts._displayOfSensitiveMedia.force }}</option>
|
||||
</MkSelect>
|
||||
|
||||
<MkSelect v-model="nsfwOpenBehavior">
|
||||
<template #label>{{ i18n.ts.nsfwOpenBehavior }} <span class="_beta">CherryPick</span></template>
|
||||
<option value="click">{{ i18n.ts._nsfwOpenBehavior.click }}</option>
|
||||
<option value="doubleClick">{{ i18n.ts._nsfwOpenBehavior.doubleClick }}</option>
|
||||
</MkSelect>
|
||||
|
||||
<MkRadios v-model="mediaListWithOneImageAppearance">
|
||||
<template #label>{{ i18n.ts.mediaListWithOneImageAppearance }}</template>
|
||||
<option value="expand">{{ i18n.ts.default }}</option>
|
||||
|
@ -378,6 +384,7 @@ const renoteQuoteButtonSeparation = computed(defaultStore.makeGetterSetter('reno
|
|||
const showFixedPostFormInReplies = computed(defaultStore.makeGetterSetter('showFixedPostFormInReplies'));
|
||||
const showingAnimatedImages = computed(defaultStore.makeGetterSetter('showingAnimatedImages'));
|
||||
const allMediaNoteCollapse = computed(defaultStore.makeGetterSetter('allMediaNoteCollapse'));
|
||||
const nsfwOpenBehavior = computed(defaultStore.makeGetterSetter('nsfwOpenBehavior'));
|
||||
|
||||
watch(lang, () => {
|
||||
miLocalStorage.setItem('lang', lang.value as string);
|
||||
|
|
|
@ -473,6 +473,10 @@ export const defaultStore = markRaw(new Storage('base', {
|
|||
where: 'device',
|
||||
default: false,
|
||||
},
|
||||
nsfwOpenBehavior: {
|
||||
where: 'device',
|
||||
default: 'click' as 'click' | 'doubleClick',
|
||||
},
|
||||
|
||||
// - Settings/Timeline
|
||||
enableHomeTimeline: {
|
||||
|
|
Loading…
Reference in a new issue