summaryrefslogtreecommitdiff
path: root/packages/frontend/src
diff options
context:
space:
mode:
authordakkar <dakkar@thenautilus.net>2024-05-11 13:11:07 +0100
committerdakkar <dakkar@thenautilus.net>2024-05-11 13:11:07 +0100
commit30bd7768d6d892629cd924da38bbc7ec0d2a117a (patch)
tree1bf440d1c4df5ecb7a765fedbe26bab41d6b53cc /packages/frontend/src
parentfix some icons (diff)
parentmerge: bump develop after 2024.3.3 (!512) (diff)
downloadsharkey-30bd7768d6d892629cd924da38bbc7ec0d2a117a.tar.gz
sharkey-30bd7768d6d892629cd924da38bbc7ec0d2a117a.tar.bz2
sharkey-30bd7768d6d892629cd924da38bbc7ec0d2a117a.zip
Merge branch 'develop' into future-2024-04-25-post
Diffstat (limited to 'packages/frontend/src')
-rw-r--r--packages/frontend/src/components/MkAutocomplete.vue2
-rw-r--r--packages/frontend/src/components/MkEmojiPicker.vue2
-rw-r--r--packages/frontend/src/components/MkFileListForAdmin.vue2
-rw-r--r--packages/frontend/src/components/MkPageWindow.vue3
-rw-r--r--packages/frontend/src/components/MkPagination.vue18
-rw-r--r--packages/frontend/src/components/MkSignupDialog.rules.vue2
-rw-r--r--packages/frontend/src/components/MkTutorialDialog.Note.vue15
-rw-r--r--packages/frontend/src/components/MkUserList.vue2
-rw-r--r--packages/frontend/src/components/MkVisitorDashboard.vue2
-rw-r--r--packages/frontend/src/components/global/MkCustomEmoji.vue1
-rw-r--r--packages/frontend/src/components/global/MkEmoji.vue5
-rw-r--r--packages/frontend/src/pages/about.federation.vue2
-rw-r--r--packages/frontend/src/pages/about.vue2
-rw-r--r--packages/frontend/src/pages/admin/abuses.vue2
-rw-r--r--packages/frontend/src/pages/admin/approvals.vue2
-rw-r--r--packages/frontend/src/pages/admin/federation.vue2
-rw-r--r--packages/frontend/src/pages/admin/invites.vue2
-rw-r--r--packages/frontend/src/pages/admin/modlog.vue2
-rw-r--r--packages/frontend/src/pages/admin/roles.role.vue2
-rw-r--r--packages/frontend/src/pages/admin/users.vue2
-rw-r--r--packages/frontend/src/pages/custom-emojis-manager.vue6
-rw-r--r--packages/frontend/src/pages/emoji-edit-dialog.vue2
-rw-r--r--packages/frontend/src/pages/settings/notifications.notification-config.vue10
-rw-r--r--packages/frontend/src/pages/settings/preferences-backups.vue9
-rw-r--r--packages/frontend/src/pages/user/index.vue2
-rw-r--r--packages/frontend/src/scripts/autocomplete.ts4
-rw-r--r--packages/frontend/src/scripts/check-word-mute.ts28
-rw-r--r--packages/frontend/src/scripts/chiptune2.ts10
-rw-r--r--packages/frontend/src/scripts/nyaize.ts8
-rw-r--r--packages/frontend/src/scripts/sanitize-html.ts18
30 files changed, 120 insertions, 49 deletions
diff --git a/packages/frontend/src/components/MkAutocomplete.vue b/packages/frontend/src/components/MkAutocomplete.vue
index 8b665bfacd..b04a1c92e7 100644
--- a/packages/frontend/src/components/MkAutocomplete.vue
+++ b/packages/frontend/src/components/MkAutocomplete.vue
@@ -238,7 +238,7 @@ function exec() {
return;
}
- emojis.value = searchEmoji(props.q.toLowerCase(), emojiDb.value);
+ emojis.value = searchEmoji(props.q.normalize('NFC').toLowerCase(), emojiDb.value);
} else if (props.type === 'mfmTag') {
if (!props.q || props.q === '') {
mfmTags.value = MFM_TAGS;
diff --git a/packages/frontend/src/components/MkEmojiPicker.vue b/packages/frontend/src/components/MkEmojiPicker.vue
index 1219a29d85..53fca97fc0 100644
--- a/packages/frontend/src/components/MkEmojiPicker.vue
+++ b/packages/frontend/src/components/MkEmojiPicker.vue
@@ -205,7 +205,7 @@ watch(q, () => {
return;
}
- const newQ = q.value.replace(/:/g, '').toLowerCase();
+ const newQ = q.value.replace(/:/g, '').normalize('NFC').toLowerCase();
const searchCustom = () => {
const max = 100;
diff --git a/packages/frontend/src/components/MkFileListForAdmin.vue b/packages/frontend/src/components/MkFileListForAdmin.vue
index f3305e9f54..bab844c27f 100644
--- a/packages/frontend/src/components/MkFileListForAdmin.vue
+++ b/packages/frontend/src/components/MkFileListForAdmin.vue
@@ -5,7 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<template>
<div>
- <MkPagination v-slot="{items}" :pagination="pagination" class="urempief" :class="{ grid: viewMode === 'grid' }">
+ <MkPagination v-slot="{items}" :pagination="pagination" :displayLimit="50" class="urempief" :class="{ grid: viewMode === 'grid' }">
<MkA
v-for="file in (items as Misskey.entities.DriveFile[])"
:key="file.id"
diff --git a/packages/frontend/src/components/MkPageWindow.vue b/packages/frontend/src/components/MkPageWindow.vue
index c3fa724a7a..d664dc9731 100644
--- a/packages/frontend/src/components/MkPageWindow.vue
+++ b/packages/frontend/src/components/MkPageWindow.vue
@@ -18,7 +18,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<template #header>
<template v-if="pageMetadata">
<i v-if="pageMetadata.icon" :class="pageMetadata.icon" style="margin-right: 0.5em;"></i>
- <span>{{ pageMetadata.title }}</span>
+ <span><MkUserName v-if="pageMetadata.userName?.name" :user="pageMetadata.userName" />{{ pageMetadata.title }}</span>
</template>
</template>
@@ -43,6 +43,7 @@ import { claimAchievement } from '@/scripts/achievements.js';
import { getScrollContainer } from '@/scripts/scroll.js';
import { useRouterFactory } from '@/router/supplier.js';
import { mainRouter } from '@/router/main.js';
+import MkUserName from './global/MkUserName.vue';
const props = defineProps<{
initialPath: string;
diff --git a/packages/frontend/src/components/MkPagination.vue b/packages/frontend/src/components/MkPagination.vue
index 62a85389ad..6f6007d432 100644
--- a/packages/frontend/src/components/MkPagination.vue
+++ b/packages/frontend/src/components/MkPagination.vue
@@ -395,10 +395,10 @@ const prepend = (item: MisskeyEntity): void => {
* @param newItems 新しいアイテムの配列
*/
function unshiftItems(newItems: MisskeyEntity[]) {
- const length = newItems.length + items.value.size;
- items.value = new Map([...arrayToEntries(newItems), ...items.value].slice(0, props.displayLimit));
-
- if (length >= props.displayLimit) more.value = true;
+ const prevLength = items.value.size;
+ items.value = new Map([...arrayToEntries(newItems), ...items.value].slice(0, newItems.length + props.displayLimit));
+ // if we truncated, mark that there are more values to fetch
+ if (items.value.size < prevLength) more.value = true;
}
/**
@@ -406,10 +406,10 @@ function unshiftItems(newItems: MisskeyEntity[]) {
* @param oldItems 古いアイテムの配列
*/
function concatItems(oldItems: MisskeyEntity[]) {
- const length = oldItems.length + items.value.size;
- items.value = new Map([...items.value, ...arrayToEntries(oldItems)].slice(0, props.displayLimit));
-
- if (length >= props.displayLimit) more.value = true;
+ const prevLength = items.value.size;
+ items.value = new Map([...items.value, ...arrayToEntries(oldItems)].slice(0, oldItems.length + props.displayLimit));
+ // if we truncated, mark that there are more values to fetch
+ if (items.value.size < prevLength) more.value = true;
}
function executeQueue() {
@@ -418,7 +418,7 @@ function executeQueue() {
}
function prependQueue(newItem: MisskeyEntity) {
- queue.value = new Map([[newItem.id, newItem], ...queue.value].slice(0, props.displayLimit) as [string, MisskeyEntity][]);
+ queue.value = new Map([[newItem.id, newItem], ...queue.value] as [string, MisskeyEntity][]);
}
/*
diff --git a/packages/frontend/src/components/MkSignupDialog.rules.vue b/packages/frontend/src/components/MkSignupDialog.rules.vue
index 18a9eeda23..c2435b308f 100644
--- a/packages/frontend/src/components/MkSignupDialog.rules.vue
+++ b/packages/frontend/src/components/MkSignupDialog.rules.vue
@@ -65,7 +65,7 @@ SPDX-License-Identifier: AGPL-3.0-only
import { computed, ref } from 'vue';
import { instance } from '@/instance.js';
import { i18n } from '@/i18n.js';
-import sanitizeHtml from 'sanitize-html';
+import sanitizeHtml from '@/scripts/sanitize-html.js';
import MkButton from '@/components/MkButton.vue';
import MkFolder from '@/components/MkFolder.vue';
import MkSwitch from '@/components/MkSwitch.vue';
diff --git a/packages/frontend/src/components/MkTutorialDialog.Note.vue b/packages/frontend/src/components/MkTutorialDialog.Note.vue
index 57216058fd..725cfcdc33 100644
--- a/packages/frontend/src/components/MkTutorialDialog.Note.vue
+++ b/packages/frontend/src/components/MkTutorialDialog.Note.vue
@@ -16,9 +16,20 @@ SPDX-License-Identifier: AGPL-3.0-only
</div>
<div v-else-if="phase === 'howToReact'" class="_gaps">
<div style="text-align: center; padding: 0 16px;">{{ i18n.ts._initialTutorial._reaction.description }}</div>
- <div>{{ i18n.ts._initialTutorial._reaction.letsTryReacting }}</div>
+ <I18n :src="i18n.ts._initialTutorial._reaction.letsTryReacting" tag="div">
+ <template #reaction>
+ <i class="ph-smiley ph-bold ph-lg"></i>
+ </template>
+ </I18n>
<MkNote :class="$style.exampleNoteRoot" :note="exampleNote" :mock="true" @reaction="addReaction" @removeReaction="removeReaction"/>
- <div v-if="onceReacted"><b style="color: var(--accent);"><i class="ph-check ph-bold ph-lg"></i> {{ i18n.ts._initialTutorial.wellDone }}</b> {{ i18n.ts._initialTutorial._reaction.reactNotification }}<br>{{ i18n.ts._initialTutorial._reaction.reactDone }}</div>
+ <div v-if="onceReacted">
+ <b style="color: var(--accent);"><i class="ph-check ph-bold ph-lg"></i> {{ i18n.ts._initialTutorial.wellDone }}</b> {{ i18n.ts._initialTutorial._reaction.reactNotification }}<br>
+ <I18n :src="i18n.ts._initialTutorial._reaction.reactDone">
+ <template #undo>
+ <i class="ph-minus ph-bold ph-lg"></i>
+ </template>
+ </I18n>
+ </div>
</div>
</template>
diff --git a/packages/frontend/src/components/MkUserList.vue b/packages/frontend/src/components/MkUserList.vue
index 17a9254d01..ac82ecc3d6 100644
--- a/packages/frontend/src/components/MkUserList.vue
+++ b/packages/frontend/src/components/MkUserList.vue
@@ -4,7 +4,7 @@ SPDX-License-Identifier: AGPL-3.0-only
-->
<template>
-<MkPagination :pagination="pagination">
+<MkPagination :pagination="pagination" :displayLimit="50">
<template #empty>
<div class="_fullinfo">
<img :src="infoImageUrl" class="_ghost"/>
diff --git a/packages/frontend/src/components/MkVisitorDashboard.vue b/packages/frontend/src/components/MkVisitorDashboard.vue
index d8e6ba9a09..f9f16c594e 100644
--- a/packages/frontend/src/components/MkVisitorDashboard.vue
+++ b/packages/frontend/src/components/MkVisitorDashboard.vue
@@ -56,7 +56,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<script lang="ts" setup>
import { ref } from 'vue';
import * as Misskey from 'misskey-js';
-import sanitizeHtml from 'sanitize-html';
+import sanitizeHtml from '@/scripts/sanitize-html.js';
import XSigninDialog from '@/components/MkSigninDialog.vue';
import XSignupDialog from '@/components/MkSignupDialog.vue';
import MkButton from '@/components/MkButton.vue';
diff --git a/packages/frontend/src/components/global/MkCustomEmoji.vue b/packages/frontend/src/components/global/MkCustomEmoji.vue
index b57a311c0c..8ba4e396b7 100644
--- a/packages/frontend/src/components/global/MkCustomEmoji.vue
+++ b/packages/frontend/src/components/global/MkCustomEmoji.vue
@@ -85,6 +85,7 @@ const errored = ref(url.value == null);
function onClick(ev: MouseEvent) {
if (props.menu) {
+ ev.stopPropagation();
os.popupMenu([{
type: 'label',
text: `:${props.name}:`,
diff --git a/packages/frontend/src/components/global/MkEmoji.vue b/packages/frontend/src/components/global/MkEmoji.vue
index 2e7a0c5bb7..b6b5aaba32 100644
--- a/packages/frontend/src/components/global/MkEmoji.vue
+++ b/packages/frontend/src/components/global/MkEmoji.vue
@@ -4,8 +4,8 @@ SPDX-License-Identifier: AGPL-3.0-only
-->
<template>
-<img v-if="!useOsNativeEmojis" :class="$style.root" :src="url" :alt="props.emoji" decoding="async" @pointerenter="computeTitle" @click="onClick" v-on:click.stop/>
-<span v-else :alt="props.emoji" @pointerenter="computeTitle" @click="onClick" v-on:click.stop>{{ colorizedNativeEmoji }}</span>
+<img v-if="!useOsNativeEmojis" :class="$style.root" :src="url" :alt="props.emoji" decoding="async" @pointerenter="computeTitle" @click="onClick"/>
+<span v-else :alt="props.emoji" @pointerenter="computeTitle" @click="onClick">{{ colorizedNativeEmoji }}</span>
</template>
<script lang="ts" setup>
@@ -39,6 +39,7 @@ function computeTitle(event: PointerEvent): void {
function onClick(ev: MouseEvent) {
if (props.menu) {
+ ev.stopPropagation();
os.popupMenu([{
type: 'label',
text: props.emoji,
diff --git a/packages/frontend/src/pages/about.federation.vue b/packages/frontend/src/pages/about.federation.vue
index c7f2315faa..b8f2fcc883 100644
--- a/packages/frontend/src/pages/about.federation.vue
+++ b/packages/frontend/src/pages/about.federation.vue
@@ -42,7 +42,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</FormSplit>
</div>
- <MkPagination v-slot="{items}" ref="instances" :key="host + state" :pagination="pagination">
+ <MkPagination v-slot="{items}" ref="instances" :key="host + state" :pagination="pagination" :displayLimit="50">
<div :class="$style.items">
<MkA v-for="instance in items" :key="instance.id" v-tooltip.mfm="`Status: ${getStatus(instance)}`" :class="$style.item" :to="`/instance-info/${instance.host}`">
<MkInstanceCardMini :instance="instance"/>
diff --git a/packages/frontend/src/pages/about.vue b/packages/frontend/src/pages/about.vue
index f2aceada7d..23960d39d9 100644
--- a/packages/frontend/src/pages/about.vue
+++ b/packages/frontend/src/pages/about.vue
@@ -130,7 +130,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</template>
<script lang="ts" setup>
-import sanitizeHtml from 'sanitize-html';
+import sanitizeHtml from '@/scripts/sanitize-html.js';
import { computed, watch, ref } from 'vue';
import * as Misskey from 'misskey-js';
import XEmojis from './about.emojis.vue';
diff --git a/packages/frontend/src/pages/admin/abuses.vue b/packages/frontend/src/pages/admin/abuses.vue
index 42fcc3a598..6e1f5f9cec 100644
--- a/packages/frontend/src/pages/admin/abuses.vue
+++ b/packages/frontend/src/pages/admin/abuses.vue
@@ -41,7 +41,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</div>
-->
- <MkPagination v-slot="{items}" ref="reports" :pagination="pagination" style="margin-top: var(--margin);">
+ <MkPagination v-slot="{items}" ref="reports" :pagination="pagination" :displayLimit="50" style="margin-top: var(--margin);">
<XAbuseReport v-for="report in items" :key="report.id" :report="report" @resolved="resolved"/>
</MkPagination>
</div>
diff --git a/packages/frontend/src/pages/admin/approvals.vue b/packages/frontend/src/pages/admin/approvals.vue
index 998e16681a..03420232c8 100644
--- a/packages/frontend/src/pages/admin/approvals.vue
+++ b/packages/frontend/src/pages/admin/approvals.vue
@@ -4,7 +4,7 @@
<template #header><XHeader :actions="headerActions" :tabs="headerTabs"/></template>
<MkSpacer :contentMax="900">
<div class="_gaps_m">
- <MkPagination ref="paginationComponent" :pagination="pagination">
+ <MkPagination ref="paginationComponent" :pagination="pagination" :displayLimit="50">
<template #default="{ items }">
<div class="_gaps_s">
<SkApprovalUser v-for="item in items" :key="item.id" :user="(item as any)" :onDeleted="deleted"/>
diff --git a/packages/frontend/src/pages/admin/federation.vue b/packages/frontend/src/pages/admin/federation.vue
index f8c4a3b272..db9211929f 100644
--- a/packages/frontend/src/pages/admin/federation.vue
+++ b/packages/frontend/src/pages/admin/federation.vue
@@ -45,7 +45,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</FormSplit>
</div>
- <MkPagination v-slot="{items}" ref="instances" :key="host + state" :pagination="pagination">
+ <MkPagination v-slot="{items}" ref="instances" :key="host + state" :pagination="pagination" :displayLimit="50">
<div :class="$style.instances">
<MkA v-for="instance in items" :key="instance.id" v-tooltip.mfm="`Status: ${getStatus(instance)}`" :class="$style.instance" :to="`/instance-info/${instance.host}`">
<MkInstanceCardMini :instance="instance"/>
diff --git a/packages/frontend/src/pages/admin/invites.vue b/packages/frontend/src/pages/admin/invites.vue
index 7b8a1e1d4e..4dc8ded7a2 100644
--- a/packages/frontend/src/pages/admin/invites.vue
+++ b/packages/frontend/src/pages/admin/invites.vue
@@ -42,7 +42,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<option value="-usedAt">{{ i18n.ts.usedAt }} ({{ i18n.ts.descendingOrder }})</option>
</MkSelect>
</div>
- <MkPagination ref="pagingComponent" :pagination="pagination">
+ <MkPagination ref="pagingComponent" :pagination="pagination" :displayLimit="50">
<template #default="{ items }">
<div class="_gaps_s">
<MkInviteCode v-for="item in items" :key="item.id" :invite="(item as any)" :onDeleted="deleted" moderator/>
diff --git a/packages/frontend/src/pages/admin/modlog.vue b/packages/frontend/src/pages/admin/modlog.vue
index 4651bb4516..850d36063e 100644
--- a/packages/frontend/src/pages/admin/modlog.vue
+++ b/packages/frontend/src/pages/admin/modlog.vue
@@ -19,7 +19,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</MkInput>
</div>
- <MkPagination v-slot="{items}" ref="logs" :pagination="pagination" style="margin-top: var(--margin);">
+ <MkPagination v-slot="{items}" ref="logs" :pagination="pagination" :displayLimit="50" style="margin-top: var(--margin);">
<div class="_gaps_s">
<XModLog v-for="item in items" :key="item.id" :log="item"/>
</div>
diff --git a/packages/frontend/src/pages/admin/roles.role.vue b/packages/frontend/src/pages/admin/roles.role.vue
index cda524f787..c084d5f8df 100644
--- a/packages/frontend/src/pages/admin/roles.role.vue
+++ b/packages/frontend/src/pages/admin/roles.role.vue
@@ -25,7 +25,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<div class="_gaps">
<MkButton primary rounded @click="assign"><i class="ph-plus ph-bold ph-lg"></i> {{ i18n.ts.assign }}</MkButton>
- <MkPagination :pagination="usersPagination">
+ <MkPagination :pagination="usersPagination" :displayLimit="50">
<template #empty>
<div class="_fullinfo">
<img :src="infoImageUrl" class="_ghost"/>
diff --git a/packages/frontend/src/pages/admin/users.vue b/packages/frontend/src/pages/admin/users.vue
index 626346a998..001b7dc82d 100644
--- a/packages/frontend/src/pages/admin/users.vue
+++ b/packages/frontend/src/pages/admin/users.vue
@@ -44,7 +44,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</MkInput>
</div>
- <MkPagination v-slot="{items}" ref="paginationComponent" :pagination="pagination">
+ <MkPagination v-slot="{items}" ref="paginationComponent" :pagination="pagination" :displayLimit="50">
<div :class="$style.users">
<MkA v-for="user in items" :key="user.id" v-tooltip.mfm="`Last posted: ${dateString(user.updatedAt)}`" :class="$style.user" :to="`/admin/user/${user.id}`">
<MkUserCardMini :user="user"/>
diff --git a/packages/frontend/src/pages/custom-emojis-manager.vue b/packages/frontend/src/pages/custom-emojis-manager.vue
index 1a745d6626..1f9a99d4f5 100644
--- a/packages/frontend/src/pages/custom-emojis-manager.vue
+++ b/packages/frontend/src/pages/custom-emojis-manager.vue
@@ -26,7 +26,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<MkButton inline @click="setLicenseBulk">Set License</MkButton>
<MkButton inline danger @click="delBulk">Delete</MkButton>
</div>
- <MkPagination ref="emojisPaginationComponent" :pagination="pagination">
+ <MkPagination ref="emojisPaginationComponent" :pagination="pagination" :displayLimit="50">
<template #empty><span>{{ i18n.ts.noCustomEmojis }}</span></template>
<template #default="{items}">
<div class="ldhfsamy">
@@ -52,7 +52,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<template #label>{{ i18n.ts.host }}</template>
</MkInput>
</FormSplit>
- <MkPagination :pagination="remotePagination">
+ <MkPagination :pagination="remotePagination" :displayLimit="50">
<template #empty><span>{{ i18n.ts.noCustomEmojis }}</span></template>
<template #default="{items}">
<div class="ldhfsamy">
@@ -352,6 +352,7 @@ definePageMetadata(() => ({
> .img {
width: 42px;
height: 42px;
+ object-fit: contain;
}
> .body {
@@ -398,6 +399,7 @@ definePageMetadata(() => ({
> .img {
width: 32px;
height: 32px;
+ object-fit: contain;
}
> .body {
diff --git a/packages/frontend/src/pages/emoji-edit-dialog.vue b/packages/frontend/src/pages/emoji-edit-dialog.vue
index 64960fd063..d03d3d9128 100644
--- a/packages/frontend/src/pages/emoji-edit-dialog.vue
+++ b/packages/frontend/src/pages/emoji-edit-dialog.vue
@@ -33,7 +33,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</div>
</div>
<MkButton rounded style="margin: 0 auto;" @click="changeImage">{{ i18n.ts.selectFile }}</MkButton>
- <MkInput v-model="name" pattern="[a-z0-9_]" autocapitalize="off">
+ <MkInput v-model="name" autocapitalize="off">
<template #label>{{ i18n.ts.name }}</template>
</MkInput>
<MkInput v-model="category" :datalist="customEmojiCategories">
diff --git a/packages/frontend/src/pages/settings/notifications.notification-config.vue b/packages/frontend/src/pages/settings/notifications.notification-config.vue
index 6dde006106..8d78ce7031 100644
--- a/packages/frontend/src/pages/settings/notifications.notification-config.vue
+++ b/packages/frontend/src/pages/settings/notifications.notification-config.vue
@@ -7,11 +7,11 @@ SPDX-License-Identifier: AGPL-3.0-only
<div class="_gaps_m">
<MkSelect v-model="type">
<option value="all">{{ i18n.ts.all }}</option>
- <option value="following" v-if="hasSender">{{ i18n.ts.following }}</option>
- <option value="follower" v-if="hasSender">{{ i18n.ts.followers }}</option>
- <option value="mutualFollow" v-if="hasSender">{{ i18n.ts.mutualFollow }}</option>
- <option value="followingOrFollower" v-if="hasSender">{{ i18n.ts.followingOrFollower }}</option>
- <option value="list" v-if="hasSender">{{ i18n.ts.userList }}</option>
+ <option v-if="hasSender" value="following">{{ i18n.ts.following }}</option>
+ <option v-if="hasSender" value="follower">{{ i18n.ts.followers }}</option>
+ <option v-if="hasSender" value="mutualFollow">{{ i18n.ts.mutualFollow }}</option>
+ <option v-if="hasSender" value="followingOrFollower">{{ i18n.ts.followingOrFollower }}</option>
+ <option v-if="hasSender" value="list">{{ i18n.ts.userList }}</option>
<option value="never">{{ i18n.ts.none }}</option>
</MkSelect>
diff --git a/packages/frontend/src/pages/settings/preferences-backups.vue b/packages/frontend/src/pages/settings/preferences-backups.vue
index 0facfc6631..c774ab5367 100644
--- a/packages/frontend/src/pages/settings/preferences-backups.vue
+++ b/packages/frontend/src/pages/settings/preferences-backups.vue
@@ -140,6 +140,7 @@ type Profile = {
hot: Record<keyof typeof defaultStoreSaveKeys, unknown>;
cold: Record<keyof typeof coldDeviceStorageSaveKeys, unknown>;
fontSize: string | null;
+ lang: string | null;
cornerRadius: string | null;
useSystemFont: 't' | null;
wallpaper: string | null;
@@ -198,6 +199,7 @@ function getSettings(): Profile['settings'] {
hot,
cold,
fontSize: miLocalStorage.getItem('fontSize'),
+ lang: miLocalStorage.getItem('lang'),
cornerRadius: miLocalStorage.getItem('cornerRadius'),
useSystemFont: miLocalStorage.getItem('useSystemFont') as 't' | null,
wallpaper: miLocalStorage.getItem('wallpaper'),
@@ -313,6 +315,13 @@ async function applyProfile(id: string): Promise<void> {
miLocalStorage.removeItem('fontSize');
}
+ // lang
+ if (settings.lang) {
+ miLocalStorage.setItem('lang', settings.lang);
+ } else {
+ miLocalStorage.removeItem('lang');
+ }
+
// cornerRadius
if (settings.cornerRadius) {
miLocalStorage.setItem('cornerRadius', settings.cornerRadius);
diff --git a/packages/frontend/src/pages/user/index.vue b/packages/frontend/src/pages/user/index.vue
index 7f20e941d3..ebe4176196 100644
--- a/packages/frontend/src/pages/user/index.vue
+++ b/packages/frontend/src/pages/user/index.vue
@@ -130,7 +130,7 @@ definePageMetadata(() => ({
title: i18n.ts.user,
icon: 'ph-user ph-bold ph-lg',
...user.value ? {
- title: user.value.name ? `${user.value.name} (@${user.value.username})` : `@${user.value.username}`,
+ title: user.value.name ? ` (@${user.value.username})` : `@${user.value.username}`,
subtitle: `@${getAcct(user.value)}`,
userName: user.value,
avatar: user.value,
diff --git a/packages/frontend/src/scripts/autocomplete.ts b/packages/frontend/src/scripts/autocomplete.ts
index 9fc8f7843e..d942402ffc 100644
--- a/packages/frontend/src/scripts/autocomplete.ts
+++ b/packages/frontend/src/scripts/autocomplete.ts
@@ -99,7 +99,7 @@ export class Autocomplete {
const isHashtag = hashtagIndex !== -1;
const isMfmParam = mfmParamIndex !== -1 && afterLastMfmParam?.includes('.') && !afterLastMfmParam?.includes(' ');
const isMfmTag = mfmTagIndex !== -1 && !isMfmParam;
- const isEmoji = emojiIndex !== -1 && text.split(/:[a-z0-9_+\-]+:/).pop()!.includes(':');
+ const isEmoji = emojiIndex !== -1 && text.split(/:[\p{Letter}\p{Number}\p{Mark}_+-]+:/u).pop()!.includes(':');
let opened = false;
@@ -125,7 +125,7 @@ export class Autocomplete {
if (isEmoji && !opened && this.onlyType.includes('emoji')) {
const emoji = text.substring(emojiIndex + 1);
if (!emoji.includes(' ')) {
- this.open('emoji', emoji);
+ this.open('emoji', emoji.normalize('NFC'));
opened = true;
}
}
diff --git a/packages/frontend/src/scripts/check-word-mute.ts b/packages/frontend/src/scripts/check-word-mute.ts
index 67e896b4b9..8d3e96cea5 100644
--- a/packages/frontend/src/scripts/check-word-mute.ts
+++ b/packages/frontend/src/scripts/check-word-mute.ts
@@ -3,12 +3,14 @@
* SPDX-License-Identifier: AGPL-3.0-only
*/
-export function checkWordMute(note: Record<string, any>, me: Record<string, any> | null | undefined, mutedWords: Array<string | string[]>): boolean {
+import type { Note, MeDetailed } from "misskey-js/entities.js";
+
+export function checkWordMute(note: Note, me: MeDetailed | null | undefined, mutedWords: Array<string | string[]>): boolean {
// 自分自身
if (me && (note.userId === me.id)) return false;
if (mutedWords.length > 0) {
- const text = ((note.cw ?? '') + '\n' + (note.text ?? '')).trim();
+ const text = getNoteText(note);
if (text === '') return false;
@@ -40,3 +42,25 @@ export function checkWordMute(note: Record<string, any>, me: Record<string, any>
return false;
}
+
+function getNoteText(note: Note): string {
+ const textParts: string[] = [];
+
+ if (note.cw)
+ textParts.push(note.cw);
+
+ if (note.text)
+ textParts.push(note.text);
+
+ if (note.files)
+ for (const file of note.files)
+ if (file.comment)
+ textParts.push(file.comment);
+
+ if (note.poll)
+ for (const choice of note.poll.choices)
+ if (choice.text)
+ textParts.push(choice.text);
+
+ return textParts.join('\n').trim();
+}
diff --git a/packages/frontend/src/scripts/chiptune2.ts b/packages/frontend/src/scripts/chiptune2.ts
index 3cc34c0040..56afb9b708 100644
--- a/packages/frontend/src/scripts/chiptune2.ts
+++ b/packages/frontend/src/scripts/chiptune2.ts
@@ -1,4 +1,3 @@
-// @ts-nocheck
/* eslint-disable */
const ChiptuneAudioContext = window.AudioContext || window.webkitAudioContext;
@@ -6,6 +5,11 @@ const ChiptuneAudioContext = window.AudioContext || window.webkitAudioContext;
let libopenmpt
let libopenmptLoadPromise
+type ChiptuneJsConfig = {
+ repeatCount: number | null;
+ context: AudioContext | null;
+};
+
export function ChiptuneJsConfig (repeatCount?: number, context?: AudioContext) {
this.repeatCount = repeatCount;
this.context = context;
@@ -13,7 +17,7 @@ export function ChiptuneJsConfig (repeatCount?: number, context?: AudioContext)
ChiptuneJsConfig.prototype.constructor = ChiptuneJsConfig;
-export function ChiptuneJsPlayer (config: object) {
+export function ChiptuneJsPlayer (config: ChiptuneJsConfig) {
this.config = config;
this.audioContext = config.context || new ChiptuneAudioContext();
this.context = this.audioContext.createGain();
@@ -27,7 +31,7 @@ ChiptuneJsPlayer.prototype.initialize = function() {
if (libopenmptLoadPromise) return libopenmptLoadPromise;
if (libopenmpt) return Promise.resolve();
- libopenmptLoadPromise = new Promise(async (resolve, reject) => {
+ libopenmptLoadPromise = new Promise<void>(async (resolve, reject) => {
try {
const { Module } = await import('./libopenmpt/libopenmpt.js');
await new Promise((resolve) => {
diff --git a/packages/frontend/src/scripts/nyaize.ts b/packages/frontend/src/scripts/nyaize.ts
index 58ed88fed1..5e6fa298d1 100644
--- a/packages/frontend/src/scripts/nyaize.ts
+++ b/packages/frontend/src/scripts/nyaize.ts
@@ -9,9 +9,9 @@ const koRegex3 = /(야(?=\?))|(야$)|(야(?= ))/gm;
function ifAfter(prefix, fn) {
const preLen = prefix.length;
- const regex = new RegExp(prefix,'i');
- return (x,pos,string) => {
- return pos > 0 && string.substring(pos-preLen,pos).match(regex) ? fn(x) : x;
+ const regex = new RegExp(prefix, 'i');
+ return (x, pos, string) => {
+ return pos > 0 && string.substring(pos - preLen, pos).match(regex) ? fn(x) : x;
};
}
@@ -25,7 +25,7 @@ export function nyaize(text: string): string {
.replace(/one/gi, ifAfter('every', x => x === 'ONE' ? 'NYAN' : 'nyan'))
// ko-KR
.replace(koRegex1, match => String.fromCharCode(
- match.charCodeAt(0)! + '냐'.charCodeAt(0) - '나'.charCodeAt(0),
+ match.charCodeAt(0) + '냐'.charCodeAt(0) - '나'.charCodeAt(0),
))
.replace(koRegex2, '다냥')
.replace(koRegex3, '냥');
diff --git a/packages/frontend/src/scripts/sanitize-html.ts b/packages/frontend/src/scripts/sanitize-html.ts
new file mode 100644
index 0000000000..6e1a46c746
--- /dev/null
+++ b/packages/frontend/src/scripts/sanitize-html.ts
@@ -0,0 +1,18 @@
+/*
+ * SPDX-FileCopyrightText: dakkar and other Sharkey contributors
+ * SPDX-License-Identifier: AGPL-3.0-only
+*/
+
+import original from 'sanitize-html';
+
+export default function sanitizeHtml(str: string | null): string | null {
+ if (str == null) return str;
+ return original(str, {
+ allowedTags: original.defaults.allowedTags.concat(['img', 'audio', 'video', 'center', 'details', 'summary']),
+ allowedAttributes: {
+ ...original.defaults.allowedAttributes,
+ a: original.defaults.allowedAttributes.a.concat(['style']),
+ img: original.defaults.allowedAttributes.img.concat(['style']),
+ },
+ });
+}