summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordakkar <dakkar@thenautilus.net>2024-06-13 09:06:24 +0100
committerdakkar <dakkar@thenautilus.net>2024-06-13 09:06:24 +0100
commitb2cbd507fe35ad0b31b3b30fdaf180fbfcb1460e (patch)
tree725bb756aa65b3e809a49d426d7e01e194777270
parentmerge: add all missing English translations (!546) (diff)
parentmerge: tweak the rate limit for `notes/create` and other improvements (!548) (diff)
downloadsharkey-b2cbd507fe35ad0b31b3b30fdaf180fbfcb1460e.tar.gz
sharkey-b2cbd507fe35ad0b31b3b30fdaf180fbfcb1460e.tar.bz2
sharkey-b2cbd507fe35ad0b31b3b30fdaf180fbfcb1460e.zip
Merge branch 'develop' into future-2024-05-31
-rw-r--r--locales/en-US.yml5
-rw-r--r--locales/generateDTS.js5
-rw-r--r--locales/index.d.ts20
-rw-r--r--locales/index.js6
-rw-r--r--locales/ja-JP.yml5
-rw-r--r--packages/backend/src/core/MfmService.ts15
-rw-r--r--packages/backend/src/server/api/endpoints/notes/create.ts5
-rw-r--r--packages/frontend/src/boot/main-boot.ts4
-rw-r--r--packages/frontend/src/components/MkAbuseReport.vue2
-rw-r--r--packages/frontend/src/components/MkAnnouncementDialog.vue2
-rw-r--r--packages/frontend/src/components/MkDialog.vue2
-rw-r--r--packages/frontend/src/components/MkGoogle.vue8
-rw-r--r--packages/frontend/src/components/MkNote.vue15
-rw-r--r--packages/frontend/src/components/MkNoteDetailed.vue11
-rw-r--r--packages/frontend/src/components/MkNotePreview.vue4
-rw-r--r--packages/frontend/src/components/MkNoteSimple.vue2
-rw-r--r--packages/frontend/src/components/MkNoteSub.vue2
-rw-r--r--packages/frontend/src/components/MkNotification.vue16
-rw-r--r--packages/frontend/src/components/MkSubNoteContent.vue4
-rw-r--r--packages/frontend/src/components/MkTextarea.vue2
-rw-r--r--packages/frontend/src/components/MkToast.vue10
-rw-r--r--packages/frontend/src/components/MkUserInfo.vue2
-rw-r--r--packages/frontend/src/components/MkUserPopup.vue2
-rw-r--r--packages/frontend/src/components/MkUserSetupDialog.User.vue2
-rw-r--r--packages/frontend/src/components/SkNote.vue13
-rw-r--r--packages/frontend/src/components/SkNoteDetailed.vue11
-rw-r--r--packages/frontend/src/components/SkNoteSimple.vue2
-rw-r--r--packages/frontend/src/components/SkNoteSub.vue2
-rw-r--r--packages/frontend/src/components/SkOldNoteWindow.vue6
-rw-r--r--packages/frontend/src/components/global/MkMisskeyFlavoredMarkdown.ts23
-rw-r--r--packages/frontend/src/components/page/page.text.vue2
-rw-r--r--packages/frontend/src/os.ts3
-rw-r--r--packages/frontend/src/pages/about-sharkey.vue23
-rw-r--r--packages/frontend/src/pages/announcements.vue2
-rw-r--r--packages/frontend/src/pages/channel.vue2
-rw-r--r--packages/frontend/src/pages/clip.vue2
-rw-r--r--packages/frontend/src/pages/flash/flash.vue2
-rw-r--r--packages/frontend/src/pages/gallery/post.vue2
-rw-r--r--packages/frontend/src/pages/settings/general.vue31
-rw-r--r--packages/frontend/src/pages/user/home.vue2
-rw-r--r--packages/frontend/src/pages/welcome.timeline.vue2
-rw-r--r--packages/frontend/src/scripts/search-engine-map.ts12
-rw-r--r--packages/frontend/src/store.ts5
-rw-r--r--packages/frontend/src/style.scss4
44 files changed, 223 insertions, 79 deletions
diff --git a/locales/en-US.yml b/locales/en-US.yml
index 6b637621b0..133df1abbd 100644
--- a/locales/en-US.yml
+++ b/locales/en-US.yml
@@ -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."
alwaysMarkSensitive: "Mark as sensitive by default"
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"
highlightSensitiveMedia: "Highlight sensitive media"
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! 🥰"
patrons: "Patrons"
projectMembers: "Project members"
+ testers: "Testers"
_displayOfSensitiveMedia:
respect: "Hide media marked as sensitive"
ignore: "Display media marked as sensitive"
diff --git a/locales/generateDTS.js b/locales/generateDTS.js
index 49807144ec..a175247445 100644
--- a/locales/generateDTS.js
+++ b/locales/generateDTS.js
@@ -6,7 +6,10 @@ import ts from 'typescript';
const __filename = fileURLToPath(import.meta.url);
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) {
if (typeof item !== 'string') {
diff --git a/locales/index.d.ts b/locales/index.d.ts
index d300ed42a3..28c9fce408 100644
--- a/locales/index.d.ts
+++ b/locales/index.d.ts
@@ -3053,6 +3053,22 @@ export interface Locale extends ILocale {
*/
"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;
+ /**
* アニメーション画åƒã‚’å†ç”Ÿã—ãªã„
*/
"disableShowingAnimatedImages": string;
@@ -7304,6 +7320,10 @@ export interface Locale extends ILocale {
* プロジェクトメンãƒãƒ¼
*/
"projectMembers": string;
+ /**
+ * テスター
+ */
+ "testers": string;
};
"_displayOfSensitiveMedia": {
/**
diff --git a/locales/index.js b/locales/index.js
index 650e552337..c7a693fb77 100644
--- a/locales/index.js
+++ b/locales/index.js
@@ -49,7 +49,11 @@ const primaries = {
};
// ä½•æ•…ã‹æ–‡å­—列ã«ãƒãƒƒã‚¯ã‚¹ãƒšãƒ¼ã‚¹æ–‡å­—ãŒæ··å…¥ã™ã‚‹ã“ã¨ãŒã‚りã€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() {
const locales = languages.reduce((a, c) => (a[c] = yaml.load(clean(fs.readFileSync(new URL(`${c}.yml`, import.meta.url), 'utf-8'))) || {}, a), {});
diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml
index 4d214b652a..1d4b9f4db4 100644
--- a/locales/ja-JP.yml
+++ b/locales/ja-JP.yml
@@ -759,6 +759,10 @@ noCrawleDescription: "å¤–éƒ¨ã®æ¤œç´¢ã‚¨ãƒ³ã‚¸ãƒ³ã«ã‚ãªãŸã®ãƒ¦ãƒ¼ã‚¶ãƒ¼ãƒšã
lockedAccountInfo: "フォローを承èªåˆ¶ã«ã—ã¦ã‚‚ã€ãƒŽãƒ¼ãƒˆã®å…¬é–‹ç¯„囲を「フォロワーã€ã«ã—ãªã„é™ã‚Šã€èª°ã§ã‚‚ã‚ãªãŸã®ãƒŽãƒ¼ãƒˆã‚’見るã“ã¨ãŒã§ãã¾ã™ã€‚"
alwaysMarkSensitive: "デフォルトã§ãƒ¡ãƒ‡ã‚£ã‚¢ã‚’センシティブ設定ã«ã™ã‚‹"
loadRawImages: "添付画åƒã®ã‚µãƒ ãƒã‚¤ãƒ«ã‚’オリジナル画質ã«ã™ã‚‹"
+searchEngine: "検索MFMã®æ¤œç´¢ã‚¨ãƒ³ã‚¸ãƒ³"
+searchEngineOther: "ä»–"
+searchEngineCustomURIDescription: "カスタム URI ã¯ã€\"https://www.google.com/search?q=\\{query}\" ã‚„ \"https://www.google.com/search?q=%s\" ã®ã‚ˆã†ãªå½¢å¼ã§å…¥åŠ›ã™ã‚‹å¿…è¦ãŒã‚りã¾ã™ã€‚"
+searchEngineCusomURI: "カスタム URI"
disableShowingAnimatedImages: "アニメーション画åƒã‚’å†ç”Ÿã—ãªã„"
highlightSensitiveMedia: "メディアãŒã‚»ãƒ³ã‚·ãƒ†ã‚£ãƒ–ã§ã‚ã‚‹ã“ã¨ã‚’分ã‹ã‚Šã‚„ã™ã表示"
verificationEmailSent: "確èªã®ãƒ¡ãƒ¼ãƒ«ã‚’é€ä¿¡ã—ã¾ã—ãŸã€‚メールã«è¨˜è¼‰ã•れãŸãƒªãƒ³ã‚¯ã«ã‚¢ã‚¯ã‚»ã‚¹ã—ã¦ã€è¨­å®šã‚’完了ã—ã¦ãã ã•ã„。"
@@ -1903,6 +1907,7 @@ _aboutMisskey:
morePatrons: "ä»–ã«ã‚‚多ãã®æ–¹ãŒæ”¯æ´ã—ã¦ãれã¦ã„ã¾ã™ã€‚ã‚りãŒã¨ã†ã”ã–ã„ã¾ã™ðŸ¥°"
patrons: "支æ´è€…"
projectMembers: "プロジェクトメンãƒãƒ¼"
+ testers: "テスター"
_displayOfSensitiveMedia:
respect: "センシティブ設定ã•れãŸãƒ¡ãƒ‡ã‚£ã‚¢ã‚’éš ã™"
diff --git a/packages/backend/src/core/MfmService.ts b/packages/backend/src/core/MfmService.ts
index 5de6e07d33..625df1feaa 100644
--- a/packages/backend/src/core/MfmService.ts
+++ b/packages/backend/src/core/MfmService.ts
@@ -132,9 +132,18 @@ export class MfmService {
case 'h1':
{
- text += 'ã€';
+ text += '**ã€';
appendChildren(node.childNodes);
- text += '】\n';
+ text += '】**\n';
+ break;
+ }
+
+ case 'h2':
+ case 'h3':
+ {
+ text += '**';
+ appendChildren(node.childNodes);
+ text += '**\n';
break;
}
@@ -203,8 +212,6 @@ export class MfmService {
}
case 'p':
- case 'h2':
- case 'h3':
case 'h4':
case 'h5':
case 'h6':
diff --git a/packages/backend/src/server/api/endpoints/notes/create.ts b/packages/backend/src/server/api/endpoints/notes/create.ts
index 5d2895cd46..626f03b758 100644
--- a/packages/backend/src/server/api/endpoints/notes/create.ts
+++ b/packages/backend/src/server/api/endpoints/notes/create.ts
@@ -30,8 +30,9 @@ export const meta = {
prohibitMoved: true,
limit: {
- duration: ms('1minute'),
- max: 5,
+ duration: ms('1hour'),
+ max: 300,
+ minInterval: ms('1sec'),
},
kind: 'write:notes',
diff --git a/packages/frontend/src/boot/main-boot.ts b/packages/frontend/src/boot/main-boot.ts
index 18dfdcdc51..013fa7c37c 100644
--- a/packages/frontend/src/boot/main-boot.ts
+++ b/packages/frontend/src/boot/main-boot.ts
@@ -94,7 +94,7 @@ export async function mainBoot() {
}).render();
}
}
- }
+ }
} catch (error) {
// console.error(error);
console.error('Failed to initialise the seasonal screen effect canvas context:', error);
@@ -236,7 +236,7 @@ export async function mainBoot() {
if (Date.now() - lastUsedDate > 1000 * 60 * 60 * 2) {
toast(i18n.tsx.welcomeBackWithName({
name: $i.name || $i.username,
- }));
+ }), true);
}
}
miLocalStorage.setItem('lastUsed', Date.now().toString());
diff --git a/packages/frontend/src/components/MkAbuseReport.vue b/packages/frontend/src/components/MkAbuseReport.vue
index 48219d0903..2f44616908 100644
--- a/packages/frontend/src/components/MkAbuseReport.vue
+++ b/packages/frontend/src/components/MkAbuseReport.vue
@@ -20,7 +20,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</div>
<div class="detail">
<div>
- <Mfm :text="report.comment" :linkNavigationBehavior="'window'"/>
+ <Mfm :text="report.comment" :isBlock="true" :linkNavigationBehavior="'window'"/>
</div>
<hr/>
<div>{{ i18n.ts.reporter }}: <MkA :to="`/admin/user/${report.reporter.id}`" class="_link" :behavior="'window'">@{{ report.reporter.username }}</MkA></div>
diff --git a/packages/frontend/src/components/MkAnnouncementDialog.vue b/packages/frontend/src/components/MkAnnouncementDialog.vue
index 74d0e7214f..032a815ee6 100644
--- a/packages/frontend/src/components/MkAnnouncementDialog.vue
+++ b/packages/frontend/src/components/MkAnnouncementDialog.vue
@@ -15,7 +15,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</span>
<span :class="$style.title">{{ announcement.title }}</span>
</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>
</div>
</MkModal>
diff --git a/packages/frontend/src/components/MkDialog.vue b/packages/frontend/src/components/MkDialog.vue
index 0c9c14ee59..b534ae4c56 100644
--- a/packages/frontend/src/components/MkDialog.vue
+++ b/packages/frontend/src/components/MkDialog.vue
@@ -26,7 +26,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<MkLoading v-else-if="type === 'waiting'" :class="$style.iconInner" :em="true"/>
</div>
<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">
<template v-if="input.type === 'password'" #prefix><i class="ph-lock ph-bold ph-lg"></i></template>
<template #caption>
diff --git a/packages/frontend/src/components/MkGoogle.vue b/packages/frontend/src/components/MkGoogle.vue
index c92a49d32a..d1809d1073 100644
--- a/packages/frontend/src/components/MkGoogle.vue
+++ b/packages/frontend/src/components/MkGoogle.vue
@@ -13,6 +13,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<script lang="ts" setup>
import { ref } from 'vue';
import { i18n } from '@/i18n.js';
+import { defaultStore } from '@/store';
const props = defineProps<{
q: string;
@@ -21,9 +22,10 @@ const props = defineProps<{
const query = ref(props.q);
const search = () => {
- const sp = new URLSearchParams();
- sp.append('q', query.value);
- window.open(`https://www.google.com/search?${sp.toString()}`, '_blank', 'noopener');
+ const searchQuery = encodeURIComponent(query.value);
+ const searchUrl = defaultStore.state.searchEngine.replace(/{query}|%s\b/g, searchQuery);
+
+ window.open(searchUrl, '_blank', 'noopener');
};
</script>
diff --git a/packages/frontend/src/components/MkNote.vue b/packages/frontend/src/components/MkNote.vue
index 86a44f3188..ba97050154 100644
--- a/packages/frontend/src/components/MkNote.vue
+++ b/packages/frontend/src/components/MkNote.vue
@@ -44,7 +44,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</div>
<div v-if="renoteCollapsed" :class="$style.collapsedRenoteTarget">
<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>
<article v-else :class="$style.article" @contextmenu.stop="onContextmenu">
<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/>
<MkInstanceTicker v-if="showTicker" :instance="appearNote.user.instance"/>
<div style="container-type: inline-size;">
+ <bdi>
<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/>
</p>
<div v-show="appearNote.cw == null || showContent" :class="[{ [$style.contentCollapsed]: collapsed }]">
@@ -71,12 +72,13 @@ SPDX-License-Identifier: AGPL-3.0-only
:enableEmojiMenu="true"
:enableEmojiMenuReaction="true"
:isAnim="allowAnim"
+ :isBlock="true"
/>
<div v-if="translating || translation" :class="$style.translation">
<MkLoading v-if="translating" mini/>
<div v-else-if="translation">
<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>
<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>
</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>
+ </bdi>
</div>
<MkReactionsViewer v-if="appearNote.reactionAcceptance !== 'likeOnly'" :note="appearNote" :maxNumber="16" @click.stop @mockUpdateMyReaction="emitUpdReaction">
<template #more>
@@ -339,7 +342,7 @@ let renoting = false;
const keymap = {
'r': () => reply(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,
'down|j|tab': focusAfter,
'esc': blur,
@@ -439,6 +442,8 @@ if (!props.mock) {
}
function boostVisibility() {
+ if (renoting) return;
+
if (!defaultStore.state.showVisibilitySelectorOnBoost) {
renote(defaultStore.state.visibilityOnBoost);
} else {
@@ -450,6 +455,8 @@ function renote(visibility: Visibility, localOnly: boolean = false) {
pleaseLogin();
showMovedDialog();
+ renoting = true;
+
if (appearNote.value.channel) {
const el = renoteButton.value as HTMLElement | null | undefined;
if (el) {
diff --git a/packages/frontend/src/components/MkNoteDetailed.vue b/packages/frontend/src/components/MkNoteDetailed.vue
index 991437a510..f0b1ca82a4 100644
--- a/packages/frontend/src/components/MkNoteDetailed.vue
+++ b/packages/frontend/src/components/MkNoteDetailed.vue
@@ -68,7 +68,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</header>
<div :class="$style.noteContent">
<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"/>
</p>
<div v-show="appearNote.cw == null || showContent">
@@ -84,13 +84,14 @@ SPDX-License-Identifier: AGPL-3.0-only
:enableEmojiMenu="true"
:enableEmojiMenuReaction="true"
:isAnim="allowAnim"
+ :isBlock="true"
/>
<a v-if="appearNote.renote != null" :class="$style.rn">RN:</a>
<div v-if="translating || translation" :class="$style.translation">
<MkLoading v-if="translating" mini/>
<div v-else-if="translation">
<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>
<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 = {
'r': () => reply(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,
'm|o': () => showMenu(true),
's': () => showContent.value !== showContent.value,
@@ -443,6 +444,8 @@ useTooltip(quoteButton, async (showing) => {
});
function boostVisibility() {
+ if (renoting) return;
+
if (!defaultStore.state.showVisibilitySelectorOnBoost) {
renote(defaultStore.state.visibilityOnBoost);
} else {
@@ -476,6 +479,8 @@ function renote(visibility: Visibility, localOnly: boolean = false) {
pleaseLogin();
showMovedDialog();
+ renoting = true;
+
if (appearNote.value.channel) {
const el = renoteButton.value as HTMLElement | null | undefined;
if (el) {
diff --git a/packages/frontend/src/components/MkNotePreview.vue b/packages/frontend/src/components/MkNotePreview.vue
index 3fcd7593ba..a8853a8a5f 100644
--- a/packages/frontend/src/components/MkNotePreview.vue
+++ b/packages/frontend/src/components/MkNotePreview.vue
@@ -12,11 +12,11 @@ SPDX-License-Identifier: AGPL-3.0-only
</div>
<div>
<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;"/>
</p>
<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>
diff --git a/packages/frontend/src/components/MkNoteSimple.vue b/packages/frontend/src/components/MkNoteSimple.vue
index 477cf4521a..542e3e79ea 100644
--- a/packages/frontend/src/components/MkNoteSimple.vue
+++ b/packages/frontend/src/components/MkNoteSimple.vue
@@ -10,7 +10,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<MkNoteHeader :class="$style.header" :note="note" :mini="true"/>
<div>
<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/>
</p>
<div v-show="note.cw == null || showContent">
diff --git a/packages/frontend/src/components/MkNoteSub.vue b/packages/frontend/src/components/MkNoteSub.vue
index 37811dd52e..66d1e51a6c 100644
--- a/packages/frontend/src/components/MkNoteSub.vue
+++ b/packages/frontend/src/components/MkNoteSub.vue
@@ -12,7 +12,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<MkNoteHeader :class="$style.header" :note="note" :mini="true"/>
<div :class="$style.content">
<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"/>
</p>
<div v-show="note.cw == null || showContent">
diff --git a/packages/frontend/src/components/MkNotification.vue b/packages/frontend/src/components/MkNotification.vue
index e5a58296cc..f849e94e93 100644
--- a/packages/frontend/src/components/MkNotification.vue
+++ b/packages/frontend/src/components/MkNotification.vue
@@ -71,29 +71,29 @@ SPDX-License-Identifier: AGPL-3.0-only
<div>
<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>
- <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>
</MkA>
<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>
- <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>
</MkA>
<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 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 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 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 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>
- <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>
</MkA>
<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)">
<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>
</MkA>
</div>
diff --git a/packages/frontend/src/components/MkSubNoteContent.vue b/packages/frontend/src/components/MkSubNoteContent.vue
index 7e63bbe82d..8386a783fc 100644
--- a/packages/frontend/src/components/MkSubNoteContent.vue
+++ b/packages/frontend/src/components/MkSubNoteContent.vue
@@ -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.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>
- <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-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">
<MkLoading v-if="translating" mini/>
<div v-else>
<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>
<MkA v-if="note.renoteId" :class="$style.rp" :to="`/notes/${note.renoteId}`" @click.stop>RN: ...</MkA>
diff --git a/packages/frontend/src/components/MkTextarea.vue b/packages/frontend/src/components/MkTextarea.vue
index 3082842699..7b9fb3d8ad 100644
--- a/packages/frontend/src/components/MkTextarea.vue
+++ b/packages/frontend/src/components/MkTextarea.vue
@@ -28,7 +28,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<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>
<div v-if="mfmPreview" v-show="preview" v-panel :class="$style.mfmPreview">
- <Mfm :text="v"/>
+ <Mfm :text="v" :isBlock="true" />
</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>
diff --git a/packages/frontend/src/components/MkToast.vue b/packages/frontend/src/components/MkToast.vue
index a117e49350..f731b3264f 100644
--- a/packages/frontend/src/components/MkToast.vue
+++ b/packages/frontend/src/components/MkToast.vue
@@ -14,7 +14,8 @@ SPDX-License-Identifier: AGPL-3.0-only
>
<div v-if="showing" class="_acrylic" :class="$style.root" :style="{ zIndex }">
<div style="padding: 16px 24px;">
- {{ message }}
+ <Mfm v-if="renderMfm" :text="message" plain/>
+ <template v-else>{{ message }}</template>
</div>
</div>
</Transition>
@@ -26,9 +27,12 @@ import { onMounted, ref } from 'vue';
import * as os from '@/os.js';
import { defaultStore } from '@/store.js';
-defineProps<{
+withDefaults(defineProps<{
message: string;
-}>();
+ renderMfm: boolean;
+}>(), {
+ renderMfm: false,
+});
const emit = defineEmits<{
(ev: 'closed'): void;
diff --git a/packages/frontend/src/components/MkUserInfo.vue b/packages/frontend/src/components/MkUserInfo.vue
index 63c4af41a0..5658188c41 100644
--- a/packages/frontend/src/components/MkUserInfo.vue
+++ b/packages/frontend/src/components/MkUserInfo.vue
@@ -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>
<div :class="$style.description">
<div v-if="user.description" :class="$style.mfm">
- <Mfm :text="user.description" :author="user"/>
+ <Mfm :text="user.description" :isBlock="true" :author="user"/>
</div>
<span v-else style="opacity: 0.7;">{{ i18n.ts.noAccountDescription }}</span>
</div>
diff --git a/packages/frontend/src/components/MkUserPopup.vue b/packages/frontend/src/components/MkUserPopup.vue
index 18e4bde59d..2aee918114 100644
--- a/packages/frontend/src/components/MkUserPopup.vue
+++ b/packages/frontend/src/components/MkUserPopup.vue
@@ -28,7 +28,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<div :class="$style.username"><MkAcct :user="user"/></div>
</div>
<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>
<div v-if="user.fields.length > 0" :class="$style.fields">
diff --git a/packages/frontend/src/components/MkUserSetupDialog.User.vue b/packages/frontend/src/components/MkUserSetupDialog.User.vue
index a4b9746f4b..efb1ed5593 100644
--- a/packages/frontend/src/components/MkUserSetupDialog.User.vue
+++ b/packages/frontend/src/components/MkUserSetupDialog.User.vue
@@ -13,7 +13,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</div>
<div :class="$style.description">
<div v-if="user.description" :class="$style.mfm">
- <Mfm :text="user.description" :author="user"/>
+ <Mfm :text="user.description" :isBlock="true" :author="user"/>
</div>
<span v-else style="opacity: 0.7;">{{ i18n.ts.noAccountDescription }}</span>
</div>
diff --git a/packages/frontend/src/components/SkNote.vue b/packages/frontend/src/components/SkNote.vue
index d09f4c79ea..7cfa3542c3 100644
--- a/packages/frontend/src/components/SkNote.vue
+++ b/packages/frontend/src/components/SkNote.vue
@@ -44,7 +44,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</div>
<div v-if="renoteCollapsed" :class="$style.collapsedRenoteTarget">
<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>
<article v-else :class="$style.article" @contextmenu.stop="onContextmenu">
<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 style="container-type: inline-size;">
<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/>
</p>
<div v-show="appearNote.cw == null || showContent" :class="[{ [$style.contentCollapsed]: collapsed }]">
@@ -73,12 +73,13 @@ SPDX-License-Identifier: AGPL-3.0-only
:enableEmojiMenu="true"
:enableEmojiMenuReaction="true"
:isAnim="allowAnim"
+ :isBlock="true"
/>
<div v-if="translating || translation" :class="$style.translation">
<MkLoading v-if="translating" mini/>
<div v-else-if="translation">
<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>
<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 = {
'r': () => reply(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,
'down|j|tab': focusAfter,
'esc': blur,
@@ -440,6 +441,8 @@ if (!props.mock) {
}
function boostVisibility() {
+ if (renoting) return;
+
if (!defaultStore.state.showVisibilitySelectorOnBoost) {
renote(defaultStore.state.visibilityOnBoost);
} else {
@@ -451,6 +454,8 @@ function renote(visibility: Visibility, localOnly: boolean = false) {
pleaseLogin();
showMovedDialog();
+ renoting = true;
+
if (appearNote.value.channel) {
const el = renoteButton.value as HTMLElement | null | undefined;
if (el) {
diff --git a/packages/frontend/src/components/SkNoteDetailed.vue b/packages/frontend/src/components/SkNoteDetailed.vue
index 56929396f3..8307d4c29d 100644
--- a/packages/frontend/src/components/SkNoteDetailed.vue
+++ b/packages/frontend/src/components/SkNoteDetailed.vue
@@ -77,7 +77,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</header>
<div :class="$style.noteContent">
<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"/>
</p>
<div v-show="appearNote.cw == null || showContent">
@@ -92,13 +92,14 @@ SPDX-License-Identifier: AGPL-3.0-only
:enableEmojiMenu="true"
:enableEmojiMenuReaction="true"
:isAnim="allowAnim"
+ :isBlock="true"
/>
<a v-if="appearNote.renote != null" :class="$style.rn">RN:</a>
<div v-if="translating || translation" :class="$style.translation">
<MkLoading v-if="translating" mini/>
<div v-else-if="translation">
<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>
<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 = {
'r': () => reply(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,
'm|o': () => showMenu(true),
's': () => showContent.value !== showContent.value,
@@ -452,6 +453,8 @@ useTooltip(quoteButton, async (showing) => {
});
function boostVisibility() {
+ if (renoting) return;
+
if (!defaultStore.state.showVisibilitySelectorOnBoost) {
renote(defaultStore.state.visibilityOnBoost);
} else {
@@ -485,6 +488,8 @@ function renote(visibility: Visibility, localOnly: boolean = false) {
pleaseLogin();
showMovedDialog();
+ renoting = true;
+
if (appearNote.value.channel) {
const el = renoteButton.value as HTMLElement | null | undefined;
if (el) {
diff --git a/packages/frontend/src/components/SkNoteSimple.vue b/packages/frontend/src/components/SkNoteSimple.vue
index 533aa60961..b31e337a99 100644
--- a/packages/frontend/src/components/SkNoteSimple.vue
+++ b/packages/frontend/src/components/SkNoteSimple.vue
@@ -10,7 +10,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<MkNoteHeader :class="$style.header" :classic="true" :note="note" :mini="true"/>
<div>
<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/>
</p>
<div v-show="note.cw == null || showContent">
diff --git a/packages/frontend/src/components/SkNoteSub.vue b/packages/frontend/src/components/SkNoteSub.vue
index 1cffd8dd66..bd17665c2e 100644
--- a/packages/frontend/src/components/SkNoteSub.vue
+++ b/packages/frontend/src/components/SkNoteSub.vue
@@ -20,7 +20,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<SkNoteHeader :class="$style.header" :note="note" :classic="true" :mini="true"/>
<div :class="$style.content">
<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"/>
</p>
<div v-show="note.cw == null || showContent">
diff --git a/packages/frontend/src/components/SkOldNoteWindow.vue b/packages/frontend/src/components/SkOldNoteWindow.vue
index bed44bbb08..d2daf3f944 100644
--- a/packages/frontend/src/components/SkOldNoteWindow.vue
+++ b/packages/frontend/src/components/SkOldNoteWindow.vue
@@ -29,19 +29,19 @@
</header>
<div :class="$style.noteContent">
<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"/>
</p>
<div v-show="appearNote.cw == null || showContent">
<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>
- <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>
<div v-if="translating || translation" :class="$style.translation">
<MkLoading v-if="translating" mini/>
<div v-else>
<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 v-if="appearNote.files.length > 0">
diff --git a/packages/frontend/src/components/global/MkMisskeyFlavoredMarkdown.ts b/packages/frontend/src/components/global/MkMisskeyFlavoredMarkdown.ts
index 5fdcaa339b..ac54b60571 100644
--- a/packages/frontend/src/components/global/MkMisskeyFlavoredMarkdown.ts
+++ b/packages/frontend/src/components/global/MkMisskeyFlavoredMarkdown.ts
@@ -46,6 +46,7 @@ type MfmProps = {
enableEmojiMenuReaction?: boolean;
isAnim?: boolean;
linkNavigationBehavior?: MkABehavior;
+ isBlock?: boolean;
};
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;
};
+ const isBlock = props.isBlock ?? false;
+
const MkFormula = defineAsyncComponent(() => import('@/components/MkFormula.vue'));
/**
@@ -393,9 +396,9 @@ export default function (props: MfmProps, { emit }: { emit: SetupContext<MfmEven
}
case 'center': {
- return [h('bdi', h('div', {
+ return [h('div', {
style: 'text-align:center;',
- }, genEl(token.children, scale)))];
+ }, h('bdi', genEl(token.children, scale)))];
}
case 'url': {
@@ -431,7 +434,7 @@ export default function (props: MfmProps, { emit }: { emit: SetupContext<MfmEven
}
case 'blockCode': {
- return [h('bdi', h(MkCode, {
+ return [h('bdi', { class: 'block' }, h(MkCode, {
key: Math.random(),
code: token.props.code,
lang: token.props.lang ?? undefined,
@@ -447,13 +450,13 @@ export default function (props: MfmProps, { emit }: { emit: SetupContext<MfmEven
case 'quote': {
if (!props.nowrap) {
- return [h('bdi', h('div', {
+ return [h('bdi', { class: 'block' }, h('div', {
style: QUOTE_STYLE,
- }, genEl(token.children, scale, true)))];
+ }, h('bdi',genEl(token.children, scale, true))))];
} else {
- return [h('bdi', h('span', {
+ return [h('span', {
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': {
- return [h('bdi', h(MkFormula, {
+ return [h('bdi', { class: 'block' }, h(MkFormula, {
formula: token.props.formula,
block: true,
}))];
@@ -518,7 +521,7 @@ export default function (props: MfmProps, { emit }: { emit: SetupContext<MfmEven
}
case 'plain': {
- return [h('span', genEl(token.children, scale, true))];
+ return [h('bdi', h('span', genEl(token.children, scale, true)))];
}
default: {
@@ -530,7 +533,7 @@ export default function (props: MfmProps, { emit }: { emit: SetupContext<MfmEven
}
}).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
style: props.nowrap ? 'white-space: pre; word-wrap: normal; overflow: hidden; text-overflow: ellipsis;' : 'white-space: pre-wrap;',
}, genEl(rootAst, props.rootScale ?? 1)));
diff --git a/packages/frontend/src/components/page/page.text.vue b/packages/frontend/src/components/page/page.text.vue
index 2f11c09db2..5f88acb11d 100644
--- a/packages/frontend/src/components/page/page.text.vue
+++ b/packages/frontend/src/components/page/page.text.vue
@@ -5,7 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<template>
<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">
<MkUrlPreview v-for="url in urls" :key="url" :url="url"/>
</div>
diff --git a/packages/frontend/src/os.ts b/packages/frontend/src/os.ts
index c728b014a2..6adf2e590b 100644
--- a/packages/frontend/src/os.ts
+++ b/packages/frontend/src/os.ts
@@ -211,9 +211,10 @@ export function pageWindow(path: string) {
}, {}, 'closed');
}
-export function toast(message: string) {
+export function toast(message: string, renderMfm = false) {
popup(MkToast, {
message,
+ renderMfm,
}, {}, 'closed');
}
diff --git a/packages/frontend/src/pages/about-sharkey.vue b/packages/frontend/src/pages/about-sharkey.vue
index f020e043c6..f5a8fcac42 100644
--- a/packages/frontend/src/pages/about-sharkey.vue
+++ b/packages/frontend/src/pages/about-sharkey.vue
@@ -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">
<span :class="$style.contributorUsername">@fEmber</span>
</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>
- <template #caption><MkLink url="https://activitypub.software/TransFem-org/Sharkey/-/graphs/develop">{{ i18n.ts._aboutMisskey.allContributors }}</MkLink></template>
</FormSection>
<FormSection>
<template #label>Misskey Contributors</template>
diff --git a/packages/frontend/src/pages/announcements.vue b/packages/frontend/src/pages/announcements.vue
index 07bbc46ffc..44dd2e90d8 100644
--- a/packages/frontend/src/pages/announcements.vue
+++ b/packages/frontend/src/pages/announcements.vue
@@ -24,7 +24,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<MkA :to="`/announcements/${announcement.id}`"><span>{{ announcement.title }}</span></MkA>
</div>
<div :class="$style.content">
- <Mfm :text="announcement.text"/>
+ <Mfm :text="announcement.text" :isBlock="true" />
<img v-if="announcement.imageUrl" :src="announcement.imageUrl"/>
<MkA :to="`/announcements/${announcement.id}`">
<div style="margin-top: 8px; opacity: 0.7; font-size: 85%;">
diff --git a/packages/frontend/src/pages/channel.vue b/packages/frontend/src/pages/channel.vue
index e49a16fecd..7f49c984a8 100644
--- a/packages/frontend/src/pages/channel.vue
+++ b/packages/frontend/src/pages/channel.vue
@@ -22,7 +22,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<div :class="$style.bannerFade"></div>
</div>
<div v-if="channel.description" :class="$style.description">
- <Mfm :text="channel.description" :isNote="false"/>
+ <Mfm :text="channel.description" :isBlock="true" :isNote="false"/>
</div>
</div>
diff --git a/packages/frontend/src/pages/clip.vue b/packages/frontend/src/pages/clip.vue
index f89ef036cf..9c42d2d3b8 100644
--- a/packages/frontend/src/pages/clip.vue
+++ b/packages/frontend/src/pages/clip.vue
@@ -11,7 +11,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<div class="_panel">
<div class="_gaps_s" :class="$style.description">
<div v-if="clip.description">
- <Mfm :text="clip.description" :isNote="false"/>
+ <Mfm :text="clip.description" :isBlock="true" :isNote="false"/>
</div>
<div v-else>({{ i18n.ts.noDescription }})</div>
<div>
diff --git a/packages/frontend/src/pages/flash/flash.vue b/packages/frontend/src/pages/flash/flash.vue
index 6e61b66a75..febfdbaaf7 100644
--- a/packages/frontend/src/pages/flash/flash.vue
+++ b/packages/frontend/src/pages/flash/flash.vue
@@ -29,7 +29,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<div v-else :class="$style.ready">
<div class="_panel main">
<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>
<div class="info">
<span v-tooltip="i18n.ts.numberOfLikes"><i class="ph-heart ph-bold ph-lg"></i> {{ flash.likedCount }}</span>
diff --git a/packages/frontend/src/pages/gallery/post.vue b/packages/frontend/src/pages/gallery/post.vue
index 1511928d55..99bd29f802 100644
--- a/packages/frontend/src/pages/gallery/post.vue
+++ b/packages/frontend/src/pages/gallery/post.vue
@@ -17,7 +17,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</div>
<div class="body">
<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">
<i class="ph-clock ph-bold ph-lg"></i> <MkTime :time="post.createdAt" mode="detail"/>
</div>
diff --git a/packages/frontend/src/pages/settings/general.vue b/packages/frontend/src/pages/settings/general.vue
index 0269985658..ab4f518d9f 100644
--- a/packages/frontend/src/pages/settings/general.vue
+++ b/packages/frontend/src/pages/settings/general.vue
@@ -67,6 +67,28 @@ SPDX-License-Identifier: AGPL-3.0-only
<MkSwitch v-model="showGapBetweenNotesInTimeline">{{ i18n.ts.showGapBetweenNotesInTimeline }}</MkSwitch>
<MkSwitch v-model="loadRawImages">{{ i18n.ts.loadRawImages }}</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">
<template #label>{{ i18n.ts.reactionsDisplaySize }}</template>
<option value="small">{{ i18n.ts.small }}</option>
@@ -279,11 +301,12 @@ SPDX-License-Identifier: AGPL-3.0-only
</template>
<script lang="ts" setup>
-import { computed, ref, watch } from 'vue';
+import { computed, reactive, ref, watch } from 'vue';
import * as Misskey from 'misskey-js';
import MkSwitch from '@/components/MkSwitch.vue';
import MkSelect from '@/components/MkSelect.vue';
import MkRadios from '@/components/MkRadios.vue';
+import MkInput from '@/components/MkInput.vue';
import MkRange from '@/components/MkRange.vue';
import MkFolder from '@/components/MkFolder.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 MkInfo from '@/components/MkInfo.vue';
import { langs } from '@/config.js';
+import { searchEngineMap } from '@/scripts/search-engine-map.js';
import { defaultStore } from '@/store.js';
import * as os from '@/os.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 useGroupedNotifications = computed(defaultStore.makeGetterSetter('useGroupedNotifications'));
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 uncollapseCW = computed(defaultStore.makeGetterSetter('uncollapseCW'));
const expandLongNote = computed(defaultStore.makeGetterSetter('expandLongNote'));
@@ -563,4 +590,6 @@ definePageMetadata(() => ({
title: i18n.ts.general,
icon: 'ph-faders ph-bold ph-lg',
}));
+
+const useCustomSearchEngine = computed(() => !Object.keys(searchEngineMap).includes(searchEngine.value));
</script>
diff --git a/packages/frontend/src/pages/user/home.vue b/packages/frontend/src/pages/user/home.vue
index 98c0ab4ce9..095645636d 100644
--- a/packages/frontend/src/pages/user/home.vue
+++ b/packages/frontend/src/pages/user/home.vue
@@ -74,7 +74,7 @@ SPDX-License-Identifier: AGPL-3.0-only
/>
</div>
<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>
</div>
<div class="fields system">
diff --git a/packages/frontend/src/pages/welcome.timeline.vue b/packages/frontend/src/pages/welcome.timeline.vue
index be4cb2d2de..4768e31d1d 100644
--- a/packages/frontend/src/pages/welcome.timeline.vue
+++ b/packages/frontend/src/pages/welcome.timeline.vue
@@ -10,7 +10,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<div class="_panel" :class="$style.content">
<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>
- <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>
</div>
<div v-if="note.files.length > 0" :class="$style.richcontent">
diff --git a/packages/frontend/src/scripts/search-engine-map.ts b/packages/frontend/src/scripts/search-engine-map.ts
new file mode 100644
index 0000000000..3fb06d135d
--- /dev/null
+++ b/packages/frontend/src/scripts/search-engine-map.ts
@@ -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',
+};
diff --git a/packages/frontend/src/store.ts b/packages/frontend/src/store.ts
index f3f6746b62..e975439456 100644
--- a/packages/frontend/src/store.ts
+++ b/packages/frontend/src/store.ts
@@ -6,6 +6,7 @@
import { markRaw, ref } from 'vue';
import * as Misskey from 'misskey-js';
import { miLocalStorage } from './local-storage.js';
+import { searchEngineMap } from './scripts/search-engine-map.js';
import type { SoundType } from '@/scripts/sound.js';
import { Storage } from '@/pizzax.js';
import { hemisphere } from '@/scripts/intl-const.js';
@@ -311,6 +312,10 @@ export const defaultStore = markRaw(new Storage('base', {
where: 'device',
default: false,
},
+ searchEngine: {
+ where: 'account',
+ default: Object.keys(searchEngineMap)[0],
+ },
noteDesign: {
where: 'device',
default: 'sharkey' as 'sharkey' | 'misskey',
diff --git a/packages/frontend/src/style.scss b/packages/frontend/src/style.scss
index f77739fdbc..37d1a3c557 100644
--- a/packages/frontend/src/style.scss
+++ b/packages/frontend/src/style.scss
@@ -565,7 +565,7 @@ html[data-color-mode=dark] ._woodenFrame {
// MFM -----------------------------
-div > bdi, p > bdi { display: block }
+bdi.block { display: block }
._mfm_blur_ {
filter: blur(6px);
@@ -716,4 +716,4 @@ div > bdi, p > bdi { display: block }
100% {
opacity: 1;
}
-} \ No newline at end of file
+}