Merge branch 'develop' into better-tutorial

This commit is contained in:
かっこかり 2023-10-28 13:19:05 +09:00 committed by GitHub
commit 1761033c9a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 617 additions and 541 deletions

View file

@ -22,19 +22,23 @@
- Feat: プラグイン・テーマを外部サイトから直接インストールできるようになりました - Feat: プラグイン・テーマを外部サイトから直接インストールできるようになりました
- 外部サイトでの実装が必要です。詳細は Misskey Hub をご覧ください - 外部サイトでの実装が必要です。詳細は Misskey Hub をご覧ください
https://misskey-hub.net/docs/advanced/publish-on-your-website.html https://misskey-hub.net/docs/advanced/publish-on-your-website.html
- Feat: AiScript関数`Mk:nyaize()`が追加されました - Enhance: AiScript関数`Mk:nyaize()`が追加されました
- Enhance: データセーバー有効時はアニメーション付きのアバター画像が停止するように
- Enhance: プラグインを削除した際には、使用されていたアクセストークンも同時に削除されるようになりました
- Fix: 投稿フォームでのユーザー変更がプレビューに反映されない問題を修正 - Fix: 投稿フォームでのユーザー変更がプレビューに反映されない問題を修正
- Fix: ユーザーページの ノート > ファイル付き タブにリプライが表示されてしまう - Fix: ユーザーページの ノート > ファイル付き タブにリプライが表示されてしまう
- Fix: 「検索」MFMにおいて一部の検索キーワードが正しく認識されない問題を修正
- Fix: 一部の言語でMisskey Webがクラッシュする問題を修正
### Server ### Server
- Enhance: RedisへのTLのキャッシュをオフにできるように - Enhance: RedisへのTLのキャッシュをオフにできるように
- Enhance: フォローしているチャンネルをフォロー解除した時(またはその逆)、タイムラインに反映される間隔を改善
- Fix: リストTLに自分のフォロワー限定投稿が含まれない問題を修正 - Fix: リストTLに自分のフォロワー限定投稿が含まれない問題を修正
- Fix: ローカルタイムラインに投稿者自身の投稿への返信が含まれない問題を修正 - Fix: ローカルタイムラインに投稿者自身の投稿への返信が含まれない問題を修正
- Fix: 自分のフォローしているユーザーの自分のフォローしていないユーザーの visibility: followers な投稿への返信がストリーミングで流れてくる問題を修正 - Fix: 自分のフォローしているユーザーの自分のフォローしていないユーザーの visibility: followers な投稿への返信がストリーミングで流れてくる問題を修正
- Fix: RedisへのTLキャッシュが有効の場合にHTL/LTL/STLが空になることがある問題を修正 - Fix: RedisへのTLキャッシュが有効の場合にHTL/LTL/STLが空になることがある問題を修正
- Fix: STLでフォローしていないチャンネルが取得される問題を修正 - Fix: STLでフォローしていないチャンネルが取得される問題を修正
- Fix: `hashtags/trend`にてRedisからトレンドの情報が取得できない際にInternal Server Errorになる問題を修正 - Fix: `hashtags/trend`にてRedisからトレンドの情報が取得できない際にInternal Server Errorになる問題を修正
- Fix: フォローしているチャンネルをフォロー解除した時(またはその逆)、タイムラインに反映される間隔を改善
## 2023.10.2 ## 2023.10.2

View file

@ -6,7 +6,7 @@
"type": "git", "type": "git",
"url": "https://github.com/misskey-dev/misskey.git" "url": "https://github.com/misskey-dev/misskey.git"
}, },
"packageManager": "pnpm@8.9.2", "packageManager": "pnpm@8.10.0",
"workspaces": [ "workspaces": [
"packages/frontend", "packages/frontend",
"packages/backend", "packages/backend",
@ -52,10 +52,10 @@
"typescript": "5.2.2" "typescript": "5.2.2"
}, },
"devDependencies": { "devDependencies": {
"@typescript-eslint/eslint-plugin": "6.8.0", "@typescript-eslint/eslint-plugin": "6.9.0",
"@typescript-eslint/parser": "6.8.0", "@typescript-eslint/parser": "6.9.0",
"cross-env": "7.0.3", "cross-env": "7.0.3",
"cypress": "13.3.2", "cypress": "13.3.3",
"eslint": "8.52.0", "eslint": "8.52.0",
"start-server-and-test": "2.0.1" "start-server-and-test": "2.0.1"
}, },

View file

@ -76,10 +76,10 @@
"@nestjs/core": "10.2.7", "@nestjs/core": "10.2.7",
"@nestjs/testing": "10.2.7", "@nestjs/testing": "10.2.7",
"@peertube/http-signature": "1.7.0", "@peertube/http-signature": "1.7.0",
"@simplewebauthn/server": "8.3.2", "@simplewebauthn/server": "8.3.4",
"@sinonjs/fake-timers": "11.2.2", "@sinonjs/fake-timers": "11.2.2",
"@swc/cli": "0.1.62", "@swc/cli": "0.1.62",
"@swc/core": "1.3.94", "@swc/core": "1.3.95",
"accepts": "1.3.8", "accepts": "1.3.8",
"ajv": "8.12.0", "ajv": "8.12.0",
"archiver": "6.0.1", "archiver": "6.0.1",
@ -87,7 +87,7 @@
"bcryptjs": "2.4.3", "bcryptjs": "2.4.3",
"blurhash": "2.0.5", "blurhash": "2.0.5",
"body-parser": "1.20.2", "body-parser": "1.20.2",
"bullmq": "4.12.5", "bullmq": "4.12.6",
"cacheable-lookup": "7.0.0", "cacheable-lookup": "7.0.0",
"cbor": "9.0.1", "cbor": "9.0.1",
"chalk": "5.3.0", "chalk": "5.3.0",
@ -143,7 +143,7 @@
"qrcode": "1.5.3", "qrcode": "1.5.3",
"random-seed": "0.3.0", "random-seed": "0.3.0",
"ratelimiter": "3.4.1", "ratelimiter": "3.4.1",
"re2": "1.20.4", "re2": "1.20.5",
"redis-lock": "0.1.4", "redis-lock": "0.1.4",
"reflect-metadata": "0.1.13", "reflect-metadata": "0.1.13",
"rename": "1.0.4", "rename": "1.0.4",
@ -156,7 +156,7 @@
"strict-event-emitter-types": "2.0.0", "strict-event-emitter-types": "2.0.0",
"stringz": "2.1.0", "stringz": "2.1.0",
"summaly": "github:misskey-dev/summaly", "summaly": "github:misskey-dev/summaly",
"systeminformation": "5.21.13", "systeminformation": "5.21.15",
"tinycolor2": "1.6.0", "tinycolor2": "1.6.0",
"tmp": "0.2.1", "tmp": "0.2.1",
"tsc-alias": "1.8.8", "tsc-alias": "1.8.8",
@ -172,7 +172,7 @@
}, },
"devDependencies": { "devDependencies": {
"@jest/globals": "29.7.0", "@jest/globals": "29.7.0",
"@simplewebauthn/typescript-types": "8.0.0", "@simplewebauthn/typescript-types": "8.3.4",
"@swc/jest": "0.2.29", "@swc/jest": "0.2.29",
"@types/accepts": "1.3.6", "@types/accepts": "1.3.6",
"@types/archiver": "5.3.4", "@types/archiver": "5.3.4",
@ -190,7 +190,7 @@
"@types/jsrsasign": "10.5.11", "@types/jsrsasign": "10.5.11",
"@types/mime-types": "2.1.3", "@types/mime-types": "2.1.3",
"@types/ms": "0.7.33", "@types/ms": "0.7.33",
"@types/node": "20.8.7", "@types/node": "20.8.9",
"@types/node-fetch": "3.0.3", "@types/node-fetch": "3.0.3",
"@types/nodemailer": "6.4.13", "@types/nodemailer": "6.4.13",
"@types/oauth": "0.9.3", "@types/oauth": "0.9.3",
@ -213,12 +213,12 @@
"@types/vary": "1.1.2", "@types/vary": "1.1.2",
"@types/web-push": "3.6.2", "@types/web-push": "3.6.2",
"@types/ws": "8.5.8", "@types/ws": "8.5.8",
"@typescript-eslint/eslint-plugin": "6.8.0", "@typescript-eslint/eslint-plugin": "6.9.0",
"@typescript-eslint/parser": "6.8.0", "@typescript-eslint/parser": "6.9.0",
"aws-sdk-client-mock": "3.0.0", "aws-sdk-client-mock": "3.0.0",
"cross-env": "7.0.3", "cross-env": "7.0.3",
"eslint": "8.52.0", "eslint": "8.52.0",
"eslint-plugin-import": "2.28.1", "eslint-plugin-import": "2.29.0",
"execa": "8.0.1", "execa": "8.0.1",
"jest": "29.7.0", "jest": "29.7.0",
"jest-mock": "29.7.0", "jest-mock": "29.7.0",

View file

@ -18,8 +18,12 @@ export const paramDef = {
type: 'object', type: 'object',
properties: { properties: {
tokenId: { type: 'string', format: 'misskey:id' }, tokenId: { type: 'string', format: 'misskey:id' },
token: { type: 'string' },
}, },
required: ['tokenId'], anyOf: [
{ required: ['tokenId'] },
{ required: ['token'] },
],
} as const; } as const;
@Injectable() @Injectable()
@ -29,6 +33,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
private accessTokensRepository: AccessTokensRepository, private accessTokensRepository: AccessTokensRepository,
) { ) {
super(meta, paramDef, async (ps, me) => { super(meta, paramDef, async (ps, me) => {
if (ps.tokenId) {
const tokenExist = await this.accessTokensRepository.exist({ where: { id: ps.tokenId } }); const tokenExist = await this.accessTokensRepository.exist({ where: { id: ps.tokenId } });
if (tokenExist) { if (tokenExist) {
@ -37,6 +42,16 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
userId: me.id, userId: me.id,
}); });
} }
} else if (ps.token) {
const tokenExist = await this.accessTokensRepository.exist({ where: { token: ps.token } });
if (tokenExist) {
await this.accessTokensRepository.delete({
token: ps.token,
userId: me.id,
});
}
}
}); });
} }
} }

View file

@ -26,10 +26,10 @@
"@tabler/icons-webfont": "2.37.0", "@tabler/icons-webfont": "2.37.0",
"@vitejs/plugin-vue": "4.4.0", "@vitejs/plugin-vue": "4.4.0",
"@vue-macros/reactivity-transform": "0.3.23", "@vue-macros/reactivity-transform": "0.3.23",
"@vue/compiler-sfc": "3.3.6", "@vue/compiler-sfc": "3.3.7",
"astring": "1.8.6", "astring": "1.8.6",
"autosize": "6.0.1", "autosize": "6.0.1",
"broadcast-channel": "5.5.0", "broadcast-channel": "5.5.1",
"browser-image-resizer": "github:misskey-dev/browser-image-resizer#v2.2.1-misskey.3", "browser-image-resizer": "github:misskey-dev/browser-image-resizer#v2.2.1-misskey.3",
"buraha": "0.0.1", "buraha": "0.0.1",
"canvas-confetti": "1.6.1", "canvas-confetti": "1.6.1",
@ -38,7 +38,7 @@
"chartjs-chart-matrix": "2.0.1", "chartjs-chart-matrix": "2.0.1",
"chartjs-plugin-gradient": "0.6.1", "chartjs-plugin-gradient": "0.6.1",
"chartjs-plugin-zoom": "2.0.1", "chartjs-plugin-zoom": "2.0.1",
"chromatic": "7.4.0", "chromatic": "7.5.4",
"compare-versions": "6.1.0", "compare-versions": "6.1.0",
"cropperjs": "2.0.0-beta.4", "cropperjs": "2.0.0-beta.4",
"date-fns": "2.30.0", "date-fns": "2.30.0",
@ -59,10 +59,10 @@
"querystring": "0.2.1", "querystring": "0.2.1",
"rollup": "4.1.4", "rollup": "4.1.4",
"sanitize-html": "2.11.0", "sanitize-html": "2.11.0",
"sass": "1.69.4", "sass": "1.69.5",
"strict-event-emitter-types": "2.0.0", "strict-event-emitter-types": "2.0.0",
"textarea-caret": "3.1.0", "textarea-caret": "3.1.0",
"three": "0.157.0", "three": "0.158.0",
"throttle-debounce": "5.0.0", "throttle-debounce": "5.0.0",
"tinycolor2": "1.6.0", "tinycolor2": "1.6.0",
"tsc-alias": "1.8.8", "tsc-alias": "1.8.8",
@ -73,7 +73,7 @@
"v-code-diff": "1.7.1", "v-code-diff": "1.7.1",
"vanilla-tilt": "1.8.1", "vanilla-tilt": "1.8.1",
"vite": "4.5.0", "vite": "4.5.0",
"vue": "3.3.6", "vue": "3.3.7",
"vue-prism-editor": "2.0.0-alpha.2", "vue-prism-editor": "2.0.0-alpha.2",
"vuedraggable": "next" "vuedraggable": "next"
}, },
@ -101,7 +101,7 @@
"@types/estree": "1.0.3", "@types/estree": "1.0.3",
"@types/matter-js": "0.19.2", "@types/matter-js": "0.19.2",
"@types/micromatch": "4.0.4", "@types/micromatch": "4.0.4",
"@types/node": "20.8.7", "@types/node": "20.8.9",
"@types/punycode": "2.1.1", "@types/punycode": "2.1.1",
"@types/sanitize-html": "2.9.3", "@types/sanitize-html": "2.9.3",
"@types/throttle-debounce": "5.0.1", "@types/throttle-debounce": "5.0.1",
@ -109,21 +109,21 @@
"@types/uuid": "9.0.6", "@types/uuid": "9.0.6",
"@types/websocket": "1.0.8", "@types/websocket": "1.0.8",
"@types/ws": "8.5.8", "@types/ws": "8.5.8",
"@typescript-eslint/eslint-plugin": "6.8.0", "@typescript-eslint/eslint-plugin": "6.9.0",
"@typescript-eslint/parser": "6.8.0", "@typescript-eslint/parser": "6.9.0",
"@vitest/coverage-v8": "0.34.6", "@vitest/coverage-v8": "0.34.6",
"@vue/runtime-core": "3.3.6", "@vue/runtime-core": "3.3.7",
"acorn": "8.10.0", "acorn": "8.11.2",
"cross-env": "7.0.3", "cross-env": "7.0.3",
"cypress": "13.3.2", "cypress": "13.3.3",
"eslint": "8.52.0", "eslint": "8.52.0",
"eslint-plugin-import": "2.28.1", "eslint-plugin-import": "2.29.0",
"eslint-plugin-vue": "9.17.0", "eslint-plugin-vue": "9.18.1",
"fast-glob": "3.3.1", "fast-glob": "3.3.1",
"happy-dom": "10.0.3", "happy-dom": "10.0.3",
"micromatch": "4.0.5", "micromatch": "4.0.5",
"msw": "1.3.2", "msw": "1.3.2",
"msw-storybook-addon": "1.9.0", "msw-storybook-addon": "1.10.0",
"nodemon": "3.0.1", "nodemon": "3.0.1",
"prettier": "3.0.3", "prettier": "3.0.3",
"react": "18.2.0", "react": "18.2.0",
@ -136,6 +136,6 @@
"vitest": "0.34.6", "vitest": "0.34.6",
"vitest-fetch-mock": "0.2.2", "vitest-fetch-mock": "0.2.2",
"vue-eslint-parser": "9.3.2", "vue-eslint-parser": "9.3.2",
"vue-tsc": "1.8.19" "vue-tsc": "1.8.22"
} }
} }

View file

@ -21,7 +21,9 @@ const props = defineProps<{
const query = ref(props.q); const query = ref(props.q);
const search = () => { const search = () => {
window.open(`https://www.google.com/search?q=${query.value}`, '_blank'); const sp = new URLSearchParams();
sp.append('q', query.value);
window.open(`https://www.google.com/search?${sp.toString()}`, '_blank');
}; };
</script> </script>

View file

@ -43,7 +43,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</div> </div>
<div v-if="renoteCollapsed" :class="$style.collapsedRenoteTarget"> <div v-if="renoteCollapsed" :class="$style.collapsedRenoteTarget">
<MkAvatar :class="$style.collapsedRenoteTargetAvatar" :user="appearNote.user" link preview/> <MkAvatar :class="$style.collapsedRenoteTargetAvatar" :user="appearNote.user" link preview/>
<Mfm :text="getNoteSummary(appearNote)" :plain="true" :nowrap="true" :author="appearNote.user" :class="$style.collapsedRenoteTargetText" @click="renoteCollapsed = false"/> <Mfm :text="getNoteSummary(appearNote)" :plain="true" :nowrap="true" :author="appearNote.user" :nyaize="'account'" :class="$style.collapsedRenoteTargetText" @click="renoteCollapsed = false"/>
</div> </div>
<article v-else :class="$style.article" @contextmenu.stop="onContextmenu"> <article v-else :class="$style.article" @contextmenu.stop="onContextmenu">
<div v-if="appearNote.channel" :class="$style.colorBar" :style="{ background: appearNote.channel.color }"></div> <div v-if="appearNote.channel" :class="$style.colorBar" :style="{ background: appearNote.channel.color }"></div>
@ -53,19 +53,19 @@ SPDX-License-Identifier: AGPL-3.0-only
<MkInstanceTicker v-if="showTicker" :instance="appearNote.user.instance"/> <MkInstanceTicker v-if="showTicker" :instance="appearNote.user.instance"/>
<div style="container-type: inline-size;"> <div style="container-type: inline-size;">
<p v-if="appearNote.cw != null" :class="$style.cw"> <p v-if="appearNote.cw != null" :class="$style.cw">
<Mfm v-if="appearNote.cw != ''" style="margin-right: 8px;" :text="appearNote.cw" :author="appearNote.user" :i="$i"/> <Mfm v-if="appearNote.cw != ''" style="margin-right: 8px;" :text="appearNote.cw" :author="appearNote.user" :nyaize="'account'" :i="$i"/>
<MkCwButton v-model="showContent" :note="appearNote" style="margin: 4px 0;"/> <MkCwButton v-model="showContent" :note="appearNote" style="margin: 4px 0;"/>
</p> </p>
<div v-show="appearNote.cw == null || showContent" :class="[{ [$style.contentCollapsed]: collapsed }]"> <div v-show="appearNote.cw == null || showContent" :class="[{ [$style.contentCollapsed]: collapsed }]">
<div :class="$style.text"> <div :class="$style.text">
<span v-if="appearNote.isHidden" style="opacity: 0.5">({{ i18n.ts.private }})</span> <span v-if="appearNote.isHidden" style="opacity: 0.5">({{ i18n.ts.private }})</span>
<MkA v-if="appearNote.replyId" :class="$style.replyIcon" :to="`/notes/${appearNote.replyId}`"><i class="ti ti-arrow-back-up"></i></MkA> <MkA v-if="appearNote.replyId" :class="$style.replyIcon" :to="`/notes/${appearNote.replyId}`"><i class="ti ti-arrow-back-up"></i></MkA>
<Mfm v-if="appearNote.text" :text="appearNote.text" :author="appearNote.user" :i="$i" :emojiUrls="appearNote.emojis"/> <Mfm v-if="appearNote.text" :text="appearNote.text" :author="appearNote.user" :nyaize="'account'" :i="$i" :emojiUrls="appearNote.emojis"/>
<div v-if="translating || translation" :class="$style.translation"> <div v-if="translating || translation" :class="$style.translation">
<MkLoading v-if="translating" mini/> <MkLoading v-if="translating" mini/>
<div v-else> <div v-else>
<b>{{ i18n.t('translatedFrom', { x: translation.sourceLang }) }}: </b> <b>{{ i18n.t('translatedFrom', { x: translation.sourceLang }) }}: </b>
<Mfm :text="translation.text" :author="appearNote.user" :i="$i" :emojiUrls="appearNote.emojis"/> <Mfm :text="translation.text" :author="appearNote.user" :nyaize="'account'" :i="$i" :emojiUrls="appearNote.emojis"/>
</div> </div>
</div> </div>
</div> </div>

View file

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

View file

@ -12,7 +12,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</div> </div>
<div> <div>
<div> <div>
<Mfm :text="text.trim()" :author="user" :i="user"/> <Mfm :text="text.trim()" :author="user" :nyaize="'account'" :i="user"/>
</div> </div>
</div> </div>
</div> </div>

View file

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

View file

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

View file

@ -83,7 +83,7 @@ const bound = $computed(() => props.link
? { to: userPage(props.user), target: props.target } ? { to: userPage(props.user), target: props.target }
: {}); : {});
const url = $computed(() => defaultStore.state.disableShowingAnimatedImages const url = $computed(() => (defaultStore.state.disableShowingAnimatedImages || defaultStore.state.enableDataSaverMode)
? getStaticImageUrl(props.user.avatarUrl) ? getStaticImageUrl(props.user.avatarUrl)
: props.user.avatarUrl); : props.user.avatarUrl);

View file

@ -17,7 +17,7 @@ import MkSparkle from '@/components/MkSparkle.vue';
import MkA from '@/components/global/MkA.vue'; import MkA from '@/components/global/MkA.vue';
import { host } from '@/config.js'; import { host } from '@/config.js';
import { defaultStore } from '@/store.js'; import { defaultStore } from '@/store.js';
import { nyaize } from '@/scripts/nyaize.js'; import { nyaize as doNyaize } from '@/scripts/nyaize.js';
const QUOTE_STYLE = ` const QUOTE_STYLE = `
display: block; display: block;
@ -28,21 +28,27 @@ border-left: solid 3px var(--fg);
opacity: 0.7; opacity: 0.7;
`.split('\n').join(' '); `.split('\n').join(' ');
export default function(props: { type MfmProps = {
text: string; text: string;
plain?: boolean; plain?: boolean;
nowrap?: boolean; nowrap?: boolean;
author?: Misskey.entities.UserLite; author?: Misskey.entities.UserLite;
i?: Misskey.entities.UserLite; i?: Misskey.entities.UserLite | null;
isNote?: boolean; isNote?: boolean;
emojiUrls?: string[]; emojiUrls?: string[];
rootScale?: number; rootScale?: number;
}) { nyaize: boolean | 'account';
const isNote = props.isNote !== undefined ? props.isNote : true; };
// eslint-disable-next-line import/no-default-export
export default function(props: MfmProps) {
const isNote = props.isNote ?? true;
const shouldNyaize = props.nyaize ? props.nyaize === 'account' ? props.author?.isCat : false : false;
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
if (props.text == null || props.text === '') return; if (props.text == null || props.text === '') return;
const ast = (props.plain ? mfm.parseSimple : mfm.parse)(props.text); const rootAst = (props.plain ? mfm.parseSimple : mfm.parse)(props.text);
const validTime = (t: string | null | undefined) => { const validTime = (t: string | null | undefined) => {
if (t == null) return null; if (t == null) return null;
@ -55,13 +61,14 @@ export default function(props: {
* Gen Vue Elements from MFM AST * Gen Vue Elements from MFM AST
* @param ast MFM AST * @param ast MFM AST
* @param scale How times large the text is * @param scale How times large the text is
* @param disableNyaize Whether nyaize is disabled or not
*/ */
const genEl = (ast: mfm.MfmNode[], scale: number, disableNyaize = false) => ast.map((token): VNode | string | (VNode | string)[] => { const genEl = (ast: mfm.MfmNode[], scale: number, disableNyaize = false) => ast.map((token): VNode | string | (VNode | string)[] => {
switch (token.type) { switch (token.type) {
case 'text': { case 'text': {
let text = token.props.text.replace(/(\r\n|\n|\r)/g, '\n'); let text = token.props.text.replace(/(\r\n|\n|\r)/g, '\n');
if (!disableNyaize && props.author?.isCat) { if (!disableNyaize && shouldNyaize) {
text = nyaize(text); text = doNyaize(text);
} }
if (!props.plain) { if (!props.plain) {
@ -377,5 +384,5 @@ export default function(props: {
return h('span', { return h('span', {
// https://codeday.me/jp/qa/20190424/690106.html // https://codeday.me/jp/qa/20190424/690106.html
style: props.nowrap ? 'white-space: pre; word-wrap: normal; overflow: hidden; text-overflow: ellipsis;' : 'white-space: pre-wrap;', style: props.nowrap ? 'white-space: pre; word-wrap: normal; overflow: hidden; text-overflow: ellipsis;' : 'white-space: pre-wrap;',
}, genEl(ast, props.rootScale ?? 1)); }, genEl(rootAst, props.rootScale ?? 1));
} }

View file

@ -77,9 +77,11 @@ import { definePageMetadata } from '@/scripts/page-metadata.js';
const plugins = ref(ColdDeviceStorage.get('plugins')); const plugins = ref(ColdDeviceStorage.get('plugins'));
function uninstall(plugin) { async function uninstall(plugin) {
ColdDeviceStorage.set('plugins', plugins.value.filter(x => x.id !== plugin.id)); ColdDeviceStorage.set('plugins', plugins.value.filter(x => x.id !== plugin.id));
os.success(); await os.apiWithDialog('i/revoke-token', {
token: plugin.token,
});
nextTick(() => { nextTick(() => {
unisonReload(); unisonReload();
}); });

View file

@ -6,7 +6,10 @@
import { lang } from '@/config.js'; import { lang } from '@/config.js';
export const versatileLang = (lang ?? 'ja-JP').replace('ja-KS', 'ja-JP'); export const versatileLang = (lang ?? 'ja-JP').replace('ja-KS', 'ja-JP');
export const dateTimeFormat = new Intl.DateTimeFormat(versatileLang, {
let _dateTimeFormat: Intl.DateTimeFormat;
try {
_dateTimeFormat = new Intl.DateTimeFormat(versatileLang, {
year: 'numeric', year: 'numeric',
month: 'numeric', month: 'numeric',
day: 'numeric', day: 'numeric',
@ -14,4 +17,30 @@ export const dateTimeFormat = new Intl.DateTimeFormat(versatileLang, {
minute: 'numeric', minute: 'numeric',
second: 'numeric', second: 'numeric',
}); });
export const numberFormat = new Intl.NumberFormat(versatileLang); } catch (err) {
console.warn(err);
if (_DEV_) console.log('[Intl] Fallback to en-US');
// Fallback to en-US
_dateTimeFormat = new Intl.DateTimeFormat('en-US', {
year: 'numeric',
month: 'numeric',
day: 'numeric',
hour: 'numeric',
minute: 'numeric',
second: 'numeric',
});
}
export const dateTimeFormat = _dateTimeFormat;
let _numberFormat: Intl.NumberFormat;
try {
_numberFormat = new Intl.NumberFormat(versatileLang);
} catch (err) {
console.warn(err);
if (_DEV_) console.log('[Intl] Fallback to en-US');
// Fallback to en-US
_numberFormat = new Intl.NumberFormat('en-US');
}
export const numberFormat = _numberFormat;

View file

@ -23,9 +23,9 @@
"@microsoft/api-extractor": "7.38.0", "@microsoft/api-extractor": "7.38.0",
"@swc/jest": "0.2.29", "@swc/jest": "0.2.29",
"@types/jest": "29.5.6", "@types/jest": "29.5.6",
"@types/node": "20.8.7", "@types/node": "20.8.9",
"@typescript-eslint/eslint-plugin": "6.8.0", "@typescript-eslint/eslint-plugin": "6.9.0",
"@typescript-eslint/parser": "6.8.0", "@typescript-eslint/parser": "6.9.0",
"eslint": "8.52.0", "eslint": "8.52.0",
"jest": "29.7.0", "jest": "29.7.0",
"jest-fetch-mock": "3.0.3", "jest-fetch-mock": "3.0.3",
@ -39,7 +39,7 @@
], ],
"dependencies": { "dependencies": {
"@swc/cli": "0.1.62", "@swc/cli": "0.1.62",
"@swc/core": "1.3.94", "@swc/core": "1.3.95",
"eventemitter3": "5.0.1", "eventemitter3": "5.0.1",
"reconnecting-websocket": "4.4.0" "reconnecting-websocket": "4.4.0"
} }

View file

@ -14,10 +14,10 @@
"misskey-js": "workspace:*" "misskey-js": "workspace:*"
}, },
"devDependencies": { "devDependencies": {
"@typescript-eslint/parser": "6.8.0", "@typescript-eslint/parser": "6.9.0",
"@typescript/lib-webworker": "npm:@types/serviceworker@0.0.67", "@typescript/lib-webworker": "npm:@types/serviceworker@0.0.67",
"eslint": "8.52.0", "eslint": "8.52.0",
"eslint-plugin-import": "2.28.1", "eslint-plugin-import": "2.29.0",
"typescript": "5.2.2" "typescript": "5.2.2"
}, },
"type": "module" "type": "module"

File diff suppressed because it is too large Load diff