Merge branch 'develop' into future-2024-05-31

This commit is contained in:
dakkar 2024-06-13 09:06:24 +01:00
commit b2cbd507fe
44 changed files with 223 additions and 79 deletions

View File

@ -760,6 +760,10 @@ noCrawleDescription: "Ask search engines to not index your profile page, notes,
lockedAccountInfo: "Unless you set your note visiblity to \"Followers only\", your notes will be visible to anyone, even if you require followers to be manually approved." lockedAccountInfo: "Unless you set your note visiblity to \"Followers only\", your notes will be visible to anyone, even if you require followers to be manually approved."
alwaysMarkSensitive: "Mark as sensitive by default" alwaysMarkSensitive: "Mark as sensitive by default"
loadRawImages: "Load original images instead of showing thumbnails" loadRawImages: "Load original images instead of showing thumbnails"
searchEngine: "Search Engine For Search MFM"
searchEngineOther: "Other"
searchEngineCustomURIDescription: "The custom URI must be input in the format like \"https://www.google.com/search?q=\\{query}\" or \"https://www.google.com/search?q=%s\"."
searchEngineCusomURI: "Custom URI"
disableShowingAnimatedImages: "Don't play animated images" disableShowingAnimatedImages: "Don't play animated images"
highlightSensitiveMedia: "Highlight sensitive media" highlightSensitiveMedia: "Highlight sensitive media"
verificationEmailSent: "A verification email has been sent. Please follow the included link to complete verification." verificationEmailSent: "A verification email has been sent. Please follow the included link to complete verification."
@ -1880,6 +1884,7 @@ _aboutMisskey:
morePatrons: "We also appreciate the support of many other helpers not listed here. Thank you! 🥰" morePatrons: "We also appreciate the support of many other helpers not listed here. Thank you! 🥰"
patrons: "Patrons" patrons: "Patrons"
projectMembers: "Project members" projectMembers: "Project members"
testers: "Testers"
_displayOfSensitiveMedia: _displayOfSensitiveMedia:
respect: "Hide media marked as sensitive" respect: "Hide media marked as sensitive"
ignore: "Display media marked as sensitive" ignore: "Display media marked as sensitive"

View File

@ -6,7 +6,10 @@ import ts from 'typescript';
const __filename = fileURLToPath(import.meta.url); const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename); const __dirname = dirname(__filename);
const parameterRegExp = /\{(\w+)\}/g; // braces preceded by backslashes are literal, they don't represent
// parameters; they get cleaned up by `locales/index.js` before
// getting shipped to the browser
const parameterRegExp = /(?<!\\)\{(\w+)\}/g;
function createMemberType(item) { function createMemberType(item) {
if (typeof item !== 'string') { if (typeof item !== 'string') {

20
locales/index.d.ts vendored
View File

@ -3052,6 +3052,22 @@ export interface Locale extends ILocale {
* *
*/ */
"loadRawImages": string; "loadRawImages": string;
/**
* MFMの検索エンジン
*/
"searchEngine": string;
/**
*
*/
"searchEngineOther": string;
/**
* URI "https://www.google.com/search?q=\{query}" "https://www.google.com/search?q=%s"
*/
"searchEngineCustomURIDescription": string;
/**
* URI
*/
"searchEngineCusomURI": string;
/** /**
* *
*/ */
@ -7304,6 +7320,10 @@ export interface Locale extends ILocale {
* *
*/ */
"projectMembers": string; "projectMembers": string;
/**
*
*/
"testers": string;
}; };
"_displayOfSensitiveMedia": { "_displayOfSensitiveMedia": {
/** /**

View File

@ -49,7 +49,11 @@ const primaries = {
}; };
// 何故か文字列にバックスペース文字が混入することがあり、YAMLが壊れるので取り除く // 何故か文字列にバックスペース文字が混入することがあり、YAMLが壊れるので取り除く
const clean = (text) => text.replace(new RegExp(String.fromCodePoint(0x08), 'g'), ''); //
// also, we remove the backslashes in front of open braces (the
// backslashes are only needed to tell `generateDTS.js` that the
// braces do not represent parameters)
const clean = (text) => text.replace(new RegExp(String.fromCodePoint(0x08), 'g'), '').replaceAll(new RegExp(/\\+\{/,'g'), '{');
export function build() { export function build() {
const locales = languages.reduce((a, c) => (a[c] = yaml.load(clean(fs.readFileSync(new URL(`${c}.yml`, import.meta.url), 'utf-8'))) || {}, a), {}); const locales = languages.reduce((a, c) => (a[c] = yaml.load(clean(fs.readFileSync(new URL(`${c}.yml`, import.meta.url), 'utf-8'))) || {}, a), {});

View File

@ -759,6 +759,10 @@ noCrawleDescription: "外部の検索エンジンにあなたのユーザーペ
lockedAccountInfo: "フォローを承認制にしても、ノートの公開範囲を「フォロワー」にしない限り、誰でもあなたのノートを見ることができます。" lockedAccountInfo: "フォローを承認制にしても、ノートの公開範囲を「フォロワー」にしない限り、誰でもあなたのノートを見ることができます。"
alwaysMarkSensitive: "デフォルトでメディアをセンシティブ設定にする" alwaysMarkSensitive: "デフォルトでメディアをセンシティブ設定にする"
loadRawImages: "添付画像のサムネイルをオリジナル画質にする" loadRawImages: "添付画像のサムネイルをオリジナル画質にする"
searchEngine: "検索MFMの検索エンジン"
searchEngineOther: "他"
searchEngineCustomURIDescription: "カスタム URI は、\"https://www.google.com/search?q=\\{query}\" や \"https://www.google.com/search?q=%s\" のような形式で入力する必要があります。"
searchEngineCusomURI: "カスタム URI"
disableShowingAnimatedImages: "アニメーション画像を再生しない" disableShowingAnimatedImages: "アニメーション画像を再生しない"
highlightSensitiveMedia: "メディアがセンシティブであることを分かりやすく表示" highlightSensitiveMedia: "メディアがセンシティブであることを分かりやすく表示"
verificationEmailSent: "確認のメールを送信しました。メールに記載されたリンクにアクセスして、設定を完了してください。" verificationEmailSent: "確認のメールを送信しました。メールに記載されたリンクにアクセスして、設定を完了してください。"
@ -1903,6 +1907,7 @@ _aboutMisskey:
morePatrons: "他にも多くの方が支援してくれています。ありがとうございます🥰" morePatrons: "他にも多くの方が支援してくれています。ありがとうございます🥰"
patrons: "支援者" patrons: "支援者"
projectMembers: "プロジェクトメンバー" projectMembers: "プロジェクトメンバー"
testers: "テスター"
_displayOfSensitiveMedia: _displayOfSensitiveMedia:
respect: "センシティブ設定されたメディアを隠す" respect: "センシティブ設定されたメディアを隠す"

View File

@ -132,9 +132,18 @@ export class MfmService {
case 'h1': case 'h1':
{ {
text += '【'; text += '**【';
appendChildren(node.childNodes); appendChildren(node.childNodes);
text += '】\n'; text += '】**\n';
break;
}
case 'h2':
case 'h3':
{
text += '**';
appendChildren(node.childNodes);
text += '**\n';
break; break;
} }
@ -203,8 +212,6 @@ export class MfmService {
} }
case 'p': case 'p':
case 'h2':
case 'h3':
case 'h4': case 'h4':
case 'h5': case 'h5':
case 'h6': case 'h6':

View File

@ -30,8 +30,9 @@ export const meta = {
prohibitMoved: true, prohibitMoved: true,
limit: { limit: {
duration: ms('1minute'), duration: ms('1hour'),
max: 5, max: 300,
minInterval: ms('1sec'),
}, },
kind: 'write:notes', kind: 'write:notes',

View File

@ -236,7 +236,7 @@ export async function mainBoot() {
if (Date.now() - lastUsedDate > 1000 * 60 * 60 * 2) { if (Date.now() - lastUsedDate > 1000 * 60 * 60 * 2) {
toast(i18n.tsx.welcomeBackWithName({ toast(i18n.tsx.welcomeBackWithName({
name: $i.name || $i.username, name: $i.name || $i.username,
})); }), true);
} }
} }
miLocalStorage.setItem('lastUsed', Date.now().toString()); miLocalStorage.setItem('lastUsed', Date.now().toString());

View File

@ -20,7 +20,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</div> </div>
<div class="detail"> <div class="detail">
<div> <div>
<Mfm :text="report.comment" :linkNavigationBehavior="'window'"/> <Mfm :text="report.comment" :isBlock="true" :linkNavigationBehavior="'window'"/>
</div> </div>
<hr/> <hr/>
<div>{{ i18n.ts.reporter }}: <MkA :to="`/admin/user/${report.reporter.id}`" class="_link" :behavior="'window'">@{{ report.reporter.username }}</MkA></div> <div>{{ i18n.ts.reporter }}: <MkA :to="`/admin/user/${report.reporter.id}`" class="_link" :behavior="'window'">@{{ report.reporter.username }}</MkA></div>

View File

@ -15,7 +15,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</span> </span>
<span :class="$style.title">{{ announcement.title }}</span> <span :class="$style.title">{{ announcement.title }}</span>
</div> </div>
<div :class="$style.text"><Mfm :text="announcement.text"/></div> <div :class="$style.text"><Mfm :text="announcement.text" :isBlock="true" /></div>
<MkButton primary full @click="ok">{{ i18n.ts.ok }}</MkButton> <MkButton primary full @click="ok">{{ i18n.ts.ok }}</MkButton>
</div> </div>
</MkModal> </MkModal>

View File

@ -26,7 +26,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<MkLoading v-else-if="type === 'waiting'" :class="$style.iconInner" :em="true"/> <MkLoading v-else-if="type === 'waiting'" :class="$style.iconInner" :em="true"/>
</div> </div>
<header v-if="title" :class="$style.title"><Mfm :text="title"/></header> <header v-if="title" :class="$style.title"><Mfm :text="title"/></header>
<div v-if="text" :class="$style.text"><Mfm :text="text"/></div> <div v-if="text" :class="$style.text"><Mfm :text="text" :isBlock="true" /></div>
<MkInput v-if="input" v-model="inputValue" autofocus :type="input.type || 'text'" :placeholder="input.placeholder || undefined" :autocomplete="input.autocomplete" @keydown="onInputKeydown"> <MkInput v-if="input" v-model="inputValue" autofocus :type="input.type || 'text'" :placeholder="input.placeholder || undefined" :autocomplete="input.autocomplete" @keydown="onInputKeydown">
<template v-if="input.type === 'password'" #prefix><i class="ph-lock ph-bold ph-lg"></i></template> <template v-if="input.type === 'password'" #prefix><i class="ph-lock ph-bold ph-lg"></i></template>
<template #caption> <template #caption>

View File

@ -13,6 +13,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<script lang="ts" setup> <script lang="ts" setup>
import { ref } from 'vue'; import { ref } from 'vue';
import { i18n } from '@/i18n.js'; import { i18n } from '@/i18n.js';
import { defaultStore } from '@/store';
const props = defineProps<{ const props = defineProps<{
q: string; q: string;
@ -21,9 +22,10 @@ const props = defineProps<{
const query = ref(props.q); const query = ref(props.q);
const search = () => { const search = () => {
const sp = new URLSearchParams(); const searchQuery = encodeURIComponent(query.value);
sp.append('q', query.value); const searchUrl = defaultStore.state.searchEngine.replace(/{query}|%s\b/g, searchQuery);
window.open(`https://www.google.com/search?${sp.toString()}`, '_blank', 'noopener');
window.open(searchUrl, '_blank', 'noopener');
}; };
</script> </script>

View File

@ -44,7 +44,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</div> </div>
<div v-if="renoteCollapsed" :class="$style.collapsedRenoteTarget"> <div v-if="renoteCollapsed" :class="$style.collapsedRenoteTarget">
<MkAvatar :class="$style.collapsedRenoteTargetAvatar" :user="appearNote.user" link preview/> <MkAvatar :class="$style.collapsedRenoteTargetAvatar" :user="appearNote.user" link preview/>
<Mfm :text="getNoteSummary(appearNote)" :plain="true" :nowrap="true" :author="appearNote.user" :nyaize="'respect'" :class="$style.collapsedRenoteTargetText" @click="renoteCollapsed = false"/> <Mfm :text="getNoteSummary(appearNote)" :isBlock="true" :plain="true" :nowrap="true" :author="appearNote.user" :nyaize="'respect'" :class="$style.collapsedRenoteTargetText" @click="renoteCollapsed = false"/>
</div> </div>
<article v-else :class="$style.article" @contextmenu.stop="onContextmenu"> <article v-else :class="$style.article" @contextmenu.stop="onContextmenu">
<div v-if="appearNote.channel" :class="$style.colorBar" :style="{ background: appearNote.channel.color }"></div> <div v-if="appearNote.channel" :class="$style.colorBar" :style="{ background: appearNote.channel.color }"></div>
@ -53,8 +53,9 @@ SPDX-License-Identifier: AGPL-3.0-only
<MkNoteHeader :note="appearNote" :mini="true" @click.stop/> <MkNoteHeader :note="appearNote" :mini="true" @click.stop/>
<MkInstanceTicker v-if="showTicker" :instance="appearNote.user.instance"/> <MkInstanceTicker v-if="showTicker" :instance="appearNote.user.instance"/>
<div style="container-type: inline-size;"> <div style="container-type: inline-size;">
<bdi>
<p v-if="appearNote.cw != null" :class="$style.cw"> <p v-if="appearNote.cw != null" :class="$style.cw">
<Mfm v-if="appearNote.cw != ''" style="margin-right: 8px;" :text="appearNote.cw" :author="appearNote.user" :nyaize="'respect'"/> <Mfm v-if="appearNote.cw != ''" style="margin-right: 8px;" :text="appearNote.cw" :isBlock="true" :author="appearNote.user" :nyaize="'respect'"/>
<MkCwButton v-model="showContent" :text="appearNote.text" :renote="appearNote.renote" :files="appearNote.files" :poll="appearNote.poll" style="margin: 4px 0;" @click.stop/> <MkCwButton v-model="showContent" :text="appearNote.text" :renote="appearNote.renote" :files="appearNote.files" :poll="appearNote.poll" style="margin: 4px 0;" @click.stop/>
</p> </p>
<div v-show="appearNote.cw == null || showContent" :class="[{ [$style.contentCollapsed]: collapsed }]"> <div v-show="appearNote.cw == null || showContent" :class="[{ [$style.contentCollapsed]: collapsed }]">
@ -71,12 +72,13 @@ SPDX-License-Identifier: AGPL-3.0-only
:enableEmojiMenu="true" :enableEmojiMenu="true"
:enableEmojiMenuReaction="true" :enableEmojiMenuReaction="true"
:isAnim="allowAnim" :isAnim="allowAnim"
:isBlock="true"
/> />
<div v-if="translating || translation" :class="$style.translation"> <div v-if="translating || translation" :class="$style.translation">
<MkLoading v-if="translating" mini/> <MkLoading v-if="translating" mini/>
<div v-else-if="translation"> <div v-else-if="translation">
<b>{{ i18n.tsx.translatedFrom({ x: translation.sourceLang }) }}: </b> <b>{{ i18n.tsx.translatedFrom({ x: translation.sourceLang }) }}: </b>
<Mfm :text="translation.text" :author="appearNote.user" :nyaize="'respect'" :emojiUrls="appearNote.emojis"/> <Mfm :text="translation.text" :isBlock="true" :author="appearNote.user" :nyaize="'respect'" :emojiUrls="appearNote.emojis"/>
</div> </div>
</div> </div>
<MkButton v-if="!allowAnim && animated" :class="$style.playMFMButton" :small="true" @click="animatedMFM()" @click.stop><i class="ph-play ph-bold ph-lg "></i> {{ i18n.ts._animatedMFM.play }}</MkButton> <MkButton v-if="!allowAnim && animated" :class="$style.playMFMButton" :small="true" @click="animatedMFM()" @click.stop><i class="ph-play ph-bold ph-lg "></i> {{ i18n.ts._animatedMFM.play }}</MkButton>
@ -98,6 +100,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</button> </button>
</div> </div>
<MkA v-if="appearNote.channel && !inChannel" :class="$style.channel" :to="`/channels/${appearNote.channel.id}`"><i class="ph-television ph-bold ph-lg"></i> {{ appearNote.channel.name }}</MkA> <MkA v-if="appearNote.channel && !inChannel" :class="$style.channel" :to="`/channels/${appearNote.channel.id}`"><i class="ph-television ph-bold ph-lg"></i> {{ appearNote.channel.name }}</MkA>
</bdi>
</div> </div>
<MkReactionsViewer v-if="appearNote.reactionAcceptance !== 'likeOnly'" :note="appearNote" :maxNumber="16" @click.stop @mockUpdateMyReaction="emitUpdReaction"> <MkReactionsViewer v-if="appearNote.reactionAcceptance !== 'likeOnly'" :note="appearNote" :maxNumber="16" @click.stop @mockUpdateMyReaction="emitUpdReaction">
<template #more> <template #more>
@ -339,7 +342,7 @@ let renoting = false;
const keymap = { const keymap = {
'r': () => reply(true), 'r': () => reply(true),
'e|a|plus': () => react(true), 'e|a|plus': () => react(true),
'(q)': () => { if (canRenote.value && !renoted.value && !renoting) { renoting = true; renote(appearNote.value.visibility); } }, '(q)': () => { if (canRenote.value && !renoted.value && !renoting) renote(defaultStore.state.visibilityOnBoost); },
'up|k|shift+tab': focusBefore, 'up|k|shift+tab': focusBefore,
'down|j|tab': focusAfter, 'down|j|tab': focusAfter,
'esc': blur, 'esc': blur,
@ -439,6 +442,8 @@ if (!props.mock) {
} }
function boostVisibility() { function boostVisibility() {
if (renoting) return;
if (!defaultStore.state.showVisibilitySelectorOnBoost) { if (!defaultStore.state.showVisibilitySelectorOnBoost) {
renote(defaultStore.state.visibilityOnBoost); renote(defaultStore.state.visibilityOnBoost);
} else { } else {
@ -450,6 +455,8 @@ function renote(visibility: Visibility, localOnly: boolean = false) {
pleaseLogin(); pleaseLogin();
showMovedDialog(); showMovedDialog();
renoting = true;
if (appearNote.value.channel) { if (appearNote.value.channel) {
const el = renoteButton.value as HTMLElement | null | undefined; const el = renoteButton.value as HTMLElement | null | undefined;
if (el) { if (el) {

View File

@ -68,7 +68,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</header> </header>
<div :class="$style.noteContent"> <div :class="$style.noteContent">
<p v-if="appearNote.cw != null" :class="$style.cw"> <p v-if="appearNote.cw != null" :class="$style.cw">
<Mfm v-if="appearNote.cw != ''" style="margin-right: 8px;" :text="appearNote.cw" :author="appearNote.user" :nyaize="'respect'"/> <Mfm v-if="appearNote.cw != ''" style="margin-right: 8px;" :text="appearNote.cw" :isBlock="true" :author="appearNote.user" :nyaize="'respect'"/>
<MkCwButton v-model="showContent" :text="appearNote.text" :renote="appearNote.renote" :files="appearNote.files" :poll="appearNote.poll"/> <MkCwButton v-model="showContent" :text="appearNote.text" :renote="appearNote.renote" :files="appearNote.files" :poll="appearNote.poll"/>
</p> </p>
<div v-show="appearNote.cw == null || showContent"> <div v-show="appearNote.cw == null || showContent">
@ -84,13 +84,14 @@ SPDX-License-Identifier: AGPL-3.0-only
:enableEmojiMenu="true" :enableEmojiMenu="true"
:enableEmojiMenuReaction="true" :enableEmojiMenuReaction="true"
:isAnim="allowAnim" :isAnim="allowAnim"
:isBlock="true"
/> />
<a v-if="appearNote.renote != null" :class="$style.rn">RN:</a> <a v-if="appearNote.renote != null" :class="$style.rn">RN:</a>
<div v-if="translating || translation" :class="$style.translation"> <div v-if="translating || translation" :class="$style.translation">
<MkLoading v-if="translating" mini/> <MkLoading v-if="translating" mini/>
<div v-else-if="translation"> <div v-else-if="translation">
<b>{{ i18n.tsx.translatedFrom({ x: translation.sourceLang }) }}: </b> <b>{{ i18n.tsx.translatedFrom({ x: translation.sourceLang }) }}: </b>
<Mfm :text="translation.text" :author="appearNote.user" :nyaize="'respect'" :emojiUrls="appearNote.emojis"/> <Mfm :text="translation.text" :isBlock="true" :author="appearNote.user" :nyaize="'respect'" :emojiUrls="appearNote.emojis"/>
</div> </div>
</div> </div>
<MkButton v-if="!allowAnim && animated" :class="$style.playMFMButton" :small="true" @click="animatedMFM()" @click.stop><i class="ph-play ph-bold ph-lg "></i> {{ i18n.ts._animatedMFM.play }}</MkButton> <MkButton v-if="!allowAnim && animated" :class="$style.playMFMButton" :small="true" @click="animatedMFM()" @click.stop><i class="ph-play ph-bold ph-lg "></i> {{ i18n.ts._animatedMFM.play }}</MkButton>
@ -351,7 +352,7 @@ let renoting = false;
const keymap = { const keymap = {
'r': () => reply(true), 'r': () => reply(true),
'e|a|plus': () => react(true), 'e|a|plus': () => react(true),
'(q)': () => { if (canRenote.value && !renoted.value && !renoting) { renoting = true; renote(appearNote.value.visibility); } }, '(q)': () => { if (canRenote.value && !renoted.value && !renoting) renote(defaultStore.state.visibilityOnBoost); },
'esc': blur, 'esc': blur,
'm|o': () => showMenu(true), 'm|o': () => showMenu(true),
's': () => showContent.value !== showContent.value, 's': () => showContent.value !== showContent.value,
@ -443,6 +444,8 @@ useTooltip(quoteButton, async (showing) => {
}); });
function boostVisibility() { function boostVisibility() {
if (renoting) return;
if (!defaultStore.state.showVisibilitySelectorOnBoost) { if (!defaultStore.state.showVisibilitySelectorOnBoost) {
renote(defaultStore.state.visibilityOnBoost); renote(defaultStore.state.visibilityOnBoost);
} else { } else {
@ -476,6 +479,8 @@ function renote(visibility: Visibility, localOnly: boolean = false) {
pleaseLogin(); pleaseLogin();
showMovedDialog(); showMovedDialog();
renoting = true;
if (appearNote.value.channel) { if (appearNote.value.channel) {
const el = renoteButton.value as HTMLElement | null | undefined; const el = renoteButton.value as HTMLElement | null | undefined;
if (el) { if (el) {

View File

@ -12,11 +12,11 @@ SPDX-License-Identifier: AGPL-3.0-only
</div> </div>
<div> <div>
<p v-if="useCw" :class="$style.cw"> <p v-if="useCw" :class="$style.cw">
<Mfm v-if="cw != null && cw != ''" :text="cw" :author="user" :nyaize="'respect'" :i="user" style="margin-right: 8px;"/> <Mfm v-if="cw != null && cw != ''" :text="cw" :isBlock="true" :author="user" :nyaize="'respect'" :i="user" style="margin-right: 8px;"/>
<MkCwButton v-model="showContent" :text="text.trim()" :files="files" :poll="poll" style="margin: 4px 0;"/> <MkCwButton v-model="showContent" :text="text.trim()" :files="files" :poll="poll" style="margin: 4px 0;"/>
</p> </p>
<div v-show="!useCw || showContent"> <div v-show="!useCw || showContent">
<Mfm :text="text.trim()" :author="user" :nyaize="'respect'" :i="user"/> <Mfm :text="text.trim()" :isBlock="true" :author="user" :nyaize="'respect'" :i="user"/>
</div> </div>
</div> </div>
</div> </div>

View File

@ -10,7 +10,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<MkNoteHeader :class="$style.header" :note="note" :mini="true"/> <MkNoteHeader :class="$style.header" :note="note" :mini="true"/>
<div> <div>
<p v-if="note.cw != null" :class="$style.cw"> <p v-if="note.cw != null" :class="$style.cw">
<Mfm v-if="note.cw != ''" style="margin-right: 8px;" :text="note.cw" :author="note.user" :nyaize="'respect'" :emojiUrls="note.emojis"/> <Mfm v-if="note.cw != ''" style="margin-right: 8px;" :text="note.cw" :isBlock="true" :author="note.user" :nyaize="'respect'" :emojiUrls="note.emojis"/>
<MkCwButton v-model="showContent" :text="note.text" :files="note.files" :poll="note.poll" @click.stop/> <MkCwButton v-model="showContent" :text="note.text" :files="note.files" :poll="note.poll" @click.stop/>
</p> </p>
<div v-show="note.cw == null || showContent"> <div v-show="note.cw == null || showContent">

View File

@ -12,7 +12,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<MkNoteHeader :class="$style.header" :note="note" :mini="true"/> <MkNoteHeader :class="$style.header" :note="note" :mini="true"/>
<div :class="$style.content"> <div :class="$style.content">
<p v-if="note.cw != null" :class="$style.cw"> <p v-if="note.cw != null" :class="$style.cw">
<Mfm v-if="note.cw != ''" style="margin-right: 8px;" :text="note.cw" :author="note.user" :nyaize="'respect'"/> <Mfm v-if="note.cw != ''" style="margin-right: 8px;" :text="note.cw" :isBlock="true" :author="note.user" :nyaize="'respect'"/>
<MkCwButton v-model="showContent" :text="note.text" :files="note.files" :poll="note.poll"/> <MkCwButton v-model="showContent" :text="note.text" :files="note.files" :poll="note.poll"/>
</p> </p>
<div v-show="note.cw == null || showContent"> <div v-show="note.cw == null || showContent">

View File

@ -71,29 +71,29 @@ SPDX-License-Identifier: AGPL-3.0-only
<div> <div>
<MkA v-if="notification.type === 'reaction' || notification.type === 'reaction:grouped'" :class="$style.text" :to="notePage(notification.note)" :title="getNoteSummary(notification.note)"> <MkA v-if="notification.type === 'reaction' || notification.type === 'reaction:grouped'" :class="$style.text" :to="notePage(notification.note)" :title="getNoteSummary(notification.note)">
<i class="ph-quotes ph-bold ph-lg" :class="$style.quote"></i> <i class="ph-quotes ph-bold ph-lg" :class="$style.quote"></i>
<Mfm :text="getNoteSummary(notification.note)" :plain="true" :nowrap="true" :author="notification.note.user"/> <Mfm :text="getNoteSummary(notification.note)" :isBlock="true" :plain="true" :nowrap="true" :author="notification.note.user"/>
<i class="ph-quotes ph-bold ph-lg" :class="$style.quote"></i> <i class="ph-quotes ph-bold ph-lg" :class="$style.quote"></i>
</MkA> </MkA>
<MkA v-else-if="notification.type === 'renote' || notification.type === 'renote:grouped'" :class="$style.text" :to="notePage(notification.note)" :title="getNoteSummary(notification.note.renote)"> <MkA v-else-if="notification.type === 'renote' || notification.type === 'renote:grouped'" :class="$style.text" :to="notePage(notification.note)" :title="getNoteSummary(notification.note.renote)">
<i class="ph-quotes ph-bold ph-lg" :class="$style.quote"></i> <i class="ph-quotes ph-bold ph-lg" :class="$style.quote"></i>
<Mfm :text="getNoteSummary(notification.note.renote)" :plain="true" :nowrap="true" :author="notification.note.renote?.user"/> <Mfm :text="getNoteSummary(notification.note.renote)" :isBlock="true" :plain="true" :nowrap="true" :author="notification.note.renote?.user"/>
<i class="ph-quotes ph-bold ph-lg" :class="$style.quote"></i> <i class="ph-quotes ph-bold ph-lg" :class="$style.quote"></i>
</MkA> </MkA>
<MkA v-else-if="notification.type === 'reply'" :class="$style.text" :to="notePage(notification.note)" :title="getNoteSummary(notification.note)"> <MkA v-else-if="notification.type === 'reply'" :class="$style.text" :to="notePage(notification.note)" :title="getNoteSummary(notification.note)">
<Mfm :text="getNoteSummary(notification.note)" :plain="true" :nowrap="true" :author="notification.note.user"/> <Mfm :text="getNoteSummary(notification.note)" :isBlock="true" :plain="true" :nowrap="true" :author="notification.note.user"/>
</MkA> </MkA>
<MkA v-else-if="notification.type === 'mention'" :class="$style.text" :to="notePage(notification.note)" :title="getNoteSummary(notification.note)"> <MkA v-else-if="notification.type === 'mention'" :class="$style.text" :to="notePage(notification.note)" :title="getNoteSummary(notification.note)">
<Mfm :text="getNoteSummary(notification.note)" :plain="true" :nowrap="true" :author="notification.note.user"/> <Mfm :text="getNoteSummary(notification.note)" :isBlock="true" :plain="true" :nowrap="true" :author="notification.note.user"/>
</MkA> </MkA>
<MkA v-else-if="notification.type === 'quote'" :class="$style.text" :to="notePage(notification.note)" :title="getNoteSummary(notification.note)"> <MkA v-else-if="notification.type === 'quote'" :class="$style.text" :to="notePage(notification.note)" :title="getNoteSummary(notification.note)">
<Mfm :text="getNoteSummary(notification.note)" :plain="true" :nowrap="true" :author="notification.note.user"/> <Mfm :text="getNoteSummary(notification.note)" :isBlock="true" :plain="true" :nowrap="true" :author="notification.note.user"/>
</MkA> </MkA>
<MkA v-else-if="notification.type === 'note'" :class="$style.text" :to="notePage(notification.note)" :title="getNoteSummary(notification.note)"> <MkA v-else-if="notification.type === 'note'" :class="$style.text" :to="notePage(notification.note)" :title="getNoteSummary(notification.note)">
<Mfm :text="getNoteSummary(notification.note)" :plain="true" :nowrap="true" :author="notification.note.user"/> <Mfm :text="getNoteSummary(notification.note)" :isBlock="true" :plain="true" :nowrap="true" :author="notification.note.user"/>
</MkA> </MkA>
<MkA v-else-if="notification.type === 'pollEnded'" :class="$style.text" :to="notePage(notification.note)" :title="getNoteSummary(notification.note)"> <MkA v-else-if="notification.type === 'pollEnded'" :class="$style.text" :to="notePage(notification.note)" :title="getNoteSummary(notification.note)">
<i class="ph-quotes ph-bold ph-lg" :class="$style.quote"></i> <i class="ph-quotes ph-bold ph-lg" :class="$style.quote"></i>
<Mfm :text="getNoteSummary(notification.note)" :plain="true" :nowrap="true" :author="notification.note.user"/> <Mfm :text="getNoteSummary(notification.note)" :isBlock="true" :plain="true" :nowrap="true" :author="notification.note.user"/>
<i class="ph-quotes ph-bold ph-lg" :class="$style.quote"></i> <i class="ph-quotes ph-bold ph-lg" :class="$style.quote"></i>
</MkA> </MkA>
<div v-else-if="notification.type === 'roleAssigned'" :class="$style.text"> <div v-else-if="notification.type === 'roleAssigned'" :class="$style.text">
@ -139,7 +139,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<MkA v-else-if="notification.type === 'edited'" :class="$style.text" :to="notePage(notification.note)" :title="getNoteSummary(notification.note)"> <MkA v-else-if="notification.type === 'edited'" :class="$style.text" :to="notePage(notification.note)" :title="getNoteSummary(notification.note)">
<i class="ph-quotes ph-bold ph-lg" :class="$style.quote"></i> <i class="ph-quotes ph-bold ph-lg" :class="$style.quote"></i>
<Mfm :text="getNoteSummary(notification.note)" :plain="true" :nowrap="true" :author="notification.note.user"/> <Mfm :text="getNoteSummary(notification.note)" :isBlock="true" :plain="true" :nowrap="true" :author="notification.note.user"/>
<i class="ph-quotes ph-bold ph-lg" :class="$style.quote"></i> <i class="ph-quotes ph-bold ph-lg" :class="$style.quote"></i>
</MkA> </MkA>
</div> </div>

View File

@ -9,14 +9,14 @@ SPDX-License-Identifier: AGPL-3.0-only
<span v-if="note.isHidden" style="opacity: 0.5">({{ i18n.ts.private }})</span> <span v-if="note.isHidden" style="opacity: 0.5">({{ i18n.ts.private }})</span>
<span v-if="note.deletedAt" style="opacity: 0.5">({{ i18n.ts.deletedNote }})</span> <span v-if="note.deletedAt" style="opacity: 0.5">({{ i18n.ts.deletedNote }})</span>
<MkA v-if="note.replyId" :class="$style.reply" :to="`/notes/${note.replyId}`" @click.stop><i class="ph-arrow-bend-left-up ph-bold ph-lg"></i></MkA> <MkA v-if="note.replyId" :class="$style.reply" :to="`/notes/${note.replyId}`" @click.stop><i class="ph-arrow-bend-left-up ph-bold ph-lg"></i></MkA>
<Mfm v-if="note.text" :text="note.text" :author="note.user" :nyaize="'respect'" :isAnim="allowAnim" :emojiUrls="note.emojis"/> <Mfm v-if="note.text" :text="note.text" :isBlock="true" :author="note.user" :nyaize="'respect'" :isAnim="allowAnim" :emojiUrls="note.emojis"/>
<MkButton v-if="!allowAnim && animated && !hideFiles" :class="$style.playMFMButton" :small="true" @click="animatedMFM()" @click.stop><i class="ph-play ph-bold ph-lg "></i> {{ i18n.ts._animatedMFM.play }}</MkButton> <MkButton v-if="!allowAnim && animated && !hideFiles" :class="$style.playMFMButton" :small="true" @click="animatedMFM()" @click.stop><i class="ph-play ph-bold ph-lg "></i> {{ i18n.ts._animatedMFM.play }}</MkButton>
<MkButton v-else-if="!defaultStore.state.animatedMfm && allowAnim && animated && !hideFiles" :class="$style.playMFMButton" :small="true" @click="animatedMFM()" @click.stop><i class="ph-stop ph-bold ph-lg "></i> {{ i18n.ts._animatedMFM.stop }}</MkButton> <MkButton v-else-if="!defaultStore.state.animatedMfm && allowAnim && animated && !hideFiles" :class="$style.playMFMButton" :small="true" @click="animatedMFM()" @click.stop><i class="ph-stop ph-bold ph-lg "></i> {{ i18n.ts._animatedMFM.stop }}</MkButton>
<div v-if="note.text && translating || note.text && translation" :class="$style.translation"> <div v-if="note.text && translating || note.text && translation" :class="$style.translation">
<MkLoading v-if="translating" mini/> <MkLoading v-if="translating" mini/>
<div v-else> <div v-else>
<b>{{ i18n.tsx.translatedFrom({ x: translation.sourceLang }) }}: </b> <b>{{ i18n.tsx.translatedFrom({ x: translation.sourceLang }) }}: </b>
<Mfm :text="translation.text" :author="note.user" :nyaize="'respect'" :emojiUrls="note.emojis"/> <Mfm :text="translation.text" :isBlock="true" :author="note.user" :nyaize="'respect'" :emojiUrls="note.emojis"/>
</div> </div>
</div> </div>
<MkA v-if="note.renoteId" :class="$style.rp" :to="`/notes/${note.renoteId}`" @click.stop>RN: ...</MkA> <MkA v-if="note.renoteId" :class="$style.rp" :to="`/notes/${note.renoteId}`" @click.stop>RN: ...</MkA>

View File

@ -28,7 +28,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<div :class="$style.caption"><slot name="caption"></slot></div> <div :class="$style.caption"><slot name="caption"></slot></div>
<button v-if="mfmPreview" style="font-size: 0.85em;" class="_textButton" type="button" @click="preview = !preview">{{ i18n.ts.preview }}</button> <button v-if="mfmPreview" style="font-size: 0.85em;" class="_textButton" type="button" @click="preview = !preview">{{ i18n.ts.preview }}</button>
<div v-if="mfmPreview" v-show="preview" v-panel :class="$style.mfmPreview"> <div v-if="mfmPreview" v-show="preview" v-panel :class="$style.mfmPreview">
<Mfm :text="v"/> <Mfm :text="v" :isBlock="true" />
</div> </div>
<MkButton v-if="manualSave && changed" primary :class="$style.save" @click="updated"><i class="ph-floppy-disk ph-bold ph-lg"></i> {{ i18n.ts.save }}</MkButton> <MkButton v-if="manualSave && changed" primary :class="$style.save" @click="updated"><i class="ph-floppy-disk ph-bold ph-lg"></i> {{ i18n.ts.save }}</MkButton>

View File

@ -14,7 +14,8 @@ SPDX-License-Identifier: AGPL-3.0-only
> >
<div v-if="showing" class="_acrylic" :class="$style.root" :style="{ zIndex }"> <div v-if="showing" class="_acrylic" :class="$style.root" :style="{ zIndex }">
<div style="padding: 16px 24px;"> <div style="padding: 16px 24px;">
{{ message }} <Mfm v-if="renderMfm" :text="message" plain/>
<template v-else>{{ message }}</template>
</div> </div>
</div> </div>
</Transition> </Transition>
@ -26,9 +27,12 @@ import { onMounted, ref } from 'vue';
import * as os from '@/os.js'; import * as os from '@/os.js';
import { defaultStore } from '@/store.js'; import { defaultStore } from '@/store.js';
defineProps<{ withDefaults(defineProps<{
message: string; message: string;
}>(); renderMfm: boolean;
}>(), {
renderMfm: false,
});
const emit = defineEmits<{ const emit = defineEmits<{
(ev: 'closed'): void; (ev: 'closed'): void;

View File

@ -14,7 +14,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<span v-if="$i && $i.id !== user.id && user.isFollowed" :class="$style.followed">{{ i18n.ts.followsYou }}</span> <span v-if="$i && $i.id !== user.id && user.isFollowed" :class="$style.followed">{{ i18n.ts.followsYou }}</span>
<div :class="$style.description"> <div :class="$style.description">
<div v-if="user.description" :class="$style.mfm"> <div v-if="user.description" :class="$style.mfm">
<Mfm :text="user.description" :author="user"/> <Mfm :text="user.description" :isBlock="true" :author="user"/>
</div> </div>
<span v-else style="opacity: 0.7;">{{ i18n.ts.noAccountDescription }}</span> <span v-else style="opacity: 0.7;">{{ i18n.ts.noAccountDescription }}</span>
</div> </div>

View File

@ -28,7 +28,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<div :class="$style.username"><MkAcct :user="user"/></div> <div :class="$style.username"><MkAcct :user="user"/></div>
</div> </div>
<div :class="$style.description"> <div :class="$style.description">
<Mfm v-if="user.description" :nyaize="false" :class="$style.mfm" :text="user.description" :author="user"/> <Mfm v-if="user.description" :nyaize="false" :class="$style.mfm" :text="user.description" :isBlock="true" :author="user"/>
<div v-else style="opacity: 0.7;">{{ i18n.ts.noAccountDescription }}</div> <div v-else style="opacity: 0.7;">{{ i18n.ts.noAccountDescription }}</div>
</div> </div>
<div v-if="user.fields.length > 0" :class="$style.fields"> <div v-if="user.fields.length > 0" :class="$style.fields">

View File

@ -13,7 +13,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</div> </div>
<div :class="$style.description"> <div :class="$style.description">
<div v-if="user.description" :class="$style.mfm"> <div v-if="user.description" :class="$style.mfm">
<Mfm :text="user.description" :author="user"/> <Mfm :text="user.description" :isBlock="true" :author="user"/>
</div> </div>
<span v-else style="opacity: 0.7;">{{ i18n.ts.noAccountDescription }}</span> <span v-else style="opacity: 0.7;">{{ i18n.ts.noAccountDescription }}</span>
</div> </div>

View File

@ -44,7 +44,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</div> </div>
<div v-if="renoteCollapsed" :class="$style.collapsedRenoteTarget"> <div v-if="renoteCollapsed" :class="$style.collapsedRenoteTarget">
<MkAvatar :class="$style.collapsedRenoteTargetAvatar" :user="appearNote.user" link preview/> <MkAvatar :class="$style.collapsedRenoteTargetAvatar" :user="appearNote.user" link preview/>
<Mfm :text="getNoteSummary(appearNote)" :plain="true" :nowrap="true" :author="appearNote.user" :nyaize="'respect'" :class="$style.collapsedRenoteTargetText" @click="renoteCollapsed = false"/> <Mfm :text="getNoteSummary(appearNote)" :isBlock="true" :plain="true" :nowrap="true" :author="appearNote.user" :nyaize="'respect'" :class="$style.collapsedRenoteTargetText" @click="renoteCollapsed = false"/>
</div> </div>
<article v-else :class="$style.article" @contextmenu.stop="onContextmenu"> <article v-else :class="$style.article" @contextmenu.stop="onContextmenu">
<div style="display: flex; padding-bottom: 10px;"> <div style="display: flex; padding-bottom: 10px;">
@ -57,7 +57,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<div :class="[{ [$style.clickToOpen]: defaultStore.state.clickToOpen }]" @click.stop="defaultStore.state.clickToOpen ? noteclick(appearNote.id) : undefined"> <div :class="[{ [$style.clickToOpen]: defaultStore.state.clickToOpen }]" @click.stop="defaultStore.state.clickToOpen ? noteclick(appearNote.id) : undefined">
<div style="container-type: inline-size;"> <div style="container-type: inline-size;">
<p v-if="appearNote.cw != null" :class="$style.cw"> <p v-if="appearNote.cw != null" :class="$style.cw">
<Mfm v-if="appearNote.cw != ''" style="margin-right: 8px;" :text="appearNote.cw" :author="appearNote.user" :nyaize="'respect'"/> <Mfm v-if="appearNote.cw != ''" style="margin-right: 8px;" :text="appearNote.cw" :isBlock="true" :author="appearNote.user" :nyaize="'respect'"/>
<MkCwButton v-model="showContent" :text="appearNote.text" :renote="appearNote.renote" :files="appearNote.files" :poll="appearNote.poll" style="margin: 4px 0;" @click.stop/> <MkCwButton v-model="showContent" :text="appearNote.text" :renote="appearNote.renote" :files="appearNote.files" :poll="appearNote.poll" style="margin: 4px 0;" @click.stop/>
</p> </p>
<div v-show="appearNote.cw == null || showContent" :class="[{ [$style.contentCollapsed]: collapsed }]"> <div v-show="appearNote.cw == null || showContent" :class="[{ [$style.contentCollapsed]: collapsed }]">
@ -73,12 +73,13 @@ SPDX-License-Identifier: AGPL-3.0-only
:enableEmojiMenu="true" :enableEmojiMenu="true"
:enableEmojiMenuReaction="true" :enableEmojiMenuReaction="true"
:isAnim="allowAnim" :isAnim="allowAnim"
:isBlock="true"
/> />
<div v-if="translating || translation" :class="$style.translation"> <div v-if="translating || translation" :class="$style.translation">
<MkLoading v-if="translating" mini/> <MkLoading v-if="translating" mini/>
<div v-else-if="translation"> <div v-else-if="translation">
<b>{{ i18n.tsx.translatedFrom({ x: translation.sourceLang }) }}: </b> <b>{{ i18n.tsx.translatedFrom({ x: translation.sourceLang }) }}: </b>
<Mfm :text="translation.text" :author="appearNote.user" :nyaize="'respect'" :emojiUrls="appearNote.emojis"/> <Mfm :text="translation.text" :isBlock="true" :author="appearNote.user" :nyaize="'respect'" :emojiUrls="appearNote.emojis"/>
</div> </div>
</div> </div>
<MkButton v-if="!allowAnim && animated" :class="$style.playMFMButton" :small="true" @click="animatedMFM()" @click.stop><i class="ph-play ph-bold ph-lg "></i> {{ i18n.ts._animatedMFM.play }}</MkButton> <MkButton v-if="!allowAnim && animated" :class="$style.playMFMButton" :small="true" @click="animatedMFM()" @click.stop><i class="ph-play ph-bold ph-lg "></i> {{ i18n.ts._animatedMFM.play }}</MkButton>
@ -340,7 +341,7 @@ let renoting = false;
const keymap = { const keymap = {
'r': () => reply(true), 'r': () => reply(true),
'e|a|plus': () => react(true), 'e|a|plus': () => react(true),
'(q)': () => { if (canRenote.value && !renoted.value && !renoting) { renoting = true; renote(appearNote.value.visibility); } }, '(q)': () => { if (canRenote.value && !renoted.value && !renoting) renote(defaultStore.state.visibilityOnBoost); },
'up|k|shift+tab': focusBefore, 'up|k|shift+tab': focusBefore,
'down|j|tab': focusAfter, 'down|j|tab': focusAfter,
'esc': blur, 'esc': blur,
@ -440,6 +441,8 @@ if (!props.mock) {
} }
function boostVisibility() { function boostVisibility() {
if (renoting) return;
if (!defaultStore.state.showVisibilitySelectorOnBoost) { if (!defaultStore.state.showVisibilitySelectorOnBoost) {
renote(defaultStore.state.visibilityOnBoost); renote(defaultStore.state.visibilityOnBoost);
} else { } else {
@ -451,6 +454,8 @@ function renote(visibility: Visibility, localOnly: boolean = false) {
pleaseLogin(); pleaseLogin();
showMovedDialog(); showMovedDialog();
renoting = true;
if (appearNote.value.channel) { if (appearNote.value.channel) {
const el = renoteButton.value as HTMLElement | null | undefined; const el = renoteButton.value as HTMLElement | null | undefined;
if (el) { if (el) {

View File

@ -77,7 +77,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</header> </header>
<div :class="$style.noteContent"> <div :class="$style.noteContent">
<p v-if="appearNote.cw != null" :class="$style.cw"> <p v-if="appearNote.cw != null" :class="$style.cw">
<Mfm v-if="appearNote.cw != ''" style="margin-right: 8px;" :text="appearNote.cw" :author="appearNote.user" :nyaize="'respect'"/> <Mfm v-if="appearNote.cw != ''" style="margin-right: 8px;" :text="appearNote.cw" :isBlock="true" :author="appearNote.user" :nyaize="'respect'"/>
<MkCwButton v-model="showContent" :text="appearNote.text" :renote="appearNote.renote" :files="appearNote.files" :poll="appearNote.poll"/> <MkCwButton v-model="showContent" :text="appearNote.text" :renote="appearNote.renote" :files="appearNote.files" :poll="appearNote.poll"/>
</p> </p>
<div v-show="appearNote.cw == null || showContent"> <div v-show="appearNote.cw == null || showContent">
@ -92,13 +92,14 @@ SPDX-License-Identifier: AGPL-3.0-only
:enableEmojiMenu="true" :enableEmojiMenu="true"
:enableEmojiMenuReaction="true" :enableEmojiMenuReaction="true"
:isAnim="allowAnim" :isAnim="allowAnim"
:isBlock="true"
/> />
<a v-if="appearNote.renote != null" :class="$style.rn">RN:</a> <a v-if="appearNote.renote != null" :class="$style.rn">RN:</a>
<div v-if="translating || translation" :class="$style.translation"> <div v-if="translating || translation" :class="$style.translation">
<MkLoading v-if="translating" mini/> <MkLoading v-if="translating" mini/>
<div v-else-if="translation"> <div v-else-if="translation">
<b>{{ i18n.tsx.translatedFrom({ x: translation.sourceLang }) }}: </b> <b>{{ i18n.tsx.translatedFrom({ x: translation.sourceLang }) }}: </b>
<Mfm :text="translation.text" :author="appearNote.user" :nyaize="'respect'" :emojiUrls="appearNote.emojis"/> <Mfm :text="translation.text" :isBlock="true" :author="appearNote.user" :nyaize="'respect'" :emojiUrls="appearNote.emojis"/>
</div> </div>
</div> </div>
<MkButton v-if="!allowAnim && animated" :class="$style.playMFMButton" :small="true" @click="animatedMFM()" @click.stop><i class="ph-play ph-bold ph-lg "></i> {{ i18n.ts._animatedMFM.play }}</MkButton> <MkButton v-if="!allowAnim && animated" :class="$style.playMFMButton" :small="true" @click="animatedMFM()" @click.stop><i class="ph-play ph-bold ph-lg "></i> {{ i18n.ts._animatedMFM.play }}</MkButton>
@ -360,7 +361,7 @@ let renoting = false;
const keymap = { const keymap = {
'r': () => reply(true), 'r': () => reply(true),
'e|a|plus': () => react(true), 'e|a|plus': () => react(true),
'(q)': () => { if (canRenote.value && !renoted.value && !renoting) { renoting = true; renote(appearNote.value.visibility); } }, '(q)': () => { if (canRenote.value && !renoted.value && !renoting) renote(defaultStore.state.visibilityOnBoost); },
'esc': blur, 'esc': blur,
'm|o': () => showMenu(true), 'm|o': () => showMenu(true),
's': () => showContent.value !== showContent.value, 's': () => showContent.value !== showContent.value,
@ -452,6 +453,8 @@ useTooltip(quoteButton, async (showing) => {
}); });
function boostVisibility() { function boostVisibility() {
if (renoting) return;
if (!defaultStore.state.showVisibilitySelectorOnBoost) { if (!defaultStore.state.showVisibilitySelectorOnBoost) {
renote(defaultStore.state.visibilityOnBoost); renote(defaultStore.state.visibilityOnBoost);
} else { } else {
@ -485,6 +488,8 @@ function renote(visibility: Visibility, localOnly: boolean = false) {
pleaseLogin(); pleaseLogin();
showMovedDialog(); showMovedDialog();
renoting = true;
if (appearNote.value.channel) { if (appearNote.value.channel) {
const el = renoteButton.value as HTMLElement | null | undefined; const el = renoteButton.value as HTMLElement | null | undefined;
if (el) { if (el) {

View File

@ -10,7 +10,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<MkNoteHeader :class="$style.header" :classic="true" :note="note" :mini="true"/> <MkNoteHeader :class="$style.header" :classic="true" :note="note" :mini="true"/>
<div> <div>
<p v-if="note.cw != null" :class="$style.cw"> <p v-if="note.cw != null" :class="$style.cw">
<Mfm v-if="note.cw != ''" style="margin-right: 8px;" :text="note.cw" :author="note.user" :nyaize="'respect'" :emojiUrls="note.emojis"/> <Mfm v-if="note.cw != ''" style="margin-right: 8px;" :text="note.cw" :isBlock="true" :author="note.user" :nyaize="'respect'" :emojiUrls="note.emojis"/>
<MkCwButton v-model="showContent" :text="note.text" :files="note.files" :poll="note.poll" @click.stop/> <MkCwButton v-model="showContent" :text="note.text" :files="note.files" :poll="note.poll" @click.stop/>
</p> </p>
<div v-show="note.cw == null || showContent"> <div v-show="note.cw == null || showContent">

View File

@ -20,7 +20,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<SkNoteHeader :class="$style.header" :note="note" :classic="true" :mini="true"/> <SkNoteHeader :class="$style.header" :note="note" :classic="true" :mini="true"/>
<div :class="$style.content"> <div :class="$style.content">
<p v-if="note.cw != null" :class="$style.cw"> <p v-if="note.cw != null" :class="$style.cw">
<Mfm v-if="note.cw != ''" style="margin-right: 8px;" :text="note.cw" :author="note.user" :nyaize="'respect'"/> <Mfm v-if="note.cw != ''" style="margin-right: 8px;" :text="note.cw" :isBlock="true" :author="note.user" :nyaize="'respect'"/>
<MkCwButton v-model="showContent" :text="note.text" :files="note.files" :poll="note.poll"/> <MkCwButton v-model="showContent" :text="note.text" :files="note.files" :poll="note.poll"/>
</p> </p>
<div v-show="note.cw == null || showContent"> <div v-show="note.cw == null || showContent">

View File

@ -29,19 +29,19 @@
</header> </header>
<div :class="$style.noteContent"> <div :class="$style.noteContent">
<p v-if="appearNote.cw != null" :class="$style.cw"> <p v-if="appearNote.cw != null" :class="$style.cw">
<Mfm v-if="appearNote.cw != ''" style="margin-right: 8px;" :text="appearNote.cw" :author="appearNote.user" :nyaize="'account'"/> <Mfm v-if="appearNote.cw != ''" style="margin-right: 8px;" :text="appearNote.cw" :isBlock="true" :author="appearNote.user" :nyaize="'account'"/>
<MkCwButton v-model="showContent" :text="appearNote.text" :files="appearNote.files" :poll="appearNote.poll"/> <MkCwButton v-model="showContent" :text="appearNote.text" :files="appearNote.files" :poll="appearNote.poll"/>
</p> </p>
<div v-show="appearNote.cw == null || showContent"> <div v-show="appearNote.cw == null || showContent">
<span v-if="appearNote.isHidden" style="opacity: 0.5">({{ i18n.ts.private }})</span> <span v-if="appearNote.isHidden" style="opacity: 0.5">({{ i18n.ts.private }})</span>
<MkA v-if="appearNote.replyId" :class="$style.noteReplyTarget" :to="`/notes/${appearNote.replyId}`"><i class="ph-arrow-bend-left-up ph-bold ph-lg"></i></MkA> <MkA v-if="appearNote.replyId" :class="$style.noteReplyTarget" :to="`/notes/${appearNote.replyId}`"><i class="ph-arrow-bend-left-up ph-bold ph-lg"></i></MkA>
<Mfm v-if="appearNote.text" :text="appearNote.text" :author="appearNote.user" :nyaize="'account'" :emojiUrls="appearNote.emojis"/> <Mfm v-if="appearNote.text" :text="appearNote.text" :isBlock="true" :author="appearNote.user" :nyaize="'account'" :emojiUrls="appearNote.emojis"/>
<a v-if="appearNote.renote != null" :class="$style.rn">RN:</a> <a v-if="appearNote.renote != null" :class="$style.rn">RN:</a>
<div v-if="translating || translation" :class="$style.translation"> <div v-if="translating || translation" :class="$style.translation">
<MkLoading v-if="translating" mini/> <MkLoading v-if="translating" mini/>
<div v-else> <div v-else>
<b>{{ i18n.t('translatedFrom', { x: translation.sourceLang }) }}: </b> <b>{{ i18n.t('translatedFrom', { x: translation.sourceLang }) }}: </b>
<Mfm :text="translation.text" :author="appearNote.user" :nyaize="'account'" :emojiUrls="appearNote.emojis"/> <Mfm :text="translation.text" :isBlock="true" :author="appearNote.user" :nyaize="'account'" :emojiUrls="appearNote.emojis"/>
</div> </div>
</div> </div>
<div v-if="appearNote.files.length > 0"> <div v-if="appearNote.files.length > 0">

View File

@ -46,6 +46,7 @@ type MfmProps = {
enableEmojiMenuReaction?: boolean; enableEmojiMenuReaction?: boolean;
isAnim?: boolean; isAnim?: boolean;
linkNavigationBehavior?: MkABehavior; linkNavigationBehavior?: MkABehavior;
isBlock?: boolean;
}; };
type MfmEvents = { type MfmEvents = {
@ -77,6 +78,8 @@ export default function (props: MfmProps, { emit }: { emit: SetupContext<MfmEven
return c.match(/^[0-9a-f]{3,6}$/i) ? c : null; return c.match(/^[0-9a-f]{3,6}$/i) ? c : null;
}; };
const isBlock = props.isBlock ?? false;
const MkFormula = defineAsyncComponent(() => import('@/components/MkFormula.vue')); const MkFormula = defineAsyncComponent(() => import('@/components/MkFormula.vue'));
/** /**
@ -393,9 +396,9 @@ export default function (props: MfmProps, { emit }: { emit: SetupContext<MfmEven
} }
case 'center': { case 'center': {
return [h('bdi', h('div', { return [h('div', {
style: 'text-align:center;', style: 'text-align:center;',
}, genEl(token.children, scale)))]; }, h('bdi', genEl(token.children, scale)))];
} }
case 'url': { case 'url': {
@ -431,7 +434,7 @@ export default function (props: MfmProps, { emit }: { emit: SetupContext<MfmEven
} }
case 'blockCode': { case 'blockCode': {
return [h('bdi', h(MkCode, { return [h('bdi', { class: 'block' }, h(MkCode, {
key: Math.random(), key: Math.random(),
code: token.props.code, code: token.props.code,
lang: token.props.lang ?? undefined, lang: token.props.lang ?? undefined,
@ -447,13 +450,13 @@ export default function (props: MfmProps, { emit }: { emit: SetupContext<MfmEven
case 'quote': { case 'quote': {
if (!props.nowrap) { if (!props.nowrap) {
return [h('bdi', h('div', { return [h('bdi', { class: 'block' }, h('div', {
style: QUOTE_STYLE, style: QUOTE_STYLE,
}, genEl(token.children, scale, true)))]; }, h('bdi',genEl(token.children, scale, true))))];
} else { } else {
return [h('bdi', h('span', { return [h('span', {
style: QUOTE_STYLE, style: QUOTE_STYLE,
}, genEl(token.children, scale, true)))]; }, h('bdi',genEl(token.children, scale, true)))];
} }
} }
@ -504,7 +507,7 @@ export default function (props: MfmProps, { emit }: { emit: SetupContext<MfmEven
} }
case 'mathBlock': { case 'mathBlock': {
return [h('bdi', h(MkFormula, { return [h('bdi', { class: 'block' }, h(MkFormula, {
formula: token.props.formula, formula: token.props.formula,
block: true, block: true,
}))]; }))];
@ -518,7 +521,7 @@ export default function (props: MfmProps, { emit }: { emit: SetupContext<MfmEven
} }
case 'plain': { case 'plain': {
return [h('span', genEl(token.children, scale, true))]; return [h('bdi', h('span', genEl(token.children, scale, true)))];
} }
default: { default: {
@ -530,7 +533,7 @@ export default function (props: MfmProps, { emit }: { emit: SetupContext<MfmEven
} }
}).flat(Infinity) as (VNode | string)[]; }).flat(Infinity) as (VNode | string)[];
return h('bdi', h('span', { return h('bdi', { ...( isBlock ? { class: 'block' } : {}) }, h('span', {
// https://codeday.me/jp/qa/20190424/690106.html // https://codeday.me/jp/qa/20190424/690106.html
style: props.nowrap ? 'white-space: pre; word-wrap: normal; overflow: hidden; text-overflow: ellipsis;' : 'white-space: pre-wrap;', style: props.nowrap ? 'white-space: pre; word-wrap: normal; overflow: hidden; text-overflow: ellipsis;' : 'white-space: pre-wrap;',
}, genEl(rootAst, props.rootScale ?? 1))); }, genEl(rootAst, props.rootScale ?? 1)));

View File

@ -5,7 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<template> <template>
<div class="_gaps" :class="$style.textRoot"> <div class="_gaps" :class="$style.textRoot">
<Mfm :text="block.text ?? ''" :isNote="false"/> <Mfm :text="block.text ?? ''" :isBlock="true" :isNote="false"/>
<div v-if="isEnabledUrlPreview" class="_gaps_s"> <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"/>
</div> </div>

View File

@ -211,9 +211,10 @@ export function pageWindow(path: string) {
}, {}, 'closed'); }, {}, 'closed');
} }
export function toast(message: string) { export function toast(message: string, renderMfm = false) {
popup(MkToast, { popup(MkToast, {
message, message,
renderMfm,
}, {}, 'closed'); }, {}, 'closed');
} }

View File

@ -105,8 +105,29 @@ SPDX-License-Identifier: AGPL-3.0-only
<img src="https://secure.gravatar.com/avatar/ea0ea6451fdb74311efad369bdce018e?s=80&d=identicon" :class="$style.contributorAvatar"> <img src="https://secure.gravatar.com/avatar/ea0ea6451fdb74311efad369bdce018e?s=80&d=identicon" :class="$style.contributorAvatar">
<span :class="$style.contributorUsername">@fEmber</span> <span :class="$style.contributorUsername">@fEmber</span>
</a> </a>
<a href="https://activitypub.software/tess" target="_blank" :class="$style.contributor">
<img src="https://activitypub.software/uploads/-/system/user/avatar/132/avatar.png?width=128" :class="$style.contributorAvatar">
<span :class="$style.contributorUsername">@tess</span>
</a>
</div>
<template #description><MkLink url="https://activitypub.software/TransFem-org/Sharkey/-/graphs/develop">{{ i18n.ts._aboutMisskey.allContributors }}</MkLink></template>
</FormSection>
<FormSection>
<template #label>{{ i18n.ts._aboutMisskey.testers }}</template>
<div :class="$style.contributors" style="margin-bottom: 8px;">
<a href="https://antani.cyou/@lucent" target="_blank" :class="$style.contributor">
<img src="https://antani.cyou/proxy/avatar.webp?url=https%3A%2F%2Fantani.cyou%2Ffiles%2Fa2944119-024c-4abd-86e5-64bf0d30b26f&avatar=1" :class="$style.contributorAvatar">
<span :class="$style.contributorUsername">@lucent</span>
</a>
<a href="https://karilaa.app/@karilaa" target="_blank" :class="$style.contributor">
<img src="https://karilaa.app/proxy/avatar.webp?url=https%3A%2F%2Fkarilaa.app%2Ffiles%2Fc366e6f9-96d8-4d3b-b996-30e0a7cb3c5a&avatar=1" :class="$style.contributorAvatar">
<span :class="$style.contributorUsername">@karilaa</span>
</a>
<a href="https://thetransagenda.gay/@phoenix_fairy" target="_blank" :class="$style.contributor">
<img src="https://thetransagenda.gay/proxy/avatar.webp?url=https%3A%2F%2Fs3.us-east-005.backblazeb2.com%2Ftranssharkey%2Fnull%2Fd93ac6dc-2020-4b5a-bce7-84b41e97a0ac.png&avatar=1" :class="$style.contributorAvatar">
<span :class="$style.contributorUsername">@phoenix_fairy</span>
</a>
</div> </div>
<template #caption><MkLink url="https://activitypub.software/TransFem-org/Sharkey/-/graphs/develop">{{ i18n.ts._aboutMisskey.allContributors }}</MkLink></template>
</FormSection> </FormSection>
<FormSection> <FormSection>
<template #label>Misskey Contributors</template> <template #label>Misskey Contributors</template>

View File

@ -24,7 +24,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<MkA :to="`/announcements/${announcement.id}`"><span>{{ announcement.title }}</span></MkA> <MkA :to="`/announcements/${announcement.id}`"><span>{{ announcement.title }}</span></MkA>
</div> </div>
<div :class="$style.content"> <div :class="$style.content">
<Mfm :text="announcement.text"/> <Mfm :text="announcement.text" :isBlock="true" />
<img v-if="announcement.imageUrl" :src="announcement.imageUrl"/> <img v-if="announcement.imageUrl" :src="announcement.imageUrl"/>
<MkA :to="`/announcements/${announcement.id}`"> <MkA :to="`/announcements/${announcement.id}`">
<div style="margin-top: 8px; opacity: 0.7; font-size: 85%;"> <div style="margin-top: 8px; opacity: 0.7; font-size: 85%;">

View File

@ -22,7 +22,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<div :class="$style.bannerFade"></div> <div :class="$style.bannerFade"></div>
</div> </div>
<div v-if="channel.description" :class="$style.description"> <div v-if="channel.description" :class="$style.description">
<Mfm :text="channel.description" :isNote="false"/> <Mfm :text="channel.description" :isBlock="true" :isNote="false"/>
</div> </div>
</div> </div>

View File

@ -11,7 +11,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<div class="_panel"> <div class="_panel">
<div class="_gaps_s" :class="$style.description"> <div class="_gaps_s" :class="$style.description">
<div v-if="clip.description"> <div v-if="clip.description">
<Mfm :text="clip.description" :isNote="false"/> <Mfm :text="clip.description" :isBlock="true" :isNote="false"/>
</div> </div>
<div v-else>({{ i18n.ts.noDescription }})</div> <div v-else>({{ i18n.ts.noDescription }})</div>
<div> <div>

View File

@ -29,7 +29,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<div v-else :class="$style.ready"> <div v-else :class="$style.ready">
<div class="_panel main"> <div class="_panel main">
<div class="title">{{ flash.title }}</div> <div class="title">{{ flash.title }}</div>
<div class="summary"><Mfm :text="flash.summary"/></div> <div class="summary"><Mfm :text="flash.summary" :isBlock="true"/></div>
<MkButton class="start" gradate rounded large @click="start">Play</MkButton> <MkButton class="start" gradate rounded large @click="start">Play</MkButton>
<div class="info"> <div class="info">
<span v-tooltip="i18n.ts.numberOfLikes"><i class="ph-heart ph-bold ph-lg"></i> {{ flash.likedCount }}</span> <span v-tooltip="i18n.ts.numberOfLikes"><i class="ph-heart ph-bold ph-lg"></i> {{ flash.likedCount }}</span>

View File

@ -17,7 +17,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</div> </div>
<div class="body"> <div class="body">
<div class="title">{{ post.title }}</div> <div class="title">{{ post.title }}</div>
<div class="description"><Mfm :text="post.description"/></div> <div class="description"><Mfm :text="post.description" :isBlock="true"/></div>
<div class="info"> <div class="info">
<i class="ph-clock ph-bold ph-lg"></i> <MkTime :time="post.createdAt" mode="detail"/> <i class="ph-clock ph-bold ph-lg"></i> <MkTime :time="post.createdAt" mode="detail"/>
</div> </div>

View File

@ -67,6 +67,28 @@ SPDX-License-Identifier: AGPL-3.0-only
<MkSwitch v-model="showGapBetweenNotesInTimeline">{{ i18n.ts.showGapBetweenNotesInTimeline }}</MkSwitch> <MkSwitch v-model="showGapBetweenNotesInTimeline">{{ i18n.ts.showGapBetweenNotesInTimeline }}</MkSwitch>
<MkSwitch v-model="loadRawImages">{{ i18n.ts.loadRawImages }}</MkSwitch> <MkSwitch v-model="loadRawImages">{{ i18n.ts.loadRawImages }}</MkSwitch>
<MkSwitch v-model="showTickerOnReplies">Show instance ticker on replies</MkSwitch> <MkSwitch v-model="showTickerOnReplies">Show instance ticker on replies</MkSwitch>
<MkSelect v-model="searchEngine" placeholder="Other">
<template #label>{{ i18n.ts.searchEngine }}</template>
<option
v-for="[key, value] in Object.entries(searchEngineMap)" :key="key" :value="key"
>
{{ value }}
</option>
<!-- If the user is on Other and enters a domain add this one so that the dropdown doesnt go blank -->
<option v-if="useCustomSearchEngine" :value="searchEngine">
{{ i18n.ts.searchEngineOther }}
</option>
<!-- If one of the other options is selected show this as a blank other -->
<option v-if="!useCustomSearchEngine" value="">{{ i18n.ts.searchEngineOther }}</option>
</MkSelect>
<div v-if="useCustomSearchEngine">
<MkInput v-model="searchEngine" :max="300">
<template #label>{{ i18n.ts.searchEngineCusomURI }}</template>
<template #caption>{{ i18n.ts.searchEngineCustomURIDescription }}</template>
</MkInput>
</div>
<MkRadios v-model="reactionsDisplaySize"> <MkRadios v-model="reactionsDisplaySize">
<template #label>{{ i18n.ts.reactionsDisplaySize }}</template> <template #label>{{ i18n.ts.reactionsDisplaySize }}</template>
<option value="small">{{ i18n.ts.small }}</option> <option value="small">{{ i18n.ts.small }}</option>
@ -279,11 +301,12 @@ SPDX-License-Identifier: AGPL-3.0-only
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { computed, ref, watch } from 'vue'; import { computed, reactive, ref, watch } from 'vue';
import * as Misskey from 'misskey-js'; import * as Misskey from 'misskey-js';
import MkSwitch from '@/components/MkSwitch.vue'; import MkSwitch from '@/components/MkSwitch.vue';
import MkSelect from '@/components/MkSelect.vue'; import MkSelect from '@/components/MkSelect.vue';
import MkRadios from '@/components/MkRadios.vue'; import MkRadios from '@/components/MkRadios.vue';
import MkInput from '@/components/MkInput.vue';
import MkRange from '@/components/MkRange.vue'; import MkRange from '@/components/MkRange.vue';
import MkFolder from '@/components/MkFolder.vue'; import MkFolder from '@/components/MkFolder.vue';
import MkButton from '@/components/MkButton.vue'; import MkButton from '@/components/MkButton.vue';
@ -292,6 +315,7 @@ import FormLink from '@/components/form/link.vue';
import MkLink from '@/components/MkLink.vue'; import MkLink from '@/components/MkLink.vue';
import MkInfo from '@/components/MkInfo.vue'; import MkInfo from '@/components/MkInfo.vue';
import { langs } from '@/config.js'; import { langs } from '@/config.js';
import { searchEngineMap } from '@/scripts/search-engine-map.js';
import { defaultStore } from '@/store.js'; import { defaultStore } from '@/store.js';
import * as os from '@/os.js'; import * as os from '@/os.js';
import { misskeyApi } from '@/scripts/misskey-api.js'; import { misskeyApi } from '@/scripts/misskey-api.js';
@ -373,6 +397,9 @@ const keepScreenOn = computed(defaultStore.makeGetterSetter('keepScreenOn'));
const disableStreamingTimeline = computed(defaultStore.makeGetterSetter('disableStreamingTimeline')); const disableStreamingTimeline = computed(defaultStore.makeGetterSetter('disableStreamingTimeline'));
const useGroupedNotifications = computed(defaultStore.makeGetterSetter('useGroupedNotifications')); const useGroupedNotifications = computed(defaultStore.makeGetterSetter('useGroupedNotifications'));
const showTickerOnReplies = computed(defaultStore.makeGetterSetter('showTickerOnReplies')); const showTickerOnReplies = computed(defaultStore.makeGetterSetter('showTickerOnReplies'));
//const searchEngine = computed(defaultStore.makeGetterSetter('searchEngine'));
const searchEngine = computed(defaultStore.makeGetterSetter('searchEngine'));
const noteDesign = computed(defaultStore.makeGetterSetter('noteDesign')); const noteDesign = computed(defaultStore.makeGetterSetter('noteDesign'));
const uncollapseCW = computed(defaultStore.makeGetterSetter('uncollapseCW')); const uncollapseCW = computed(defaultStore.makeGetterSetter('uncollapseCW'));
const expandLongNote = computed(defaultStore.makeGetterSetter('expandLongNote')); const expandLongNote = computed(defaultStore.makeGetterSetter('expandLongNote'));
@ -563,4 +590,6 @@ definePageMetadata(() => ({
title: i18n.ts.general, title: i18n.ts.general,
icon: 'ph-faders ph-bold ph-lg', icon: 'ph-faders ph-bold ph-lg',
})); }));
const useCustomSearchEngine = computed(() => !Object.keys(searchEngineMap).includes(searchEngine.value));
</script> </script>

View File

@ -74,7 +74,7 @@ SPDX-License-Identifier: AGPL-3.0-only
/> />
</div> </div>
<div class="description"> <div class="description">
<Mfm v-if="user.description" :text="user.description" :isNote="false" :author="user"/> <Mfm v-if="user.description" :text="user.description" :isBlock="true" :isNote="false" :author="user"/>
<p v-else class="empty">{{ i18n.ts.noAccountDescription }}</p> <p v-else class="empty">{{ i18n.ts.noAccountDescription }}</p>
</div> </div>
<div class="fields system"> <div class="fields system">

View File

@ -10,7 +10,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<div class="_panel" :class="$style.content"> <div class="_panel" :class="$style.content">
<div> <div>
<MkA v-if="note.replyId" class="reply" :to="`/notes/${note.replyId}`"><i class="ph-arrow-u-up-left ph-bold ph-lg"></i></MkA> <MkA v-if="note.replyId" class="reply" :to="`/notes/${note.replyId}`"><i class="ph-arrow-u-up-left ph-bold ph-lg"></i></MkA>
<Mfm v-if="note.text" :text="note.text" :author="note.user"/> <Mfm v-if="note.text" :text="note.text" :isBlock="true" :author="note.user"/>
<MkA v-if="note.renoteId" class="rp" :to="`/notes/${note.renoteId}`">RN: ...</MkA> <MkA v-if="note.renoteId" class="rp" :to="`/notes/${note.renoteId}`">RN: ...</MkA>
</div> </div>
<div v-if="note.files.length > 0" :class="$style.richcontent"> <div v-if="note.files.length > 0" :class="$style.richcontent">

View File

@ -0,0 +1,12 @@
//store the URL and if its none of these its a custom one
export const searchEngineMap = {
//The first one is the default search engine
'https://www.google.com/search?q={query}': 'Google',
'https://duckduckgo.com/?q={query}': 'Duckduckgo',
'https://www.bing.com/search?q={query}': 'Bing',
'https://search.yahoo.com/search?p={query}': 'Yahoo',
'https://www.ecosia.org/search?q={query}': 'Ecosia',
'https://www.qwant.com/?q={query}': 'Qwant',
'https://search.aol.com/aol/search?q={query}': 'AOL',
'https://yandex.com/search?text={query}': 'Yandex',
};

View File

@ -6,6 +6,7 @@
import { markRaw, ref } from 'vue'; import { markRaw, ref } from 'vue';
import * as Misskey from 'misskey-js'; import * as Misskey from 'misskey-js';
import { miLocalStorage } from './local-storage.js'; import { miLocalStorage } from './local-storage.js';
import { searchEngineMap } from './scripts/search-engine-map.js';
import type { SoundType } from '@/scripts/sound.js'; import type { SoundType } from '@/scripts/sound.js';
import { Storage } from '@/pizzax.js'; import { Storage } from '@/pizzax.js';
import { hemisphere } from '@/scripts/intl-const.js'; import { hemisphere } from '@/scripts/intl-const.js';
@ -311,6 +312,10 @@ export const defaultStore = markRaw(new Storage('base', {
where: 'device', where: 'device',
default: false, default: false,
}, },
searchEngine: {
where: 'account',
default: Object.keys(searchEngineMap)[0],
},
noteDesign: { noteDesign: {
where: 'device', where: 'device',
default: 'sharkey' as 'sharkey' | 'misskey', default: 'sharkey' as 'sharkey' | 'misskey',

View File

@ -565,7 +565,7 @@ html[data-color-mode=dark] ._woodenFrame {
// MFM ----------------------------- // MFM -----------------------------
div > bdi, p > bdi { display: block } bdi.block { display: block }
._mfm_blur_ { ._mfm_blur_ {
filter: blur(6px); filter: blur(6px);