Merge remote-tracking branch 'msky/develop' into deps-update-pnpm

This commit is contained in:
kakkokari-gtyih 2025-03-03 20:14:23 +09:00
commit 0c61097917
26 changed files with 683 additions and 594 deletions

View File

@ -5,7 +5,12 @@
- Fix: システムアカウントが削除できる問題を修正 - Fix: システムアカウントが削除できる問題を修正
### Client ### Client
- - Enhance: モデレーターがセンシティブ設定を変更する際に確認ダイアログを出すように
- Enhance: ユーザーページのノート一覧と前後のノート表示でチャンネルのノートを含めるように
- Enhance: 「UIのアニメーションを減らす」で画面上のエフェクトも減らせるように
- Fix: 削除して編集の削除タイミングを投稿後になるように `#14498`
- Fix: フォローされたときのメッセージがちらつくことがある問題を修正
- Fix: 投稿ダイアログがサイズ限界を超えた際にスクロールできない問題を修正
### Server ### Server
- Fix: 特定のケースでActivityPubの処理がデッドロックになることがあるのを修正 - Fix: 特定のケースでActivityPubの処理がデッドロックになることがあるのを修正

8
locales/index.d.ts vendored
View File

@ -5262,6 +5262,14 @@ export interface Locale extends ILocale {
* " {emoji} " * " {emoji} "
*/ */
"reactAreYouSure": ParameterizedString<"emoji">; "reactAreYouSure": ParameterizedString<"emoji">;
/**
*
*/
"markAsSensitiveConfirm": string;
/**
*
*/
"unmarkAsSensitiveConfirm": string;
"_accountSettings": { "_accountSettings": {
/** /**
* *

View File

@ -1311,6 +1311,8 @@ federationSpecified: "このサーバーはホワイトリスト連合で運用
federationDisabled: "このサーバーは連合が無効化されています。他のサーバーのユーザーとやり取りすることはできません。" federationDisabled: "このサーバーは連合が無効化されています。他のサーバーのユーザーとやり取りすることはできません。"
confirmOnReact: "リアクションする際に確認する" confirmOnReact: "リアクションする際に確認する"
reactAreYouSure: "\" {emoji} \" をリアクションしますか?" reactAreYouSure: "\" {emoji} \" をリアクションしますか?"
markAsSensitiveConfirm: "このメディアをセンシティブとして設定しますか?"
unmarkAsSensitiveConfirm: "このメディアのセンシティブ指定を解除しますか?"
_accountSettings: _accountSettings:
requireSigninToViewContents: "コンテンツの表示にログインを必須にする" requireSigninToViewContents: "コンテンツの表示にログインを必須にする"

View File

@ -25,7 +25,7 @@
"misskey-js": "workspace:*", "misskey-js": "workspace:*",
"frontend-shared": "workspace:*", "frontend-shared": "workspace:*",
"punycode.js": "2.3.1", "punycode.js": "2.3.1",
"rollup": "4.34.8", "rollup": "4.34.9",
"sass": "1.85.1", "sass": "1.85.1",
"shiki": "3.1.0", "shiki": "3.1.0",
"tinycolor2": "1.6.0", "tinycolor2": "1.6.0",
@ -42,7 +42,7 @@
"@testing-library/vue": "8.1.0", "@testing-library/vue": "8.1.0",
"@types/estree": "1.0.6", "@types/estree": "1.0.6",
"@types/micromatch": "4.0.9", "@types/micromatch": "4.0.9",
"@types/node": "22.13.7", "@types/node": "22.13.8",
"@types/punycode.js": "npm:@types/punycode@2.1.4", "@types/punycode.js": "npm:@types/punycode@2.1.4",
"@types/tinycolor2": "1.4.6", "@types/tinycolor2": "1.4.6",
"@types/ws": "8.5.14", "@types/ws": "8.5.14",
@ -60,11 +60,11 @@
"micromatch": "4.0.8", "micromatch": "4.0.8",
"msw": "2.7.3", "msw": "2.7.3",
"nodemon": "3.1.9", "nodemon": "3.1.9",
"prettier": "3.5.2", "prettier": "3.5.3",
"start-server-and-test": "2.0.10", "start-server-and-test": "2.0.10",
"vite-plugin-turbosnap": "1.0.3", "vite-plugin-turbosnap": "1.0.3",
"vue-component-type-helpers": "2.2.4", "vue-component-type-helpers": "2.2.8",
"vue-eslint-parser": "9.4.3", "vue-eslint-parser": "9.4.3",
"vue-tsc": "2.2.4" "vue-tsc": "2.2.8"
} }
} }

View File

@ -21,7 +21,7 @@
"lint": "pnpm typecheck && pnpm eslint" "lint": "pnpm typecheck && pnpm eslint"
}, },
"devDependencies": { "devDependencies": {
"@types/node": "22.13.7", "@types/node": "22.13.8",
"@typescript-eslint/eslint-plugin": "8.25.0", "@typescript-eslint/eslint-plugin": "8.25.0",
"@typescript-eslint/parser": "8.25.0", "@typescript-eslint/parser": "8.25.0",
"esbuild": "0.25.0", "esbuild": "0.25.0",

View File

@ -42,7 +42,7 @@
"chartjs-plugin-zoom": "2.2.0", "chartjs-plugin-zoom": "2.2.0",
"chromatic": "11.26.1", "chromatic": "11.26.1",
"compare-versions": "6.1.1", "compare-versions": "6.1.1",
"cropperjs": "2.0.0-rc.2", "cropperjs": "2.0.0",
"date-fns": "4.1.0", "date-fns": "4.1.0",
"estree-walker": "3.0.3", "estree-walker": "3.0.3",
"eventemitter3": "5.0.1", "eventemitter3": "5.0.1",
@ -58,7 +58,7 @@
"misskey-reversi": "workspace:*", "misskey-reversi": "workspace:*",
"photoswipe": "5.4.4", "photoswipe": "5.4.4",
"punycode.js": "2.3.1", "punycode.js": "2.3.1",
"rollup": "4.34.8", "rollup": "4.34.9",
"sanitize-html": "2.14.0", "sanitize-html": "2.14.0",
"sass": "1.85.1", "sass": "1.85.1",
"shiki": "3.1.0", "shiki": "3.1.0",
@ -78,30 +78,30 @@
}, },
"devDependencies": { "devDependencies": {
"@misskey-dev/summaly": "5.2.0", "@misskey-dev/summaly": "5.2.0",
"@storybook/addon-actions": "8.6.2", "@storybook/addon-actions": "8.6.3",
"@storybook/addon-essentials": "8.6.2", "@storybook/addon-essentials": "8.6.3",
"@storybook/addon-interactions": "8.6.2", "@storybook/addon-interactions": "8.6.3",
"@storybook/addon-links": "8.6.2", "@storybook/addon-links": "8.6.3",
"@storybook/addon-mdx-gfm": "8.6.2", "@storybook/addon-mdx-gfm": "8.6.3",
"@storybook/addon-storysource": "8.6.2", "@storybook/addon-storysource": "8.6.3",
"@storybook/blocks": "8.6.2", "@storybook/blocks": "8.6.3",
"@storybook/components": "8.6.2", "@storybook/components": "8.6.3",
"@storybook/core-events": "8.6.2", "@storybook/core-events": "8.6.3",
"@storybook/manager-api": "8.6.2", "@storybook/manager-api": "8.6.3",
"@storybook/preview-api": "8.6.2", "@storybook/preview-api": "8.6.3",
"@storybook/react": "8.6.2", "@storybook/react": "8.6.3",
"@storybook/react-vite": "8.6.2", "@storybook/react-vite": "8.6.3",
"@storybook/test": "8.6.2", "@storybook/test": "8.6.3",
"@storybook/theming": "8.6.2", "@storybook/theming": "8.6.3",
"@storybook/types": "8.6.2", "@storybook/types": "8.6.3",
"@storybook/vue3": "8.6.2", "@storybook/vue3": "8.6.3",
"@storybook/vue3-vite": "8.6.2", "@storybook/vue3-vite": "8.6.3",
"@testing-library/vue": "8.1.0", "@testing-library/vue": "8.1.0",
"@types/canvas-confetti": "1.9.0", "@types/canvas-confetti": "1.9.0",
"@types/estree": "1.0.6", "@types/estree": "1.0.6",
"@types/matter-js": "0.19.8", "@types/matter-js": "0.19.8",
"@types/micromatch": "4.0.9", "@types/micromatch": "4.0.9",
"@types/node": "22.13.7", "@types/node": "22.13.8",
"@types/punycode.js": "npm:@types/punycode@2.1.4", "@types/punycode.js": "npm:@types/punycode@2.1.4",
"@types/sanitize-html": "2.13.0", "@types/sanitize-html": "2.13.0",
"@types/seedrandom": "3.0.8", "@types/seedrandom": "3.0.8",
@ -124,18 +124,18 @@
"msw": "2.7.3", "msw": "2.7.3",
"msw-storybook-addon": "2.0.4", "msw-storybook-addon": "2.0.4",
"nodemon": "3.1.9", "nodemon": "3.1.9",
"prettier": "3.5.2", "prettier": "3.5.3",
"react": "19.0.0", "react": "19.0.0",
"react-dom": "19.0.0", "react-dom": "19.0.0",
"seedrandom": "3.0.5", "seedrandom": "3.0.5",
"start-server-and-test": "2.0.10", "start-server-and-test": "2.0.10",
"storybook": "8.6.2", "storybook": "8.6.3",
"storybook-addon-misskey-theme": "github:misskey-dev/storybook-addon-misskey-theme", "storybook-addon-misskey-theme": "github:misskey-dev/storybook-addon-misskey-theme",
"vite-plugin-turbosnap": "1.0.3", "vite-plugin-turbosnap": "1.0.3",
"vitest": "3.0.7", "vitest": "3.0.7",
"vitest-fetch-mock": "0.4.4", "vitest-fetch-mock": "0.4.4",
"vue-component-type-helpers": "2.2.4", "vue-component-type-helpers": "2.2.8",
"vue-eslint-parser": "9.4.3", "vue-eslint-parser": "9.4.3",
"vue-tsc": "2.2.4" "vue-tsc": "2.2.8"
} }
} }

View File

@ -413,7 +413,7 @@ function computeButtonTitle(ev: MouseEvent): void {
function chosen(emoji: string | Misskey.entities.EmojiSimple | UnicodeEmojiDef, ev?: MouseEvent) { function chosen(emoji: string | Misskey.entities.EmojiSimple | UnicodeEmojiDef, ev?: MouseEvent) {
const el = ev && (ev.currentTarget ?? ev.target) as HTMLElement | null | undefined; const el = ev && (ev.currentTarget ?? ev.target) as HTMLElement | null | undefined;
if (el) { if (el && defaultStore.state.animation) {
const rect = el.getBoundingClientRect(); const rect = el.getBoundingClientRect();
const x = rect.left + (el.offsetWidth / 2); const x = rect.left + (el.offsetWidth / 2);
const y = rect.top + (el.offsetHeight / 2); const y = rect.top + (el.offsetHeight / 2);

View File

@ -259,7 +259,14 @@ function showMenu(ev: MouseEvent) {
}); });
} }
function toggleSensitive(file: Misskey.entities.DriveFile) { async function toggleSensitive(file: Misskey.entities.DriveFile) {
const { canceled } = await os.confirm({
type: 'warning',
text: file.isSensitive ? i18n.ts.unmarkAsSensitiveConfirm : i18n.ts.markAsSensitiveConfirm,
});
if (canceled) return;
os.apiWithDialog('drive/files/update', { os.apiWithDialog('drive/files/update', {
fileId: file.id, fileId: file.id,
isSensitive: !file.isSensitive, isSensitive: !file.isSensitive,

View File

@ -124,11 +124,21 @@ function showMenu(ev: MouseEvent) {
if (iAmModerator) { if (iAmModerator) {
menuItems.push({ menuItems.push({
text: i18n.ts.markAsSensitive, text: props.image.isSensitive ? i18n.ts.unmarkAsSensitive : i18n.ts.markAsSensitive,
icon: 'ti ti-eye-exclamation', icon: 'ti ti-eye-exclamation',
danger: true, danger: true,
action: () => { action: async () => {
os.apiWithDialog('drive/files/update', { fileId: props.image.id, isSensitive: true }); const { canceled } = await os.confirm({
type: 'warning',
text: props.image.isSensitive ? i18n.ts.unmarkAsSensitiveConfirm : i18n.ts.markAsSensitiveConfirm,
});
if (canceled) return;
os.apiWithDialog('drive/files/update', {
fileId: props.image.id,
isSensitive: !props.image.isSensitive,
});
}, },
}); });
} }

View File

@ -284,7 +284,14 @@ function showMenu(ev: MouseEvent) {
}); });
} }
function toggleSensitive(file: Misskey.entities.DriveFile) { async function toggleSensitive(file: Misskey.entities.DriveFile) {
const { canceled } = await os.confirm({
type: 'warning',
text: file.isSensitive ? i18n.ts.unmarkAsSensitiveConfirm : i18n.ts.markAsSensitiveConfirm,
});
if (canceled) return;
os.apiWithDialog('drive/files/update', { os.apiWithDialog('drive/files/update', {
fileId: file.id, fileId: file.id,
isSensitive: !file.isSensitive, isSensitive: !file.isSensitive,

View File

@ -479,7 +479,7 @@ function react(): void {
reaction: '❤️', reaction: '❤️',
}); });
const el = reactButton.value; const el = reactButton.value;
if (el) { if (el && defaultStore.state.animation) {
const rect = el.getBoundingClientRect(); const rect = el.getBoundingClientRect();
const x = rect.left + (el.offsetWidth / 2); const x = rect.left + (el.offsetWidth / 2);
const y = rect.top + (el.offsetHeight / 2); const y = rect.top + (el.offsetHeight / 2);

View File

@ -442,7 +442,7 @@ function react(): void {
reaction: '❤️', reaction: '❤️',
}); });
const el = reactButton.value; const el = reactButton.value;
if (el) { if (el && defaultStore.state.animation) {
const rect = el.getBoundingClientRect(); const rect = el.getBoundingClientRect();
const x = rect.left + (el.offsetWidth / 2); const x = rect.left + (el.offsetWidth / 2);
const y = rect.top + (el.offsetHeight / 2); const y = rect.top + (el.offsetHeight / 2);

View File

@ -67,7 +67,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<MkInfo v-if="hasNotSpecifiedMentions" warn :class="$style.hasNotSpecifiedMentions">{{ i18n.ts.notSpecifiedMentionWarning }} - <button class="_textButton" @click="addMissingMention()">{{ i18n.ts.add }}</button></MkInfo> <MkInfo v-if="hasNotSpecifiedMentions" warn :class="$style.hasNotSpecifiedMentions">{{ i18n.ts.notSpecifiedMentionWarning }} - <button class="_textButton" @click="addMissingMention()">{{ i18n.ts.add }}</button></MkInfo>
<div v-show="useCw" :class="$style.cwOuter"> <div v-show="useCw" :class="$style.cwOuter">
<input ref="cwInputEl" v-model="cw" :class="$style.cw" :placeholder="i18n.ts.annotation" @keydown="onKeydown" @keyup="onKeyup" @compositionend="onCompositionEnd"> <input ref="cwInputEl" v-model="cw" :class="$style.cw" :placeholder="i18n.ts.annotation" @keydown="onKeydown" @keyup="onKeyup" @compositionend="onCompositionEnd">
<div v-if="maxCwTextLength - cwTextLength < 20" :class="['_acrylic', $style.cwTextCount, { [$style.cwTextOver]: cwTextLength > maxCwTextLength }]">{{ maxCwTextLength - cwTextLength }}</div> <div v-if="maxCwTextLength - cwTextLength < 20" :class="['_acrylic', $style.cwTextCount, { [$style.cwTextOver]: cwTextLength > maxCwTextLength }]">{{ maxCwTextLength - cwTextLength }}</div>
</div> </div>
<div :class="[$style.textOuter, { [$style.withCw]: useCw }]"> <div :class="[$style.textOuter, { [$style.withCw]: useCw }]">
<div v-if="channel" :class="$style.colorBar" :style="{ background: channel.color }"></div> <div v-if="channel" :class="$style.colorBar" :style="{ background: channel.color }"></div>
@ -104,18 +104,18 @@ SPDX-License-Identifier: AGPL-3.0-only
<script lang="ts" setup> <script lang="ts" setup>
import { inject, watch, nextTick, onMounted, defineAsyncComponent, provide, shallowRef, ref, computed } from 'vue'; import { inject, watch, nextTick, onMounted, defineAsyncComponent, provide, shallowRef, ref, computed } from 'vue';
import type { ShallowRef } from 'vue';
import * as mfm from 'mfm-js'; import * as mfm from 'mfm-js';
import * as Misskey from 'misskey-js'; import * as Misskey from 'misskey-js';
import insertTextAtCursor from 'insert-text-at-cursor'; import insertTextAtCursor from 'insert-text-at-cursor';
import { toASCII } from 'punycode.js'; import { toASCII } from 'punycode.js';
import { host, url } from '@@/js/config.js'; import { host, url } from '@@/js/config.js';
import type { ShallowRef } from 'vue';
import type { PostFormProps } from '@/types/post-form.js'; import type { PostFormProps } from '@/types/post-form.js';
import MkNoteSimple from '@/components/MkNoteSimple.vue'; import type { PollEditorModelValue } from '@/components/MkPollEditor.vue';
import MkNotePreview from '@/components/MkNotePreview.vue'; import MkNotePreview from '@/components/MkNotePreview.vue';
import XPostFormAttaches from '@/components/MkPostFormAttaches.vue'; import XPostFormAttaches from '@/components/MkPostFormAttaches.vue';
import MkPollEditor from '@/components/MkPollEditor.vue'; import MkPollEditor from '@/components/MkPollEditor.vue';
import type { PollEditorModelValue } from '@/components/MkPollEditor.vue'; import MkNoteSimple from '@/components/MkNoteSimple.vue';
import { erase, unique } from '@/scripts/array.js'; import { erase, unique } from '@/scripts/array.js';
import { extractMentions } from '@/scripts/extract-mentions.js'; import { extractMentions } from '@/scripts/extract-mentions.js';
import { formatTimeString } from '@/scripts/format-time-string.js'; import { formatTimeString } from '@/scripts/format-time-string.js';
@ -150,6 +150,7 @@ const props = withDefaults(defineProps<PostFormProps & {
autofocus: true, autofocus: true,
mock: false, mock: false,
initialLocalOnly: undefined, initialLocalOnly: undefined,
deleteInitialNoteAfterPost: false,
}); });
provide('mock', props.mock); provide('mock', props.mock);
@ -751,7 +752,7 @@ async function post(ev?: MouseEvent) {
if (ev) { if (ev) {
const el = (ev.currentTarget ?? ev.target) as HTMLElement | null; const el = (ev.currentTarget ?? ev.target) as HTMLElement | null;
if (el) { if (el && defaultStore.state.animation) {
const rect = el.getBoundingClientRect(); const rect = el.getBoundingClientRect();
const x = rect.left + (el.offsetWidth / 2); const x = rect.left + (el.offsetWidth / 2);
const y = rect.top + (el.offsetHeight / 2); const y = rect.top + (el.offsetHeight / 2);
@ -845,6 +846,12 @@ async function post(ev?: MouseEvent) {
clear(); clear();
} }
nextTick(() => { nextTick(() => {
//
if (props.initialNote && props.deleteInitialNoteAfterPost) {
misskeyApi('notes/delete', {
noteId: props.initialNote.id,
});
}
deleteDraft(); deleteDraft();
emit('posted'); emit('posted');
if (postData.text && postData.text !== '') { if (postData.text && postData.text !== '') {
@ -896,6 +903,11 @@ async function post(ev?: MouseEvent) {
if (m === 0 && s === 0) { if (m === 0 && s === 0) {
claimAchievement('postedAt0min0sec'); claimAchievement('postedAt0min0sec');
} }
if (props.initialNote && props.deleteInitialNoteAfterPost) {
if (date.getTime() - new Date(props.initialNote.createdAt).getTime() < 1000 * 60 && props.initialNote.userId === $i.id) {
claimAchievement('noteDeletedWithin1min');
}
}
}); });
}).catch(err => { }).catch(err => {
posting.value = false; posting.value = false;
@ -1070,6 +1082,8 @@ defineExpose({
&.modal { &.modal {
width: 100%; width: 100%;
max-width: 520px; max-width: 520px;
overflow-x: clip;
overflow-y: auto;
} }
} }

View File

@ -4,8 +4,23 @@ SPDX-License-Identifier: AGPL-3.0-only
--> -->
<template> <template>
<MkModal ref="modal" :preferType="'dialog'" @click="modal?.close()" @closed="onModalClosed()" @esc="modal?.close()"> <MkModal
<MkPostForm ref="form" :class="$style.form" v-bind="props" autofocus freezeAfterPosted @posted="onPosted" @cancel="modal?.close()" @esc="modal?.close()"/> ref="modal"
:preferType="'dialog'"
@click="modal?.close()"
@closed="onModalClosed()"
@esc="modal?.close()"
>
<MkPostForm
ref="form"
:class="$style.form"
v-bind="props"
autofocus
freezeAfterPosted
@posted="onPosted"
@cancel="modal?.close()"
@esc="modal?.close()"
/>
</MkModal> </MkModal>
</template> </template>

View File

@ -4,12 +4,14 @@
*/ */
import MkRippleEffect from '@/components/MkRippleEffect.vue'; import MkRippleEffect from '@/components/MkRippleEffect.vue';
import { defaultStore } from '@/store.js';
import { popup } from '@/os.js'; import { popup } from '@/os.js';
export default { export default {
mounted(el, binding, vn) { mounted(el, binding, vn) {
// 明示的に false であればバインドしない // 明示的に false であればバインドしない
if (binding.value === false) return; if (binding.value === false) return;
if (!defaultStore.state.animation) return;
el.addEventListener('click', () => { el.addEventListener('click', () => {
const rect = el.getBoundingClientRect(); const rect = el.getBoundingClientRect();

View File

@ -36,8 +36,9 @@ SPDX-License-Identifier: AGPL-3.0-only
<MkA v-if="file.user" class="user" :to="`/admin/user/${file.user.id}`"> <MkA v-if="file.user" class="user" :to="`/admin/user/${file.user.id}`">
<MkUserCardMini :user="file.user"/> <MkUserCardMini :user="file.user"/>
</MkA> </MkA>
<div> <div>
<MkSwitch v-model="isSensitive" @update:modelValue="toggleIsSensitive">{{ i18n.ts.sensitive }}</MkSwitch> <MkSwitch :modelValue="isSensitive" @update:modelValue="toggleSensitive">{{ i18n.ts.sensitive }}</MkSwitch>
</div> </div>
<div> <div>
@ -117,9 +118,21 @@ async function del() {
}); });
} }
async function toggleIsSensitive(v) { async function toggleSensitive() {
await misskeyApi('drive/files/update', { fileId: props.fileId, isSensitive: v }); if (!file.value) return;
isSensitive.value = v;
const { canceled } = await os.confirm({
type: 'warning',
text: isSensitive.value ? i18n.ts.unmarkAsSensitiveConfirm : i18n.ts.markAsSensitiveConfirm,
});
if (canceled) return;
isSensitive.value = !isSensitive.value;
os.apiWithDialog('drive/files/update', {
fileId: file.value.id,
isSensitive: !file.value.isSensitive,
});
} }
const headerActions = computed(() => [{ const headerActions = computed(() => [{

View File

@ -87,6 +87,7 @@ const prevUserPagination: Paging = {
params: computed(() => note.value ? ({ params: computed(() => note.value ? ({
userId: note.value.userId, userId: note.value.userId,
untilId: note.value.id, untilId: note.value.id,
withChannelNotes: true,
}) : undefined), }) : undefined),
}; };
@ -97,6 +98,8 @@ const nextUserPagination: Paging = {
params: computed(() => note.value ? ({ params: computed(() => note.value ? ({
userId: note.value.userId, userId: note.value.userId,
sinceId: note.value.id, sinceId: note.value.id,
withChannelNotes: true,
includeSensitiveChannel: $i != null,
}) : undefined), }) : undefined),
}; };

View File

@ -120,6 +120,7 @@ import { i18n } from '@/i18n.js';
import { instance } from '@/instance.js'; import { instance } from '@/instance.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';
import { apLookup } from '@/scripts/lookup.js';
import { useRouter } from '@/router/supplier.js'; import { useRouter } from '@/router/supplier.js';
import MkButton from '@/components/MkButton.vue'; import MkButton from '@/components/MkButton.vue';
import MkFoldableSection from '@/components/MkFoldableSection.vue'; import MkFoldableSection from '@/components/MkFoldableSection.vue';
@ -260,13 +261,7 @@ async function search() {
text: i18n.ts.lookupConfirm, text: i18n.ts.lookupConfirm,
}); });
if (!confirm.canceled) { if (!confirm.canceled) {
const promise = misskeyApi('ap/show', { const res = await apLookup(searchParams.value.query);
uri: searchParams.value.query,
});
os.promiseDialog(promise, null, null, i18n.ts.fetchingAsApObject);
const res = await promise;
if (res.type === 'User') { if (res.type === 'User') {
router.push(`/@${res.object.username}@${res.object.host}`); router.push(`/@${res.object.username}@${res.object.host}`);

View File

@ -49,7 +49,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</div> </div>
</div> </div>
<div v-if="user.followedMessage != null" class="followedMessage"> <div v-if="user.followedMessage != null" class="followedMessage">
<MkFukidashi class="fukidashi" :tail="narrow ? 'none' : 'left'" negativeMargin shadow> <MkFukidashi class="fukidashi" :tail="narrow ? 'none' : 'left'" negativeMargin>
<div class="messageHeader">{{ i18n.ts.messageToFollower }}</div> <div class="messageHeader">{{ i18n.ts.messageToFollower }}</div>
<div><MkSparkle><Mfm :plain="true" :text="user.followedMessage" :author="user"/></MkSparkle></div> <div><MkSparkle><Mfm :plain="true" :text="user.followedMessage" :author="user"/></MkSparkle></div>
</MkFukidashi> </MkFukidashi>

View File

@ -43,7 +43,7 @@ const pagination = computed(() => tab.value === 'featured' ? {
userId: props.user.id, userId: props.user.id,
withRenotes: tab.value === 'all', withRenotes: tab.value === 'all',
withReplies: tab.value === 'all', withReplies: tab.value === 'all',
withChannelNotes: tab.value === 'all', withChannelNotes: true,
withFiles: tab.value === 'files', withFiles: tab.value === 'files',
}, },
}); });

View File

@ -4,10 +4,10 @@
*/ */
import { defineAsyncComponent } from 'vue'; import { defineAsyncComponent } from 'vue';
import type { Ref, ShallowRef } from 'vue';
import * as Misskey from 'misskey-js'; import * as Misskey from 'misskey-js';
import { url } from '@@/js/config.js'; import { url } from '@@/js/config.js';
import { claimAchievement } from './achievements.js'; import { claimAchievement } from './achievements.js';
import type { Ref, ShallowRef } from 'vue';
import type { MenuItem } from '@/types/menu.js'; import type { MenuItem } from '@/types/menu.js';
import { $i } from '@/account.js'; import { $i } from '@/account.js';
import { i18n } from '@/i18n.js'; import { i18n } from '@/i18n.js';
@ -208,15 +208,7 @@ export function getNoteMenu(props: {
}).then(({ canceled }) => { }).then(({ canceled }) => {
if (canceled) return; if (canceled) return;
misskeyApi('notes/delete', { os.post({ initialNote: appearNote, renote: appearNote.renote, reply: appearNote.reply, channel: appearNote.channel, deleteInitialNoteAfterPost: true });
noteId: appearNote.id,
});
os.post({ initialNote: appearNote, renote: appearNote.renote, reply: appearNote.reply, channel: appearNote.channel });
if (Date.now() - new Date(appearNote.createdAt).getTime() < 1000 * 60 && appearNote.userId === $i.id) {
claimAchievement('noteDeletedWithin1min');
}
}); });
} }
@ -558,7 +550,7 @@ export function getRenoteMenu(props: {
icon: 'ti ti-repeat', icon: 'ti ti-repeat',
action: () => { action: () => {
const el = props.renoteButton.value; const el = props.renoteButton.value;
if (el) { if (el && defaultStore.state.animation) {
const rect = el.getBoundingClientRect(); const rect = el.getBoundingClientRect();
const x = rect.left + (el.offsetWidth / 2); const x = rect.left + (el.offsetWidth / 2);
const y = rect.top + (el.offsetHeight / 2); const y = rect.top + (el.offsetHeight / 2);
@ -596,7 +588,7 @@ export function getRenoteMenu(props: {
icon: 'ti ti-repeat', icon: 'ti ti-repeat',
action: () => { action: () => {
const el = props.renoteButton.value; const el = props.renoteButton.value;
if (el) { if (el && defaultStore.state.animation) {
const rect = el.getBoundingClientRect(); const rect = el.getBoundingClientRect();
const x = rect.left + (el.offsetWidth / 2); const x = rect.left + (el.offsetWidth / 2);
const y = rect.top + (el.offsetHeight / 2); const y = rect.top + (el.offsetHeight / 2);
@ -647,7 +639,7 @@ export function getRenoteMenu(props: {
text: channel.name, text: channel.name,
action: () => { action: () => {
const el = props.renoteButton.value; const el = props.renoteButton.value;
if (el) { if (el && defaultStore.state.animation) {
const rect = el.getBoundingClientRect(); const rect = el.getBoundingClientRect();
const x = rect.left + (el.offsetWidth / 2); const x = rect.left + (el.offsetWidth / 2);
const y = rect.top + (el.offsetHeight / 2); const y = rect.top + (el.offsetHeight / 2);

View File

@ -29,45 +29,7 @@ export async function lookup(router?: Router) {
} }
if (query.startsWith('https://')) { if (query.startsWith('https://')) {
const promise = misskeyApi('ap/show', { const res = await apLookup(query);
uri: query,
});
os.promiseDialog(promise, null, (err) => {
let title = i18n.ts.somethingHappened;
let text = err.message + '\n' + err.id;
switch (err.id) {
case '974b799e-1a29-4889-b706-18d4dd93e266':
title = i18n.ts._remoteLookupErrors._federationNotAllowed.title;
text = i18n.ts._remoteLookupErrors._federationNotAllowed.description;
break;
case '1a5eab56-e47b-48c2-8d5e-217b897d70db':
title = i18n.ts._remoteLookupErrors._uriInvalid.title;
text = i18n.ts._remoteLookupErrors._uriInvalid.description;
break;
case '81b539cf-4f57-4b29-bc98-032c33c0792e':
title = i18n.ts._remoteLookupErrors._requestFailed.title;
text = i18n.ts._remoteLookupErrors._requestFailed.description;
break;
case '70193c39-54f3-4813-82f0-70a680f7495b':
title = i18n.ts._remoteLookupErrors._responseInvalid.title;
text = i18n.ts._remoteLookupErrors._responseInvalid.description;
break;
case 'dc94d745-1262-4e63-a17d-fecaa57efc82':
title = i18n.ts._remoteLookupErrors._noSuchObject.title;
text = i18n.ts._remoteLookupErrors._noSuchObject.description;
break;
}
os.alert({
type: 'error',
title,
text,
});
}, i18n.ts.fetchingAsApObject);
const res = await promise;
if (res.type === 'User') { if (res.type === 'User') {
_router.push(`/@${res.object.username}@${res.object.host}`); _router.push(`/@${res.object.username}@${res.object.host}`);
@ -78,3 +40,45 @@ export async function lookup(router?: Router) {
return; return;
} }
} }
export async function apLookup(query: string) {
const promise = misskeyApi('ap/show', {
uri: query,
});
os.promiseDialog(promise, null, (err) => {
let title = i18n.ts.somethingHappened;
let text = err.message + '\n' + err.id;
switch (err.id) {
case '974b799e-1a29-4889-b706-18d4dd93e266':
title = i18n.ts._remoteLookupErrors._federationNotAllowed.title;
text = i18n.ts._remoteLookupErrors._federationNotAllowed.description;
break;
case '1a5eab56-e47b-48c2-8d5e-217b897d70db':
title = i18n.ts._remoteLookupErrors._uriInvalid.title;
text = i18n.ts._remoteLookupErrors._uriInvalid.description;
break;
case '81b539cf-4f57-4b29-bc98-032c33c0792e':
title = i18n.ts._remoteLookupErrors._requestFailed.title;
text = i18n.ts._remoteLookupErrors._requestFailed.description;
break;
case '70193c39-54f3-4813-82f0-70a680f7495b':
title = i18n.ts._remoteLookupErrors._responseInvalid.title;
text = i18n.ts._remoteLookupErrors._responseInvalid.description;
break;
case 'dc94d745-1262-4e63-a17d-fecaa57efc82':
title = i18n.ts._remoteLookupErrors._noSuchObject.title;
text = i18n.ts._remoteLookupErrors._noSuchObject.description;
break;
}
os.alert({
type: 'error',
title,
text,
});
}, i18n.ts.fetchingAsApObject);
return await promise;
}

View File

@ -19,4 +19,5 @@ export interface PostFormProps {
initialVisibleUsers?: Misskey.entities.UserDetailed[]; initialVisibleUsers?: Misskey.entities.UserDetailed[];
initialNote?: Misskey.entities.Note; initialNote?: Misskey.entities.Note;
instant?: boolean; instant?: boolean;
deleteInitialNoteAfterPost?: boolean;
}; };

View File

@ -24,7 +24,7 @@
"devDependencies": { "devDependencies": {
"@types/matter-js": "0.19.8", "@types/matter-js": "0.19.8",
"@types/seedrandom": "3.0.8", "@types/seedrandom": "3.0.8",
"@types/node": "22.13.7", "@types/node": "22.13.8",
"@typescript-eslint/eslint-plugin": "8.25.0", "@typescript-eslint/eslint-plugin": "8.25.0",
"@typescript-eslint/parser": "8.25.0", "@typescript-eslint/parser": "8.25.0",
"nodemon": "3.1.9", "nodemon": "3.1.9",

View File

@ -22,7 +22,7 @@
"lint": "pnpm typecheck && pnpm eslint" "lint": "pnpm typecheck && pnpm eslint"
}, },
"devDependencies": { "devDependencies": {
"@types/node": "22.13.7", "@types/node": "22.13.8",
"@typescript-eslint/eslint-plugin": "8.25.0", "@typescript-eslint/eslint-plugin": "8.25.0",
"@typescript-eslint/parser": "8.25.0", "@typescript-eslint/parser": "8.25.0",
"execa": "9.5.2", "execa": "9.5.2",

File diff suppressed because it is too large Load Diff