merge: Add "reject quotes" settings (!901)

View MR for information: https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/901

Approved-by: dakkar <dakkar@thenautilus.net>
Approved-by: Marie <github@yuugi.dev>
This commit is contained in:
Hazelnoot 2025-03-01 03:33:06 +00:00
commit 14a81b4f85
49 changed files with 693 additions and 100 deletions

View file

@ -102,7 +102,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</div>
<MkPoll v-if="appearNote.poll" :noteId="appearNote.id" :poll="appearNote.poll" :local="!appearNote.user.host" :author="appearNote.user" :emojiUrls="appearNote.emojis" :class="$style.poll" @click.stop/>
<div v-if="isEnabledUrlPreview">
<MkUrlPreview v-for="url in urls" :key="url" :url="url" :compact="true" :detail="false" :showAsQuote="true" :skipNoteIds="[appearNote.renote?.id]" :class="$style.urlPreview" @click.stop/>
<MkUrlPreview v-for="url in urls" :key="url" :url="url" :compact="true" :detail="false" :showAsQuote="!appearNote.user.rejectQuotes" :skipNoteIds="[appearNote.renote?.id]" :class="$style.urlPreview" @click.stop/>
</div>
<div v-if="appearNote.renote" :class="$style.quote"><MkNoteSimple :note="appearNote.renote" :class="$style.quoteNote"/></div>
<button v-if="isLong && collapsed" :class="$style.collapsed" class="_button" @click.stop @click="collapsed = false">
@ -142,7 +142,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<i class="ti ti-ban"></i>
</button>
<button
v-if="canRenote && !props.mock"
v-if="canRenote && !props.mock && !$i?.rejectQuotes"
ref="quoteButton"
:class="$style.footerButton"
class="_button"

View file

@ -117,7 +117,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</div>
<MkPoll v-if="appearNote.poll" ref="pollViewer" :noteId="appearNote.id" :poll="appearNote.poll" :local="!appearNote.user.host" :class="$style.poll" :author="appearNote.user" :emojiUrls="appearNote.emojis"/>
<div v-if="isEnabledUrlPreview">
<MkUrlPreview v-for="url in urls" :key="url" :url="url" :compact="true" :detail="true" :showAsQuote="true" :skipNoteIds="[appearNote.renote?.id]" style="margin-top: 6px;"/>
<MkUrlPreview v-for="url in urls" :key="url" :url="url" :compact="true" :detail="true" :showAsQuote="!appearNote.user.rejectQuotes" :skipNoteIds="[appearNote.renote?.id]" style="margin-top: 6px;"/>
</div>
<div v-if="appearNote.renote" :class="$style.quote"><MkNoteSimple :note="appearNote.renote" :class="$style.quoteNote" :expandAllCws="props.expandAllCws"/></div>
</div>
@ -153,7 +153,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<i class="ti ti-ban"></i>
</button>
<button
v-if="canRenote"
v-if="canRenote && !$i?.rejectQuotes"
ref="quoteButton"
class="_button"
:class="$style.noteFooterButton"

View file

@ -38,7 +38,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<p v-if="note.renoteCount > 0" :class="$style.noteFooterButtonCount">{{ note.renoteCount }}</p>
</button>
<button
v-if="canRenote"
v-if="canRenote && !$i?.rejectQuotes"
ref="quoteButton"
class="_button"
:class="$style.noteFooterButton"

View file

@ -640,7 +640,7 @@ async function onPaste(ev: ClipboardEvent) {
const paste = ev.clipboardData.getData('text');
if (!renoteTargetNote.value && !quoteId.value && paste.startsWith(url + '/notes/')) {
if (!renoteTargetNote.value && !quoteId.value && paste.startsWith(url + '/notes/') && !$i.rejectQuotes) {
ev.preventDefault();
os.confirm({

View file

@ -87,20 +87,22 @@ SPDX-License-Identifier: AGPL-3.0-only
import { defineAsyncComponent, onDeactivated, onUnmounted, ref, watch } from 'vue';
import { url as local } from '@@/js/config.js';
import { versatileLang } from '@@/js/intl-const.js';
import * as Misskey from 'misskey-js';
import type { summaly } from '@misskey-dev/summaly';
import type MkNoteSimple from '@/components/MkNoteSimple.vue';
import type SkNoteSimple from '@/components/SkNoteSimple.vue';
import { i18n } from '@/i18n.js';
import * as os from '@/os.js';
import { deviceKind } from '@/scripts/device-kind.js';
import MkButton from '@/components/MkButton.vue';
import { transformPlayerUrl } from '@/scripts/player-url-transform.js';
import { defaultStore } from '@/store.js';
import * as Misskey from 'misskey-js';
import { misskeyApi } from '@/scripts/misskey-api.js';
const XNoteSimple = defineAsyncComponent(() =>
(defaultStore.state.noteDesign === 'misskey') ? import('@/components/MkNoteSimple.vue') :
(defaultStore.state.noteDesign === 'sharkey') ? import('@/components/SkNoteSimple.vue') :
null
const XNoteSimple = defineAsyncComponent<typeof MkNoteSimple | typeof SkNoteSimple>(() =>
defaultStore.state.noteDesign === 'misskey'
? import('@/components/MkNoteSimple.vue')
: import('@/components/SkNoteSimple.vue'),
);
type SummalyResult = Awaited<ReturnType<typeof summaly>>;
@ -111,12 +113,13 @@ const props = withDefaults(defineProps<{
compact?: boolean;
showAsQuote?: boolean;
showActions?: boolean;
skipNoteIds?: string[];
skipNoteIds?: (string | undefined)[];
}>(), {
detail: false,
compact: false,
showAsQuote: false,
showActions: true,
skipNoteIds: undefined,
});
const MOBILE_THRESHOLD = 500;

View file

@ -0,0 +1,43 @@
<!--
SPDX-FileCopyrightText: hazelnoot and other Sharkey contributors
SPDX-License-Identifier: AGPL-3.0-only
-->
<template>
<!-- Match appearance of MkRemoteCaution.vue -->
<div v-for="error of displayErrors" :key="error" :class="$style.root">
<i :class="$style.icon" class="ti ti-alert-triangle"></i>{{ i18n.ts._processErrors[error] ?? error }}
</div>
</template>
<script setup lang="ts">
import { computed } from 'vue';
import { i18n } from '@/i18n.js';
const props = defineProps<{
errors?: string[] | null;
}>();
const displayErrors = computed<Iterable<string>>(() => {
if (!props.errors?.length) return [];
// Set constructor preserve order, so we can sort first to avoid a copy operation.
return new Set(props.errors.toSorted());
});
</script>
<style module lang="scss">
.root {
font-size: 0.8em;
padding: 16px;
background: color-mix(in srgb, var(--MI_THEME-infoWarnBg) 65%, transparent);
color: var(--MI_THEME-infoWarnFg);
border-radius: var(--MI-radius);
overflow: clip;
z-index: 1;
}
.icon {
margin-right: 8px;
}
</style>

View file

@ -104,7 +104,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</div>
<MkPoll v-if="appearNote.poll" :noteId="appearNote.id" :poll="appearNote.poll" :local="!appearNote.user.host" :author="appearNote.user" :emojiUrls="appearNote.emojis" :class="$style.poll" @click.stop/>
<div v-if="isEnabledUrlPreview">
<MkUrlPreview v-for="url in urls" :key="url" :url="url" :compact="true" :detail="false" :showAsQuote="true" :skipNoteIds="[appearNote.renote?.id]" :class="$style.urlPreview" @click.stop/>
<MkUrlPreview v-for="url in urls" :key="url" :url="url" :compact="true" :detail="false" :showAsQuote="!appearNote.user.rejectQuotes" :skipNoteIds="[appearNote.renote?.id]" :class="$style.urlPreview" @click.stop/>
</div>
<div v-if="appearNote.renote" :class="$style.quote"><SkNoteSimple :note="appearNote.renote" :class="$style.quoteNote"/></div>
<button v-if="isLong && collapsed" :class="$style.collapsed" class="_button" @click.stop @click="collapsed = false">
@ -143,7 +143,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<i class="ti ti-ban"></i>
</button>
<button
v-if="canRenote && !props.mock"
v-if="canRenote && !props.mock && !$i?.rejectQuotes"
ref="quoteButton"
:class="$style.footerButton"
class="_button"

View file

@ -122,7 +122,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</div>
<MkPoll v-if="appearNote.poll" ref="pollViewer" :noteId="appearNote.id" :poll="appearNote.poll" :local="!appearNote.user.host" :class="$style.poll" :author="appearNote.user" :emojiUrls="appearNote.emojis"/>
<div v-if="isEnabledUrlPreview">
<MkUrlPreview v-for="url in urls" :key="url" :url="url" :compact="true" :detail="true" :showAsQuote="true" :skipNoteIds="[appearNote.renote?.id]" style="margin-top: 6px;"/>
<MkUrlPreview v-for="url in urls" :key="url" :url="url" :compact="true" :detail="true" :showAsQuote="!appearNote.user.rejectQuotes" :skipNoteIds="[appearNote.renote?.id]" style="margin-top: 6px;"/>
</div>
<div v-if="appearNote.renote" :class="$style.quote"><SkNoteSimple :note="appearNote.renote" :class="$style.quoteNote" :expandAllCws="props.expandAllCws"/></div>
</div>
@ -158,7 +158,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<i class="ti ti-ban"></i>
</button>
<button
v-if="canRenote"
v-if="canRenote && !$i?.rejectQuotes"
ref="quoteButton"
class="_button"
:class="$style.noteFooterButton"

View file

@ -46,7 +46,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<p v-if="note.renoteCount > 0" :class="$style.noteFooterButtonCount">{{ note.renoteCount }}</p>
</button>
<button
v-if="canRenote"
v-if="canRenote && !$i?.rejectQuotes"
ref="quoteButton"
class="_button"
:class="$style.noteFooterButton"

View file

@ -7,7 +7,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<div class="_gaps" :class="$style.textRoot">
<Mfm :text="block.text ?? ''" :isBlock="true" :isNote="false"/>
<div v-if="isEnabledUrlPreview" class="_gaps_s">
<MkUrlPreview v-for="url in urls" :key="url" :url="url"/>
<MkUrlPreview v-for="url in urls" :key="url" :url="url" :showAsQuote="!page.user.rejectQuotes"/>
</div>
</div>
</template>