diff --git a/CHANGELOG.md b/CHANGELOG.md index 656f69643c..0a5e566263 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,9 @@ You should also include the user name that made the change. - You may have to `yarn run clean-all`, `sudo corepack enable` and `yarn set version berry` before running `yarn install` if you're still on yarn classic - 新たに動的なPagesを作ることはできなくなりました - 代わりに今後AiScriptを用いてより柔軟に動的なコンテンツを作成できるMisskey Play機能の実装を予定しています。 +- AiScriptが0.12.0にアップデートされました + - 0.12.0の変更点についてはこちら https://github.com/syuilo/aiscript/blob/master/CHANGELOG.md#0120 + - 0.12.0未満のプラグインは読み込むことはできません - iOS15以下のデバイスはサポートされなくなりました - API: カスタム絵文字エンティティに`url`プロパティが含まれなくなりました - 絵文字画像を表示するには、`<instance host>/emoji/<emoji name>.webp`にリクエストすると画像が返ります。 @@ -27,6 +30,7 @@ You should also include the user name that made the change. - remote: `https://p1.a9z.dev/emoji/syuilo_birth_present@mk.f72u.net.webp` - API: `user`および`note`エンティティに`emojis`プロパティが含まれなくなりました - API: `user`エンティティに`avatarColor`および`bannerColor`プロパティが含まれなくなりました +- API: `instance`エンティティに`latestStatus`、`lastCommunicatedAt`、`latestRequestSentAt`プロパティが含まれなくなりました ### Improvements - Push notification of Antenna note @tamaina @@ -41,6 +45,7 @@ You should also include the user name that made the change. - Server: delete outdated notifications regularly to improve db performance @syuilo - Server: delete outdated hard-mutes regularly to improve db performance @syuilo - Server: delete outdated notes of antenna regularly to improve db performance @syuilo +- Server: improve activitypub deliver performance @syuilo - Client: use tabler-icons instead of fontawesome to better design @syuilo - Client: Add new gabber kick sounds (thanks for noizenecio) - Client: Add link to user RSS feed in profile menu @ssmucny diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index eb30eed53a..d6a5518196 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -167,7 +167,6 @@ annotation: "注釈" federation: "連合" instances: "インスタンス" registeredAt: "初観測" -latestRequestSentAt: "直近のリクエスト送信" latestRequestReceivedAt: "直近のリクエスト受信" latestStatus: "直近のステータス" storageUsage: "ストレージ使用量" diff --git a/package.json b/package.json index 0ae0bb2a32..1e3bf82a7b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "misskey", - "version": "13.0.0-beta.17", + "version": "13.0.0-beta.20", "codename": "indigo", "repository": { "type": "git", diff --git a/packages/backend/migration/1672703171386-remove-latestRequestSentAt.js b/packages/backend/migration/1672703171386-remove-latestRequestSentAt.js new file mode 100644 index 0000000000..c9b28dd7e1 --- /dev/null +++ b/packages/backend/migration/1672703171386-remove-latestRequestSentAt.js @@ -0,0 +1,11 @@ +export class removeLatestRequestSentAt1672703171386 { + name = 'removeLatestRequestSentAt1672703171386' + + async up(queryRunner) { + await queryRunner.query(`ALTER TABLE "instance" DROP COLUMN "latestRequestSentAt"`); + } + + async down(queryRunner) { + await queryRunner.query(`ALTER TABLE "instance" ADD "latestRequestSentAt" TIMESTAMP WITH TIME ZONE`); + } +} diff --git a/packages/backend/migration/1672704017999-remove-lastCommunicatedAt.js b/packages/backend/migration/1672704017999-remove-lastCommunicatedAt.js new file mode 100644 index 0000000000..38a6769851 --- /dev/null +++ b/packages/backend/migration/1672704017999-remove-lastCommunicatedAt.js @@ -0,0 +1,11 @@ +export class removeLastCommunicatedAt1672704017999 { + name = 'removeLastCommunicatedAt1672704017999' + + async up(queryRunner) { + await queryRunner.query(`ALTER TABLE "instance" DROP COLUMN "lastCommunicatedAt"`); + } + + async down(queryRunner) { + await queryRunner.query(`ALTER TABLE "instance" ADD "lastCommunicatedAt" TIMESTAMP WITH TIME ZONE NOT NULL`); + } +} diff --git a/packages/backend/migration/1672704136584-remove-latestStatus.js b/packages/backend/migration/1672704136584-remove-latestStatus.js new file mode 100644 index 0000000000..937c2fe8fd --- /dev/null +++ b/packages/backend/migration/1672704136584-remove-latestStatus.js @@ -0,0 +1,11 @@ +export class removeLatestStatus1672704136584 { + name = 'removeLatestStatus1672704136584' + + async up(queryRunner) { + await queryRunner.query(`ALTER TABLE "instance" DROP COLUMN "latestStatus"`); + } + + async down(queryRunner) { + await queryRunner.query(`ALTER TABLE "instance" ADD "latestStatus" integer`); + } +} diff --git a/packages/backend/package.json b/packages/backend/package.json index b25f03110f..d139c1db86 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -37,7 +37,6 @@ "@nestjs/testing": "9.2.1", "@peertube/http-signature": "1.7.0", "@sinonjs/fake-timers": "10.0.2", - "@syuilo/aiscript": "0.11.1", "accepts": "^1.3.8", "ajv": "8.11.2", "archiver": "5.3.1", diff --git a/packages/backend/src/core/FederatedInstanceService.ts b/packages/backend/src/core/FederatedInstanceService.ts index 97745a1168..d517117da6 100644 --- a/packages/backend/src/core/FederatedInstanceService.ts +++ b/packages/backend/src/core/FederatedInstanceService.ts @@ -22,7 +22,7 @@ export class FederatedInstanceService { } @bindThis - public async registerOrFetchInstanceDoc(host: string): Promise<Instance> { + public async fetch(host: string): Promise<Instance> { host = this.utilityService.toPuny(host); const cached = this.cache.get(host); @@ -35,7 +35,6 @@ export class FederatedInstanceService { id: this.idService.genId(), host, caughtAt: new Date(), - lastCommunicatedAt: new Date(), }).then(x => this.instancesRepository.findOneByOrFail(x.identifiers[0])); this.cache.set(host, i); @@ -45,4 +44,17 @@ export class FederatedInstanceService { return index; } } + + @bindThis + public async updateCachePartial(host: string, data: Partial<Instance>): Promise<void> { + host = this.utilityService.toPuny(host); + + const cached = this.cache.get(host); + if (cached == null) return; + + this.cache.set(host, { + ...cached, + ...data, + }); + } } diff --git a/packages/backend/src/core/NoteCreateService.ts b/packages/backend/src/core/NoteCreateService.ts index cc6c213446..6038840406 100644 --- a/packages/backend/src/core/NoteCreateService.ts +++ b/packages/backend/src/core/NoteCreateService.ts @@ -428,7 +428,7 @@ export class NoteCreateService { // Register host if (this.userEntityService.isRemoteUser(user)) { - this.federatedInstanceService.registerOrFetchInstanceDoc(user.host).then(i => { + this.federatedInstanceService.fetch(user.host).then(i => { this.instancesRepository.increment({ id: i.id }, 'notesCount', 1); this.instanceChart.updateNote(i.host, note, true); }); diff --git a/packages/backend/src/core/NoteDeleteService.ts b/packages/backend/src/core/NoteDeleteService.ts index 1313fcbd3d..b1f16b6e8a 100644 --- a/packages/backend/src/core/NoteDeleteService.ts +++ b/packages/backend/src/core/NoteDeleteService.ts @@ -100,7 +100,7 @@ export class NoteDeleteService { this.perUserNotesChart.update(user, note, false); if (this.userEntityService.isRemoteUser(user)) { - this.federatedInstanceService.registerOrFetchInstanceDoc(user.host).then(i => { + this.federatedInstanceService.fetch(user.host).then(i => { this.instancesRepository.decrement({ id: i.id }, 'notesCount', 1); this.instanceChart.updateNote(i.host, note, false); }); diff --git a/packages/backend/src/core/UserFollowingService.ts b/packages/backend/src/core/UserFollowingService.ts index 074aae86c8..52834c375e 100644 --- a/packages/backend/src/core/UserFollowingService.ts +++ b/packages/backend/src/core/UserFollowingService.ts @@ -205,12 +205,12 @@ export class UserFollowingService { //#region Update instance stats if (this.userEntityService.isRemoteUser(follower) && this.userEntityService.isLocalUser(followee)) { - this.federatedInstanceService.registerOrFetchInstanceDoc(follower.host).then(i => { + this.federatedInstanceService.fetch(follower.host).then(i => { this.instancesRepository.increment({ id: i.id }, 'followingCount', 1); this.instanceChart.updateFollowing(i.host, true); }); } else if (this.userEntityService.isLocalUser(follower) && this.userEntityService.isRemoteUser(followee)) { - this.federatedInstanceService.registerOrFetchInstanceDoc(followee.host).then(i => { + this.federatedInstanceService.fetch(followee.host).then(i => { this.instancesRepository.increment({ id: i.id }, 'followersCount', 1); this.instanceChart.updateFollowers(i.host, true); }); @@ -323,12 +323,12 @@ export class UserFollowingService { //#region Update instance stats if (this.userEntityService.isRemoteUser(follower) && this.userEntityService.isLocalUser(followee)) { - this.federatedInstanceService.registerOrFetchInstanceDoc(follower.host).then(i => { + this.federatedInstanceService.fetch(follower.host).then(i => { this.instancesRepository.decrement({ id: i.id }, 'followingCount', 1); this.instanceChart.updateFollowing(i.host, false); }); } else if (this.userEntityService.isLocalUser(follower) && this.userEntityService.isRemoteUser(followee)) { - this.federatedInstanceService.registerOrFetchInstanceDoc(followee.host).then(i => { + this.federatedInstanceService.fetch(followee.host).then(i => { this.instancesRepository.decrement({ id: i.id }, 'followersCount', 1); this.instanceChart.updateFollowers(i.host, false); }); diff --git a/packages/backend/src/core/activitypub/models/ApPersonService.ts b/packages/backend/src/core/activitypub/models/ApPersonService.ts index d5faf37df2..e08f33c906 100644 --- a/packages/backend/src/core/activitypub/models/ApPersonService.ts +++ b/packages/backend/src/core/activitypub/models/ApPersonService.ts @@ -348,7 +348,7 @@ export class ApPersonService implements OnModuleInit { } // Register host - this.federatedInstanceService.registerOrFetchInstanceDoc(host).then(i => { + this.federatedInstanceService.fetch(host).then(i => { this.instancesRepository.increment({ id: i.id }, 'usersCount', 1); this.instanceChart.newUser(i.host); this.fetchInstanceMetadataService.fetchInstanceMetadata(i); diff --git a/packages/backend/src/core/chart/charts/federation.ts b/packages/backend/src/core/chart/charts/federation.ts index d9234e8028..b8012809f7 100644 --- a/packages/backend/src/core/chart/charts/federation.ts +++ b/packages/backend/src/core/chart/charts/federation.ts @@ -86,7 +86,7 @@ export default class FederationChart extends Chart<typeof schema> { .where(`instance.host IN (${ subInstancesQuery.getQuery() })`) .andWhere(meta.blockedHosts.length === 0 ? '1=1' : 'instance.host NOT IN (:...blocked)', { blocked: meta.blockedHosts }) .andWhere('instance.isSuspended = false') - .andWhere('instance.lastCommunicatedAt > :gt', { gt: new Date(Date.now() - (1000 * 60 * 60 * 24 * 30)) }) + .andWhere('instance.isNotResponding = false') .getRawOne() .then(x => parseInt(x.count, 10)), this.instancesRepository.createQueryBuilder('instance') @@ -94,7 +94,7 @@ export default class FederationChart extends Chart<typeof schema> { .where(`instance.host IN (${ pubInstancesQuery.getQuery() })`) .andWhere(meta.blockedHosts.length === 0 ? '1=1' : 'instance.host NOT IN (:...blocked)', { blocked: meta.blockedHosts }) .andWhere('instance.isSuspended = false') - .andWhere('instance.lastCommunicatedAt > :gt', { gt: new Date(Date.now() - (1000 * 60 * 60 * 24 * 30)) }) + .andWhere('instance.isNotResponding = false') .getRawOne() .then(x => parseInt(x.count, 10)), ]); diff --git a/packages/backend/src/core/entities/InstanceEntityService.ts b/packages/backend/src/core/entities/InstanceEntityService.ts index 5a7ceb89a3..81d02bb331 100644 --- a/packages/backend/src/core/entities/InstanceEntityService.ts +++ b/packages/backend/src/core/entities/InstanceEntityService.ts @@ -7,8 +7,8 @@ import type { } from '@/models/entities/Blocking.js'; import type { User } from '@/models/entities/User.js'; import type { Instance } from '@/models/entities/Instance.js'; import { MetaService } from '@/core/MetaService.js'; -import { UserEntityService } from './UserEntityService.js'; import { bindThis } from '@/decorators.js'; +import { UserEntityService } from './UserEntityService.js'; @Injectable() export class InstanceEntityService { @@ -33,8 +33,6 @@ export class InstanceEntityService { notesCount: instance.notesCount, followingCount: instance.followingCount, followersCount: instance.followersCount, - latestRequestSentAt: instance.latestRequestSentAt ? instance.latestRequestSentAt.toISOString() : null, - lastCommunicatedAt: instance.lastCommunicatedAt.toISOString(), isNotResponding: instance.isNotResponding, isSuspended: instance.isSuspended, isBlocked: meta.blockedHosts.includes(instance.host), diff --git a/packages/backend/src/models/entities/Instance.ts b/packages/backend/src/models/entities/Instance.ts index 7ea9234384..8092f67c86 100644 --- a/packages/backend/src/models/entities/Instance.ts +++ b/packages/backend/src/models/entities/Instance.ts @@ -59,22 +59,6 @@ export class Instance { }) public followersCount: number; - /** - * 直近のリクエスト送信日時 - */ - @Column('timestamp with time zone', { - nullable: true, - }) - public latestRequestSentAt: Date | null; - - /** - * 直近のリクエスト送信時のHTTPステータスコード - */ - @Column('integer', { - nullable: true, - }) - public latestStatus: number | null; - /** * 直近のリクエスト受信日時 */ @@ -83,12 +67,6 @@ export class Instance { }) public latestRequestReceivedAt: Date | null; - /** - * このインスタンスと最後にやり取りした日時 - */ - @Column('timestamp with time zone') - public lastCommunicatedAt: Date; - /** * このインスタンスと不通かどうか */ diff --git a/packages/backend/src/models/schema/federation-instance.ts b/packages/backend/src/models/schema/federation-instance.ts index c57b3fec19..f3f93f3097 100644 --- a/packages/backend/src/models/schema/federation-instance.ts +++ b/packages/backend/src/models/schema/federation-instance.ts @@ -32,16 +32,6 @@ export const packedFederationInstanceSchema = { type: 'number', optional: false, nullable: false, }, - latestRequestSentAt: { - type: 'string', - optional: false, nullable: true, - format: 'date-time', - }, - lastCommunicatedAt: { - type: 'string', - optional: false, nullable: false, - format: 'date-time', - }, isNotResponding: { type: 'boolean', optional: false, nullable: false, diff --git a/packages/backend/src/queue/processors/DeliverProcessorService.ts b/packages/backend/src/queue/processors/DeliverProcessorService.ts index 58969d550e..c5e4a66517 100644 --- a/packages/backend/src/queue/processors/DeliverProcessorService.ts +++ b/packages/backend/src/queue/processors/DeliverProcessorService.ts @@ -15,10 +15,10 @@ import ApRequestChart from '@/core/chart/charts/ap-request.js'; import FederationChart from '@/core/chart/charts/federation.js'; import { StatusError } from '@/misc/status-error.js'; import { UtilityService } from '@/core/UtilityService.js'; +import { bindThis } from '@/decorators.js'; import { QueueLoggerService } from '../QueueLoggerService.js'; import type Bull from 'bull'; import type { DeliverJobData } from '../types.js'; -import { bindThis } from '@/decorators.js'; @Injectable() export class DeliverProcessorService { @@ -48,7 +48,6 @@ export class DeliverProcessorService { ) { this.logger = this.queueLoggerService.logger.createSubLogger('deliver'); this.suspendedHostsCache = new Cache<Instance[]>(1000 * 60 * 60); - this.latest = null; } @bindThis @@ -76,20 +75,18 @@ export class DeliverProcessorService { } try { - if (this.latest !== (this.latest = JSON.stringify(job.data.content, null, 2))) { - this.logger.debug(`delivering ${this.latest}`); - } - await this.apRequestService.signedPost(job.data.user, job.data.to, job.data.content); // Update stats - this.federatedInstanceService.registerOrFetchInstanceDoc(host).then(i => { - this.instancesRepository.update(i.id, { - latestRequestSentAt: new Date(), - latestStatus: 200, - lastCommunicatedAt: new Date(), - isNotResponding: false, - }); + this.federatedInstanceService.fetch(host).then(i => { + if (i.isNotResponding) { + this.instancesRepository.update(i.id, { + isNotResponding: false, + }); + this.federatedInstanceService.updateCachePartial(host, { + isNotResponding: false, + }); + } this.fetchInstanceMetadataService.fetchInstanceMetadata(i); @@ -100,13 +97,16 @@ export class DeliverProcessorService { return 'Success'; } catch (res) { - // Update stats - this.federatedInstanceService.registerOrFetchInstanceDoc(host).then(i => { - this.instancesRepository.update(i.id, { - latestRequestSentAt: new Date(), - latestStatus: res instanceof StatusError ? res.statusCode : null, - isNotResponding: true, - }); + // Update stats + this.federatedInstanceService.fetch(host).then(i => { + if (!i.isNotResponding) { + this.instancesRepository.update(i.id, { + isNotResponding: true, + }); + this.federatedInstanceService.updateCachePartial(host, { + isNotResponding: true, + }); + } this.instanceChart.requestSent(i.host, false); this.apRequestChart.deliverFail(); @@ -114,17 +114,17 @@ export class DeliverProcessorService { }); if (res instanceof StatusError) { - // 4xx + // 4xx if (res.isClientError) { - // HTTPステータスコード4xxはクライアントエラーであり、それはつまり - // 何回再送しても成功することはないということなのでエラーにはしないでおく + // HTTPステータスコード4xxはクライアントエラーであり、それはつまり + // 何回再送しても成功することはないということなのでエラーにはしないでおく return `${res.statusCode} ${res.statusMessage}`; } // 5xx etc. throw `${res.statusCode} ${res.statusMessage}`; } else { - // DNS error, socket error, timeout ... + // DNS error, socket error, timeout ... throw res; } } diff --git a/packages/backend/src/queue/processors/InboxProcessorService.ts b/packages/backend/src/queue/processors/InboxProcessorService.ts index c032122caf..d033637849 100644 --- a/packages/backend/src/queue/processors/InboxProcessorService.ts +++ b/packages/backend/src/queue/processors/InboxProcessorService.ts @@ -176,10 +176,12 @@ export class InboxProcessorService { } // Update stats - this.federatedInstanceService.registerOrFetchInstanceDoc(authUser.user.host).then(i => { + this.federatedInstanceService.fetch(authUser.user.host).then(i => { this.instancesRepository.update(i.id, { latestRequestReceivedAt: new Date(), - lastCommunicatedAt: new Date(), + isNotResponding: false, + }); + this.federatedInstanceService.updateCachePartial(host, { isNotResponding: false, }); diff --git a/packages/backend/src/server/api/endpoints/federation/instances.ts b/packages/backend/src/server/api/endpoints/federation/instances.ts index 81276a7ab0..180887285a 100644 --- a/packages/backend/src/server/api/endpoints/federation/instances.ts +++ b/packages/backend/src/server/api/endpoints/federation/instances.ts @@ -64,8 +64,8 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { case '-followers': query.orderBy('instance.followersCount', 'ASC'); break; case '+caughtAt': query.orderBy('instance.caughtAt', 'DESC'); break; case '-caughtAt': query.orderBy('instance.caughtAt', 'ASC'); break; - case '+lastCommunicatedAt': query.orderBy('instance.lastCommunicatedAt', 'DESC'); break; - case '-lastCommunicatedAt': query.orderBy('instance.lastCommunicatedAt', 'ASC'); break; + case '+latestRequestReceivedAt': query.orderBy('instance.latestRequestReceivedAt', 'DESC'); break; + case '-latestRequestReceivedAt': query.orderBy('instance.latestRequestReceivedAt', 'ASC'); break; default: query.orderBy('instance.id', 'DESC'); break; } diff --git a/packages/backend/src/server/api/endpoints/users/show.ts b/packages/backend/src/server/api/endpoints/users/show.ts index 48a6bbf9bc..fcdaeae1c9 100644 --- a/packages/backend/src/server/api/endpoints/users/show.ts +++ b/packages/backend/src/server/api/endpoints/users/show.ts @@ -139,10 +139,12 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { throw new ApiError(meta.errors.noSuchUser); } - if (me == null && ip != null) { - this.perUserPvChart.commitByVisitor(user, ip); - } else if (me && me.id !== user.id) { - this.perUserPvChart.commitByUser(user, me.id); + if (user.host == null) { + if (me == null && ip != null) { + this.perUserPvChart.commitByVisitor(user, ip); + } else if (me && me.id !== user.id) { + this.perUserPvChart.commitByUser(user, me.id); + } } return await this.userEntityService.pack(user, me, { diff --git a/packages/frontend/package.json b/packages/frontend/package.json index e380165681..2506e8e9d3 100644 --- a/packages/frontend/package.json +++ b/packages/frontend/package.json @@ -11,7 +11,7 @@ "@rollup/plugin-alias": "4.0.2", "@rollup/plugin-json": "6.0.0", "@rollup/pluginutils": "5.0.2", - "@syuilo/aiscript": "0.11.1", + "@syuilo/aiscript": "0.12.0", "@tabler/icons": "^1.118.0", "@vitejs/plugin-vue": "4.0.0", "@vue/compiler-sfc": "3.2.45", diff --git a/packages/frontend/src/components/MkAbuseReportWindow.vue b/packages/frontend/src/components/MkAbuseReportWindow.vue index 039f77c859..ab90ed357a 100644 --- a/packages/frontend/src/components/MkAbuseReportWindow.vue +++ b/packages/frontend/src/components/MkAbuseReportWindow.vue @@ -23,7 +23,7 @@ </template> <script setup lang="ts"> -import { ref } from 'vue'; +import { ref, shallowRef } from 'vue'; import * as Misskey from 'misskey-js'; import XWindow from '@/components/MkWindow.vue'; import MkTextarea from '@/components/form/textarea.vue'; @@ -40,7 +40,7 @@ const emit = defineEmits<{ (ev: 'closed'): void; }>(); -const uiWindow = ref<InstanceType<typeof XWindow>>(); +const uiWindow = shallowRef<InstanceType<typeof XWindow>>(); const comment = ref(props.initialComment || ''); function send() { diff --git a/packages/frontend/src/components/MkAutocomplete.vue b/packages/frontend/src/components/MkAutocomplete.vue index a2b020b900..08e2c29de2 100644 --- a/packages/frontend/src/components/MkAutocomplete.vue +++ b/packages/frontend/src/components/MkAutocomplete.vue @@ -16,9 +16,9 @@ </li> </ol> <ol v-else-if="emojis.length > 0" ref="suggests" class="emojis"> - <li v-for="emoji in emojis" tabindex="-1" :key="emoji.emoji" @click="complete(type, emoji.emoji)" @keydown="onKeydown"> + <li v-for="emoji in emojis" :key="emoji.emoji" tabindex="-1" @click="complete(type, emoji.emoji)" @keydown="onKeydown"> <div class="emoji"> - <MkEmoji :emoji="emoji.emoji" /> + <MkEmoji :emoji="emoji.emoji"/> </div> <!-- eslint-disable-next-line vue/no-v-html --> <span v-if="q" class="name" v-html="sanitizeHtml(emoji.name.replace(q, `<b>${q}</b>`))"></span> @@ -35,7 +35,8 @@ </template> <script lang="ts"> -import { markRaw, ref, onUpdated, onMounted, onBeforeUnmount, nextTick, watch } from 'vue'; +import { markRaw, ref, shallowRef, onUpdated, onMounted, onBeforeUnmount, nextTick, watch } from 'vue'; +import sanitizeHtml from 'sanitize-html'; import contains from '@/scripts/contains'; import { char2twemojiFilePath, char2fluentEmojiFilePath } from '@/scripts/emoji-base'; import { acct } from '@/filters/user'; @@ -45,7 +46,6 @@ import { defaultStore } from '@/store'; import { emojilist } from '@/scripts/emojilist'; import { instance } from '@/instance'; import { i18n } from '@/i18n'; -import sanitizeHtml from 'sanitize-html'; type EmojiDef = { emoji: string; @@ -136,7 +136,7 @@ const emit = defineEmits<{ }>(); const suggests = ref<Element>(); -const rootEl = ref<HTMLDivElement>(); +const rootEl = shallowRef<HTMLDivElement>(); const fetching = ref(true); const users = ref<any[]>([]); diff --git a/packages/frontend/src/components/MkButton.vue b/packages/frontend/src/components/MkButton.vue index 2b1b66da29..daf47e12d4 100644 --- a/packages/frontend/src/components/MkButton.vue +++ b/packages/frontend/src/components/MkButton.vue @@ -47,8 +47,8 @@ const emit = defineEmits<{ (ev: 'click', payload: MouseEvent): void; }>(); -let el = $ref<HTMLElement | null>(null); -let ripples = $ref<HTMLElement | null>(null); +let el = $shallowRef<HTMLElement | null>(null); +let ripples = $shallowRef<HTMLElement | null>(null); onMounted(() => { if (props.autofocus) { diff --git a/packages/frontend/src/components/MkCaptcha.vue b/packages/frontend/src/components/MkCaptcha.vue index 6d218389fc..8db2e54e88 100644 --- a/packages/frontend/src/components/MkCaptcha.vue +++ b/packages/frontend/src/components/MkCaptcha.vue @@ -6,7 +6,7 @@ </template> <script lang="ts" setup> -import { ref, computed, onMounted, onBeforeUnmount, watch } from 'vue'; +import { ref, shallowRef, computed, onMounted, onBeforeUnmount, watch } from 'vue'; import { defaultStore } from '@/store'; import { i18n } from '@/i18n'; @@ -42,7 +42,7 @@ const emit = defineEmits<{ const available = ref(false); -const captchaEl = ref<HTMLDivElement | undefined>(); +const captchaEl = shallowRef<HTMLDivElement | undefined>(); const variable = computed(() => { switch (props.provider) { @@ -62,7 +62,7 @@ const src = computed(() => { } }); -const scriptId = computed(() => `script-${props.provider}`) +const scriptId = computed(() => `script-${props.provider}`); const captcha = computed<Captcha>(() => window[variable.value] || {} as unknown as Captcha); diff --git a/packages/frontend/src/components/MkChart.vue b/packages/frontend/src/components/MkChart.vue index d602849651..ea28cfa794 100644 --- a/packages/frontend/src/components/MkChart.vue +++ b/packages/frontend/src/components/MkChart.vue @@ -1,6 +1,7 @@ <template> <div class="cbbedffa"> <canvas ref="chartEl"></canvas> + <MkChartLegend ref="legendEl" style="margin-top: 8px;"/> <div v-if="fetching" class="fetching"> <MkLoading/> </div> @@ -13,9 +14,8 @@ id-denylist violation when setting it. This is causing about 60+ lint issues. As this is part of Chart.js's API it makes sense to disable the check here. */ -import { onMounted, ref, watch, PropType, onUnmounted } from 'vue'; +import { onMounted, ref, shallowRef, watch, PropType, onUnmounted } from 'vue'; import { Chart } from 'chart.js'; -import 'chartjs-adapter-date-fns'; import { enUS } from 'date-fns/locale'; import gradient from 'chartjs-plugin-gradient'; import * as os from '@/os'; @@ -25,6 +25,8 @@ import { chartVLine } from '@/scripts/chart-vline'; import { alpha } from '@/scripts/color'; import date from '@/filters/date'; import { initChart } from '@/scripts/init-chart'; +import { chartLegend } from '@/scripts/chart-legend'; +import MkChartLegend from '@/components/MkChartLegend.vue'; initChart(); @@ -68,6 +70,8 @@ const props = defineProps({ }, }); +let legendEl = $shallowRef<InstanceType<typeof MkChartLegend>>(); + const sum = (...arr) => arr.reduce((r, a) => r.map((b, i) => a[i] + b)); const negate = arr => arr.map(x => -x); @@ -102,7 +106,7 @@ let chartData: { }[]; } = null; -const chartEl = ref<HTMLCanvasElement>(null); +const chartEl = shallowRef<HTMLCanvasElement>(null); const fetching = ref(true); const getDate = (ago: number) => { @@ -221,11 +225,7 @@ const render = () => { }, plugins: { legend: { - display: props.detailed, - position: 'bottom', - labels: { - boxWidth: 16, - }, + display: false, }, tooltip: { enabled: false, @@ -265,7 +265,7 @@ const render = () => { gradient, }, }, - plugins: [chartVLine(vLineColor)], + plugins: [chartVLine(vLineColor), ...(props.detailed ? [chartLegend(legendEl)] : [])], }); }; diff --git a/packages/frontend/src/components/MkChartLegend.vue b/packages/frontend/src/components/MkChartLegend.vue new file mode 100644 index 0000000000..f33f753723 --- /dev/null +++ b/packages/frontend/src/components/MkChartLegend.vue @@ -0,0 +1,75 @@ +<template> +<div :class="$style.root"> + <button v-for="item in items" class="_button item" :class="{ disabled: item.hidden }" @click="onClick(item)"> + <span class="box" :style="{ background: chart.config.type === 'line' ? item.strokeStyle?.toString() : item.fillStyle?.toString() }"></span> + {{ item.text }} + </button> +</div> +</template> + +<script lang="ts" setup> +import { onMounted, ref, shallowRef, watch, PropType, onUnmounted } from 'vue'; +import { Chart, LegendItem } from 'chart.js'; + +const props = defineProps({ +}); + +let chart = $shallowRef<Chart>(); +let items = $shallowRef<LegendItem[]>([]); + +function update(_chart: Chart, _items: LegendItem[]) { + chart = _chart, + items = _items; +} + +function onClick(item: LegendItem) { + if (chart == null) return; + const { type } = chart.config; + if (type === 'pie' || type === 'doughnut') { + // Pie and doughnut charts only have a single dataset and visibility is per item + chart.toggleDataVisibility(item.index); + } else { + chart.setDatasetVisibility(item.datasetIndex, !chart.isDatasetVisible(item.datasetIndex)); + } + chart.update(); +} + +defineExpose({ + update, +}); +</script> + +<style lang="scss" module> +.root { + display: flex; + flex-wrap: wrap; + justify-content: center; + gap: 8px; + + &:global { + > .item { + font-size: 85%; + padding: 4px 12px 4px 8px; + border: solid 1px var(--divider); + border-radius: 999px; + + &:hover { + border-color: var(--inputBorderHover); + } + + &.disabled { + text-decoration: line-through; + opacity: 0.6; + } + + > .box { + display: inline-block; + width: 12px; + height: 12px; + border-radius: 100%; + vertical-align: -10%; + } + } + } +} +</style> diff --git a/packages/frontend/src/components/MkContextMenu.vue b/packages/frontend/src/components/MkContextMenu.vue index 6470f8b972..9d9abc5d09 100644 --- a/packages/frontend/src/components/MkContextMenu.vue +++ b/packages/frontend/src/components/MkContextMenu.vue @@ -22,7 +22,7 @@ const emit = defineEmits<{ (ev: 'closed'): void; }>(); -let rootEl = $ref<HTMLDivElement>(); +let rootEl = $shallowRef<HTMLDivElement>(); let zIndex = $ref<number>(os.claimZIndex('high')); diff --git a/packages/frontend/src/components/MkCropperDialog.vue b/packages/frontend/src/components/MkCropperDialog.vue index ae18160dea..f00fef12f1 100644 --- a/packages/frontend/src/components/MkCropperDialog.vue +++ b/packages/frontend/src/components/MkCropperDialog.vue @@ -50,8 +50,8 @@ const props = defineProps<{ }>(); const imgUrl = getProxiedImageUrl(props.file.url); -let dialogEl = $ref<InstanceType<typeof XModalWindow>>(); -let imgEl = $ref<HTMLImageElement>(); +let dialogEl = $shallowRef<InstanceType<typeof XModalWindow>>(); +let imgEl = $shallowRef<HTMLImageElement>(); let cropper: Cropper | null = null; let loading = $ref(true); diff --git a/packages/frontend/src/components/MkDialog.vue b/packages/frontend/src/components/MkDialog.vue index 374ecd8abf..18c9f9203c 100644 --- a/packages/frontend/src/components/MkDialog.vue +++ b/packages/frontend/src/components/MkDialog.vue @@ -39,7 +39,7 @@ </template> <script lang="ts" setup> -import { onBeforeUnmount, onMounted, ref } from 'vue'; +import { onBeforeUnmount, onMounted, ref, shallowRef } from 'vue'; import MkModal from '@/components/MkModal.vue'; import MkButton from '@/components/MkButton.vue'; import MkInput from '@/components/form/input.vue'; @@ -94,7 +94,7 @@ const emit = defineEmits<{ (ev: 'closed'): void; }>(); -const modal = ref<InstanceType<typeof MkModal>>(); +const modal = shallowRef<InstanceType<typeof MkModal>>(); const inputValue = ref(props.input?.default || null); const selectedValue = ref(props.select?.default || null); diff --git a/packages/frontend/src/components/MkDrive.vue b/packages/frontend/src/components/MkDrive.vue index 4053870950..112a64f52d 100644 --- a/packages/frontend/src/components/MkDrive.vue +++ b/packages/frontend/src/components/MkDrive.vue @@ -88,7 +88,7 @@ </template> <script lang="ts" setup> -import { markRaw, nextTick, onActivated, onBeforeUnmount, onMounted, ref, watch } from 'vue'; +import { markRaw, nextTick, onActivated, onBeforeUnmount, onMounted, ref, shallowRef, watch } from 'vue'; import * as Misskey from 'misskey-js'; import MkButton from './MkButton.vue'; import XNavFolder from '@/components/MkDrive.navFolder.vue'; @@ -118,8 +118,8 @@ const emit = defineEmits<{ (ev: 'open-folder', v: Misskey.entities.DriveFolder): void; }>(); -const loadMoreFiles = ref<InstanceType<typeof MkButton>>(); -const fileInput = ref<HTMLInputElement>(); +const loadMoreFiles = shallowRef<InstanceType<typeof MkButton>>(); +const fileInput = shallowRef<HTMLInputElement>(); const folder = ref<Misskey.entities.DriveFolder | null>(null); const files = ref<Misskey.entities.DriveFile[]>([]); diff --git a/packages/frontend/src/components/MkDriveSelectDialog.vue b/packages/frontend/src/components/MkDriveSelectDialog.vue index 3ee821b539..6a96e758fa 100644 --- a/packages/frontend/src/components/MkDriveSelectDialog.vue +++ b/packages/frontend/src/components/MkDriveSelectDialog.vue @@ -19,7 +19,7 @@ </template> <script lang="ts" setup> -import { ref } from 'vue'; +import { ref, shallowRef } from 'vue'; import * as Misskey from 'misskey-js'; import XDrive from '@/components/MkDrive.vue'; import XModalWindow from '@/components/MkModalWindow.vue'; @@ -38,7 +38,7 @@ const emit = defineEmits<{ (ev: 'closed'): void; }>(); -const dialog = ref<InstanceType<typeof XModalWindow>>(); +const dialog = shallowRef<InstanceType<typeof XModalWindow>>(); const selected = ref<Misskey.entities.DriveFile[]>([]); diff --git a/packages/frontend/src/components/MkEmojiPicker.vue b/packages/frontend/src/components/MkEmojiPicker.vue index fe098c9de6..4ce451c85c 100644 --- a/packages/frontend/src/components/MkEmojiPicker.vue +++ b/packages/frontend/src/components/MkEmojiPicker.vue @@ -77,7 +77,7 @@ </template> <script lang="ts" setup> -import { ref, computed, watch, onMounted } from 'vue'; +import { ref, shallowRef, computed, watch, onMounted } from 'vue'; import * as Misskey from 'misskey-js'; import XSection from '@/components/MkEmojiPicker.section.vue'; import { emojilist, UnicodeEmojiDef, unicodeEmojiCategories as categories } from '@/scripts/emojilist'; @@ -102,8 +102,8 @@ const emit = defineEmits<{ (ev: 'chosen', v: string): void; }>(); -const search = ref<HTMLInputElement>(); -const emojis = ref<HTMLDivElement>(); +const search = shallowRef<HTMLInputElement>(); +const emojis = shallowRef<HTMLDivElement>(); const { reactions: pinned, diff --git a/packages/frontend/src/components/MkEmojiPickerDialog.vue b/packages/frontend/src/components/MkEmojiPickerDialog.vue index 3b41f9d75b..da68ecd809 100644 --- a/packages/frontend/src/components/MkEmojiPickerDialog.vue +++ b/packages/frontend/src/components/MkEmojiPickerDialog.vue @@ -26,7 +26,7 @@ </template> <script lang="ts" setup> -import { ref } from 'vue'; +import { shallowRef } from 'vue'; import MkModal from '@/components/MkModal.vue'; import MkEmojiPicker from '@/components/MkEmojiPicker.vue'; import { defaultStore } from '@/store'; @@ -48,8 +48,8 @@ const emit = defineEmits<{ (ev: 'closed'): void; }>(); -const modal = ref<InstanceType<typeof MkModal>>(); -const picker = ref<InstanceType<typeof MkEmojiPicker>>(); +const modal = shallowRef<InstanceType<typeof MkModal>>(); +const picker = shallowRef<InstanceType<typeof MkEmojiPicker>>(); function chosen(emoji: any) { emit('done', emoji); diff --git a/packages/frontend/src/components/MkFileCaptionEditWindow.vue b/packages/frontend/src/components/MkFileCaptionEditWindow.vue index e6b6c468ac..b3bd194dc3 100644 --- a/packages/frontend/src/components/MkFileCaptionEditWindow.vue +++ b/packages/frontend/src/components/MkFileCaptionEditWindow.vue @@ -37,7 +37,7 @@ const emit = defineEmits<{ (ev: 'closed'): void; }>(); -const dialog = $ref<InstanceType<typeof XModalWindow>>(); +const dialog = $shallowRef<InstanceType<typeof XModalWindow>>(); let caption = $ref(props.default); diff --git a/packages/frontend/src/components/MkHeatmap.vue b/packages/frontend/src/components/MkHeatmap.vue index f7a2db8509..ec7f49beee 100644 --- a/packages/frontend/src/components/MkHeatmap.vue +++ b/packages/frontend/src/components/MkHeatmap.vue @@ -12,11 +12,10 @@ import { markRaw, version as vueVersion, onMounted, onBeforeUnmount, nextTick, w import { Chart } from 'chart.js'; import { enUS } from 'date-fns/locale'; import tinycolor from 'tinycolor2'; +import { MatrixController, MatrixElement } from 'chartjs-chart-matrix'; import * as os from '@/os'; -import 'chartjs-adapter-date-fns'; import { defaultStore } from '@/store'; import { useChartTooltip } from '@/scripts/use-chart-tooltip'; -import { MatrixController, MatrixElement } from 'chartjs-chart-matrix'; import { chartVLine } from '@/scripts/chart-vline'; import { alpha } from '@/scripts/color'; import { initChart } from '@/scripts/init-chart'; @@ -27,8 +26,8 @@ const props = defineProps<{ src: string; }>(); -const rootEl = $ref<HTMLDivElement>(null); -const chartEl = $ref<HTMLCanvasElement>(null); +const rootEl = $shallowRef<HTMLDivElement>(null); +const chartEl = $shallowRef<HTMLCanvasElement>(null); const now = new Date(); let chartInstance: Chart = null; let fetching = $ref(true); diff --git a/packages/frontend/src/components/MkImageViewer.vue b/packages/frontend/src/components/MkImageViewer.vue index f074b1a2f2..22b7c12e38 100644 --- a/packages/frontend/src/components/MkImageViewer.vue +++ b/packages/frontend/src/components/MkImageViewer.vue @@ -28,7 +28,7 @@ const emit = defineEmits<{ (ev: 'closed'): void; }>(); -const modal = $ref<InstanceType<typeof MkModal>>(); +const modal = $shallowRef<InstanceType<typeof MkModal>>(); </script> <style lang="scss" scoped> diff --git a/packages/frontend/src/components/MkImgWithBlurhash.vue b/packages/frontend/src/components/MkImgWithBlurhash.vue index 80d7c201a4..6e651a06ab 100644 --- a/packages/frontend/src/components/MkImgWithBlurhash.vue +++ b/packages/frontend/src/components/MkImgWithBlurhash.vue @@ -24,7 +24,7 @@ const props = withDefaults(defineProps<{ cover: true, }); -const canvas = $ref<HTMLCanvasElement>(); +const canvas = $shallowRef<HTMLCanvasElement>(); let loaded = $ref(false); function draw() { diff --git a/packages/frontend/src/components/MkInstanceStats.vue b/packages/frontend/src/components/MkInstanceStats.vue index e576caf78a..531175b764 100644 --- a/packages/frontend/src/components/MkInstanceStats.vue +++ b/packages/frontend/src/components/MkInstanceStats.vue @@ -94,8 +94,8 @@ const chartLimit = 500; let chartSpan = $ref<'hour' | 'day'>('hour'); let chartSrc = $ref('active-users'); let heatmapSrc = $ref('active-users'); -let subDoughnutEl = $ref<HTMLCanvasElement>(); -let pubDoughnutEl = $ref<HTMLCanvasElement>(); +let subDoughnutEl = $shallowRef<HTMLCanvasElement>(); +let pubDoughnutEl = $shallowRef<HTMLCanvasElement>(); const { handler: externalTooltipHandler1 } = useChartTooltip({ position: 'middle', diff --git a/packages/frontend/src/components/MkLaunchPad.vue b/packages/frontend/src/components/MkLaunchPad.vue index 1ccc648c72..3ea90712a0 100644 --- a/packages/frontend/src/components/MkLaunchPad.vue +++ b/packages/frontend/src/components/MkLaunchPad.vue @@ -44,7 +44,7 @@ const preferedModalType = (deviceKind === 'desktop' && props.src != null) ? 'pop deviceKind === 'smartphone' ? 'drawer' : 'dialog'; -const modal = $ref<InstanceType<typeof MkModal>>(); +const modal = $shallowRef<InstanceType<typeof MkModal>>(); const menu = defaultStore.state.menu; diff --git a/packages/frontend/src/components/MkMediaBanner.vue b/packages/frontend/src/components/MkMediaBanner.vue index aa06c00fc6..718ce80e0d 100644 --- a/packages/frontend/src/components/MkMediaBanner.vue +++ b/packages/frontend/src/components/MkMediaBanner.vue @@ -38,7 +38,7 @@ const props = withDefaults(defineProps<{ }>(), { }); -const audioEl = $ref<HTMLAudioElement | null>(); +const audioEl = $shallowRef<HTMLAudioElement | null>(); let hide = $ref(true); function volumechange() { diff --git a/packages/frontend/src/components/MkMenu.child.vue b/packages/frontend/src/components/MkMenu.child.vue index c2705d394a..0ff8794c5d 100644 --- a/packages/frontend/src/components/MkMenu.child.vue +++ b/packages/frontend/src/components/MkMenu.child.vue @@ -6,7 +6,7 @@ <script lang="ts" setup> import { on } from 'events'; -import { nextTick, onBeforeUnmount, onMounted, onUnmounted, ref, watch } from 'vue'; +import { nextTick, onBeforeUnmount, onMounted, onUnmounted, ref, shallowRef, watch } from 'vue'; import MkMenu from './MkMenu.vue'; import { MenuItem } from '@/types/menu'; import * as os from '@/os'; @@ -24,7 +24,7 @@ const emit = defineEmits<{ (ev: 'actioned'): void; }>(); -const el = ref<HTMLElement>(); +const el = shallowRef<HTMLElement>(); const align = 'left'; function setPosition() { diff --git a/packages/frontend/src/components/MkMenu.vue b/packages/frontend/src/components/MkMenu.vue index 64d18b6b7c..263030e015 100644 --- a/packages/frontend/src/components/MkMenu.vue +++ b/packages/frontend/src/components/MkMenu.vue @@ -78,11 +78,11 @@ const emit = defineEmits<{ (ev: 'close', actioned?: boolean): void; }>(); -let itemsEl = $ref<HTMLDivElement>(); +let itemsEl = $shallowRef<HTMLDivElement>(); let items2: InnerMenuItem[] = $ref([]); -let child = $ref<InstanceType<typeof XChild>>(); +let child = $shallowRef<InstanceType<typeof XChild>>(); let keymap = $computed(() => ({ 'up|k|shift+tab': focusUp, @@ -112,7 +112,7 @@ watch(() => props.items, () => { }); let childMenu = $ref<MenuItem[] | null>(); -let childTarget = $ref<HTMLElement | null>(); +let childTarget = $shallowRef<HTMLElement | null>(); function closeChild() { childMenu = null; @@ -203,7 +203,7 @@ onBeforeUnmount(() => { > .item { display: block; position: relative; - padding: 6px 16px; + padding: 5px 16px; width: 100%; box-sizing: border-box; white-space: nowrap; @@ -226,10 +226,6 @@ onBeforeUnmount(() => { border-radius: 6px; } - > * { - position: relative; - } - &:not(:disabled):hover { color: var(--accent); text-decoration: none; diff --git a/packages/frontend/src/components/MkModal.vue b/packages/frontend/src/components/MkModal.vue index bd6ac02cc8..505b5e64bc 100644 --- a/packages/frontend/src/components/MkModal.vue +++ b/packages/frontend/src/components/MkModal.vue @@ -61,7 +61,7 @@ let maxHeight = $ref<number>(); let fixed = $ref(false); let transformOrigin = $ref('center'); let showing = $ref(true); -let content = $ref<HTMLElement>(); +let content = $shallowRef<HTMLElement>(); const zIndex = os.claimZIndex(props.zPriority); const type = $computed<ModalTypes>(() => { if (props.preferType === 'auto') { diff --git a/packages/frontend/src/components/MkModalPageWindow.vue b/packages/frontend/src/components/MkModalPageWindow.vue index 645da6a49c..2791d5ceb9 100644 --- a/packages/frontend/src/components/MkModalPageWindow.vue +++ b/packages/frontend/src/components/MkModalPageWindow.vue @@ -49,7 +49,7 @@ router.addListener('push', ctx => { let pageMetadata = $ref<null | ComputedRef<PageMetadata>>(); let rootEl = $ref(); -let modal = $ref<InstanceType<typeof MkModal>>(); +let modal = $shallowRef<InstanceType<typeof MkModal>>(); let path = $ref(props.initialPath); let width = $ref(860); let height = $ref(660); diff --git a/packages/frontend/src/components/MkModalWindow.vue b/packages/frontend/src/components/MkModalWindow.vue index d977ca6e9c..1e93f01c8d 100644 --- a/packages/frontend/src/components/MkModalWindow.vue +++ b/packages/frontend/src/components/MkModalWindow.vue @@ -41,9 +41,9 @@ const emit = defineEmits<{ (event: 'ok'): void; }>(); -let modal = $ref<InstanceType<typeof MkModal>>(); -let rootEl = $ref<HTMLElement>(); -let headerEl = $ref<HTMLElement>(); +let modal = $shallowRef<InstanceType<typeof MkModal>>(); +let rootEl = $shallowRef<HTMLElement>(); +let headerEl = $shallowRef<HTMLElement>(); let bodyWidth = $ref(0); let bodyHeight = $ref(0); diff --git a/packages/frontend/src/components/MkNote.vue b/packages/frontend/src/components/MkNote.vue index b379a8a7e4..5a97204bc5 100644 --- a/packages/frontend/src/components/MkNote.vue +++ b/packages/frontend/src/components/MkNote.vue @@ -59,7 +59,7 @@ </div> <MkPoll v-if="appearNote.poll" ref="pollViewer" :note="appearNote" class="poll"/> <MkUrlPreview v-for="url in urls" :key="url" :url="url" :compact="true" :detail="false" class="url-preview"/> - <div v-if="appearNote.renote" class="renote"><MkNoteSimple :note="appearNote.renote"/></div> + <div v-if="appearNote.renote" class="renote"><MkNoteSimple :note="appearNote.renote" class="note"/></div> <button v-if="isLong && collapsed" class="fade _button" @click="collapsed = false"> <span>{{ i18n.ts.showMore }}</span> </button> @@ -101,7 +101,7 @@ </template> <script lang="ts" setup> -import { computed, inject, onMounted, onUnmounted, reactive, ref, Ref } from 'vue'; +import { computed, inject, onMounted, onUnmounted, reactive, ref, shallowRef, Ref } from 'vue'; import * as mfm from 'mfm-js'; import * as misskey from 'misskey-js'; import MkNoteSub from '@/components/MkNoteSub.vue'; @@ -156,11 +156,11 @@ const isRenote = ( note.poll == null ); -const el = ref<HTMLElement>(); -const menuButton = ref<HTMLElement>(); -const renoteButton = ref<InstanceType<typeof MkRenoteButton>>(); -const renoteTime = ref<HTMLElement>(); -const reactButton = ref<HTMLElement>(); +const el = shallowRef<HTMLElement>(); +const menuButton = shallowRef<HTMLElement>(); +const renoteButton = shallowRef<InstanceType<typeof MkRenoteButton>>(); +const renoteTime = shallowRef<HTMLElement>(); +const reactButton = shallowRef<HTMLElement>(); let appearNote = $computed(() => isRenote ? note.renote as misskey.entities.Note : note); const isMyRenote = $i && ($i.id === note.userId); const showContent = ref(false); @@ -529,7 +529,7 @@ function readPromo() { > .renote { padding: 8px 0; - > * { + > .note { padding: 16px; border: dashed 1px var(--renote); border-radius: 8px; diff --git a/packages/frontend/src/components/MkNoteDetailed.vue b/packages/frontend/src/components/MkNoteDetailed.vue index 79dff69be5..7d01a7bf75 100644 --- a/packages/frontend/src/components/MkNoteDetailed.vue +++ b/packages/frontend/src/components/MkNoteDetailed.vue @@ -70,7 +70,7 @@ </div> <MkPoll v-if="appearNote.poll" ref="pollViewer" :note="appearNote" class="poll"/> <MkUrlPreview v-for="url in urls" :key="url" :url="url" :compact="true" :detail="true" class="url-preview"/> - <div v-if="appearNote.renote" class="renote"><MkNoteSimple :note="appearNote.renote"/></div> + <div v-if="appearNote.renote" class="renote"><MkNoteSimple :note="appearNote.renote" class="note"/></div> </div> <MkA v-if="appearNote.channel && !inChannel" class="channel" :to="`/channels/${appearNote.channel.id}`"><i class="ti ti-device-tv"></i> {{ appearNote.channel.name }}</MkA> </div> @@ -112,7 +112,7 @@ </template> <script lang="ts" setup> -import { computed, inject, onMounted, onUnmounted, reactive, ref } from 'vue'; +import { computed, inject, onMounted, onUnmounted, reactive, ref, shallowRef } from 'vue'; import * as mfm from 'mfm-js'; import * as misskey from 'misskey-js'; import MkNoteSub from '@/components/MkNoteSub.vue'; @@ -166,11 +166,11 @@ const isRenote = ( note.poll == null ); -const el = ref<HTMLElement>(); -const menuButton = ref<HTMLElement>(); -const renoteButton = ref<InstanceType<typeof MkRenoteButton>>(); -const renoteTime = ref<HTMLElement>(); -const reactButton = ref<HTMLElement>(); +const el = shallowRef<HTMLElement>(); +const menuButton = shallowRef<HTMLElement>(); +const renoteButton = shallowRef<InstanceType<typeof MkRenoteButton>>(); +const renoteTime = shallowRef<HTMLElement>(); +const reactButton = shallowRef<HTMLElement>(); let appearNote = $computed(() => isRenote ? note.renote as misskey.entities.Note : note); const isMyRenote = $i && ($i.id === note.userId); const showContent = ref(false); @@ -491,7 +491,7 @@ if (appearNote.replyId) { > .renote { padding: 8px 0; - > * { + > .note { padding: 16px; border: dashed 1px var(--renote); border-radius: 8px; diff --git a/packages/frontend/src/components/MkNotes.vue b/packages/frontend/src/components/MkNotes.vue index 5abcdc2298..0d77597531 100644 --- a/packages/frontend/src/components/MkNotes.vue +++ b/packages/frontend/src/components/MkNotes.vue @@ -18,7 +18,7 @@ </template> <script lang="ts" setup> -import { ref } from 'vue'; +import { shallowRef } from 'vue'; import XNote from '@/components/MkNote.vue'; import XList from '@/components/MkDateSeparatedList.vue'; import MkPagination, { Paging } from '@/components/MkPagination.vue'; @@ -29,7 +29,7 @@ const props = defineProps<{ noGap?: boolean; }>(); -const pagingComponent = ref<InstanceType<typeof MkPagination>>(); +const pagingComponent = shallowRef<InstanceType<typeof MkPagination>>(); defineExpose({ pagingComponent, diff --git a/packages/frontend/src/components/MkNotification.vue b/packages/frontend/src/components/MkNotification.vue index c8b197a850..a21a9e12a1 100644 --- a/packages/frontend/src/components/MkNotification.vue +++ b/packages/frontend/src/components/MkNotification.vue @@ -73,7 +73,7 @@ </template> <script lang="ts" setup> -import { ref, onMounted, onUnmounted, watch } from 'vue'; +import { ref, shallowRef, onMounted, onUnmounted, watch } from 'vue'; import * as misskey from 'misskey-js'; import XReactionIcon from '@/components/MkReactionIcon.vue'; import MkFollowButton from '@/components/MkFollowButton.vue'; @@ -95,7 +95,7 @@ const props = withDefaults(defineProps<{ full: false, }); -const elRef = ref<HTMLElement>(null); +const elRef = shallowRef<HTMLElement>(null); const reactionRef = ref(null); let readObserver: IntersectionObserver | undefined; diff --git a/packages/frontend/src/components/MkNotificationSettingWindow.vue b/packages/frontend/src/components/MkNotificationSettingWindow.vue index 92165ef476..754d8d687b 100644 --- a/packages/frontend/src/components/MkNotificationSettingWindow.vue +++ b/packages/frontend/src/components/MkNotificationSettingWindow.vue @@ -56,7 +56,7 @@ const props = withDefaults(defineProps<{ let includingTypes = $computed(() => props.includingTypes || []); -const dialog = $ref<InstanceType<typeof XModalWindow>>(); +const dialog = $shallowRef<InstanceType<typeof XModalWindow>>(); let typesMap = $ref<Record<typeof notificationTypes[number], boolean>>({}); let useGlobalSetting = $ref((includingTypes === null || includingTypes.length === 0) && props.showGlobalToggle); diff --git a/packages/frontend/src/components/MkNotifications.vue b/packages/frontend/src/components/MkNotifications.vue index 0e1cc06743..18aa76deeb 100644 --- a/packages/frontend/src/components/MkNotifications.vue +++ b/packages/frontend/src/components/MkNotifications.vue @@ -17,7 +17,7 @@ </template> <script lang="ts" setup> -import { defineComponent, markRaw, onUnmounted, onMounted, computed, ref } from 'vue'; +import { defineComponent, markRaw, onUnmounted, onMounted, computed, shallowRef } from 'vue'; import { notificationTypes } from 'misskey-js'; import MkPagination, { Paging } from '@/components/MkPagination.vue'; import XNotification from '@/components/MkNotification.vue'; @@ -33,7 +33,7 @@ const props = defineProps<{ unreadOnly?: boolean; }>(); -const pagingComponent = ref<InstanceType<typeof MkPagination>>(); +const pagingComponent = shallowRef<InstanceType<typeof MkPagination>>(); const pagination: Paging = { endpoint: 'i/notifications' as const, diff --git a/packages/frontend/src/components/MkPageWindow.vue b/packages/frontend/src/components/MkPageWindow.vue index d47823c71f..e25737d50c 100644 --- a/packages/frontend/src/components/MkPageWindow.vue +++ b/packages/frontend/src/components/MkPageWindow.vue @@ -47,7 +47,7 @@ defineEmits<{ const router = new Router(routes, props.initialPath); let pageMetadata = $ref<null | ComputedRef<PageMetadata>>(); -let windowEl = $ref<InstanceType<typeof XWindow>>(); +let windowEl = $shallowRef<InstanceType<typeof XWindow>>(); const history = $ref<{ path: string; key: any; }[]>([{ path: router.getCurrentPath(), key: router.getCurrentKey(), diff --git a/packages/frontend/src/components/MkPagination.vue b/packages/frontend/src/components/MkPagination.vue index dc2a9832fe..2c0a30a888 100644 --- a/packages/frontend/src/components/MkPagination.vue +++ b/packages/frontend/src/components/MkPagination.vue @@ -32,7 +32,7 @@ </template> <script lang="ts" setup> -import { computed, ComputedRef, isRef, markRaw, onActivated, onDeactivated, Ref, ref, watch } from 'vue'; +import { computed, ComputedRef, isRef, markRaw, onActivated, onDeactivated, Ref, ref, shallowRef, watch } from 'vue'; import * as misskey from 'misskey-js'; import * as os from '@/os'; import { onScrollTop, isTopVisible, getScrollPosition, getScrollContainer } from '@/scripts/scroll'; @@ -65,7 +65,7 @@ const props = withDefaults(defineProps<{ disableAutoLoad?: boolean; displayLimit?: number; }>(), { - displayLimit: 30, + displayLimit: 20, }); const emit = defineEmits<{ @@ -74,7 +74,7 @@ const emit = defineEmits<{ type Item = { id: string; [another: string]: unknown; }; -const rootEl = ref<HTMLElement>(); +const rootEl = shallowRef<HTMLElement>(); const items = ref<Item[]>([]); const queue = ref<Item[]>([]); const offset = ref(0); diff --git a/packages/frontend/src/components/MkPopupMenu.vue b/packages/frontend/src/components/MkPopupMenu.vue index f04c7f5618..b5987715a9 100644 --- a/packages/frontend/src/components/MkPopupMenu.vue +++ b/packages/frontend/src/components/MkPopupMenu.vue @@ -22,7 +22,7 @@ const emit = defineEmits<{ (ev: 'closed'): void; }>(); -let modal = $ref<InstanceType<typeof MkModal>>(); +let modal = $shallowRef<InstanceType<typeof MkModal>>(); </script> <style lang="scss" scoped> diff --git a/packages/frontend/src/components/MkPostForm.vue b/packages/frontend/src/components/MkPostForm.vue index fb2cb5671d..883ad9f14f 100644 --- a/packages/frontend/src/components/MkPostForm.vue +++ b/packages/frontend/src/components/MkPostForm.vue @@ -128,10 +128,10 @@ const emit = defineEmits<{ (ev: 'esc'): void; }>(); -const textareaEl = $ref<HTMLTextAreaElement | null>(null); -const cwInputEl = $ref<HTMLInputElement | null>(null); -const hashtagsInputEl = $ref<HTMLInputElement | null>(null); -const visibilityButton = $ref<HTMLElement | null>(null); +const textareaEl = $shallowRef<HTMLTextAreaElement | null>(null); +const cwInputEl = $shallowRef<HTMLInputElement | null>(null); +const hashtagsInputEl = $shallowRef<HTMLInputElement | null>(null); +const visibilityButton = $shallowRef<HTMLElement | null>(null); let posting = $ref(false); let posted = $ref(false); diff --git a/packages/frontend/src/components/MkPostFormDialog.vue b/packages/frontend/src/components/MkPostFormDialog.vue index 71c07ed658..f71dbdfdab 100644 --- a/packages/frontend/src/components/MkPostFormDialog.vue +++ b/packages/frontend/src/components/MkPostFormDialog.vue @@ -31,8 +31,8 @@ const emit = defineEmits<{ (ev: 'closed'): void; }>(); -let modal = $ref<InstanceType<typeof MkModal>>(); -let form = $ref<InstanceType<typeof MkPostForm>>(); +let modal = $shallowRef<InstanceType<typeof MkModal>>(); +let form = $shallowRef<InstanceType<typeof MkPostForm>>(); function onPosted() { modal.close({ diff --git a/packages/frontend/src/components/MkReactionsViewer.reaction.vue b/packages/frontend/src/components/MkReactionsViewer.reaction.vue index b10c7009f5..e0e1262550 100644 --- a/packages/frontend/src/components/MkReactionsViewer.reaction.vue +++ b/packages/frontend/src/components/MkReactionsViewer.reaction.vue @@ -12,7 +12,7 @@ </template> <script lang="ts" setup> -import { computed, onMounted, ref, watch } from 'vue'; +import { computed, onMounted, ref, shallowRef, watch } from 'vue'; import * as misskey from 'misskey-js'; import XDetails from '@/components/MkReactionsViewer.details.vue'; import XReactionIcon from '@/components/MkReactionIcon.vue'; @@ -28,7 +28,7 @@ const props = defineProps<{ note: misskey.entities.Note; }>(); -const buttonRef = ref<HTMLElement>(); +const buttonRef = shallowRef<HTMLElement>(); const canToggle = computed(() => !props.reaction.match(/@\w/) && $i); diff --git a/packages/frontend/src/components/MkRenoteButton.vue b/packages/frontend/src/components/MkRenoteButton.vue index e0b1eaafc9..e84d4a3faa 100644 --- a/packages/frontend/src/components/MkRenoteButton.vue +++ b/packages/frontend/src/components/MkRenoteButton.vue @@ -14,7 +14,7 @@ </template> <script lang="ts" setup> -import { computed, ref } from 'vue'; +import { computed, ref, shallowRef } from 'vue'; import * as misskey from 'misskey-js'; import XDetails from '@/components/MkUsersTooltip.vue'; import { pleaseLogin } from '@/scripts/please-login'; @@ -28,7 +28,7 @@ const props = defineProps<{ count: number; }>(); -const buttonRef = ref<HTMLElement>(); +const buttonRef = shallowRef<HTMLElement>(); const canRenote = computed(() => ['public', 'home'].includes(props.note.visibility) || props.note.userId === $i.id); diff --git a/packages/frontend/src/components/MkRetentionHeatmap.vue b/packages/frontend/src/components/MkRetentionHeatmap.vue index 4dcf0cef9c..e91b58a4a8 100644 --- a/packages/frontend/src/components/MkRetentionHeatmap.vue +++ b/packages/frontend/src/components/MkRetentionHeatmap.vue @@ -12,19 +12,18 @@ import { markRaw, version as vueVersion, onMounted, onBeforeUnmount, nextTick } import { Chart } from 'chart.js'; import { enUS } from 'date-fns/locale'; import tinycolor from 'tinycolor2'; +import { MatrixController, MatrixElement } from 'chartjs-chart-matrix'; import * as os from '@/os'; -import 'chartjs-adapter-date-fns'; import { defaultStore } from '@/store'; import { useChartTooltip } from '@/scripts/use-chart-tooltip'; -import { MatrixController, MatrixElement } from 'chartjs-chart-matrix'; import { chartVLine } from '@/scripts/chart-vline'; import { alpha } from '@/scripts/color'; import { initChart } from '@/scripts/init-chart'; initChart(); -const rootEl = $ref<HTMLDivElement>(null); -const chartEl = $ref<HTMLCanvasElement>(null); +const rootEl = $shallowRef<HTMLDivElement>(null); +const chartEl = $shallowRef<HTMLCanvasElement>(null); const now = new Date(); let chartInstance: Chart = null; let fetching = $ref(true); diff --git a/packages/frontend/src/components/MkSigninDialog.vue b/packages/frontend/src/components/MkSigninDialog.vue index fd27244516..5015d09e64 100644 --- a/packages/frontend/src/components/MkSigninDialog.vue +++ b/packages/frontend/src/components/MkSigninDialog.vue @@ -32,7 +32,7 @@ const emit = defineEmits<{ (ev: 'cancelled'): void; }>(); -const dialog = $ref<InstanceType<typeof XModalWindow>>(); +const dialog = $shallowRef<InstanceType<typeof XModalWindow>>(); function onClose() { emit('cancelled'); diff --git a/packages/frontend/src/components/MkSignupDialog.vue b/packages/frontend/src/components/MkSignupDialog.vue index 77497021c3..e1b76474a0 100644 --- a/packages/frontend/src/components/MkSignupDialog.vue +++ b/packages/frontend/src/components/MkSignupDialog.vue @@ -33,7 +33,7 @@ const emit = defineEmits<{ (ev: 'closed'): void; }>(); -const dialog = $ref<InstanceType<typeof XModalWindow>>(); +const dialog = $shallowRef<InstanceType<typeof XModalWindow>>(); function onSignup(res) { emit('done', res); diff --git a/packages/frontend/src/components/MkSparkle.vue b/packages/frontend/src/components/MkSparkle.vue index cdeaf9c417..0f268a9d1a 100644 --- a/packages/frontend/src/components/MkSparkle.vue +++ b/packages/frontend/src/components/MkSparkle.vue @@ -64,10 +64,10 @@ </template> <script lang="ts" setup> -import { onMounted, onUnmounted, ref } from 'vue'; +import { onMounted, onUnmounted, ref, shallowRef } from 'vue'; const particles = ref([]); -const el = ref<HTMLElement>(); +const el = shallowRef<HTMLElement>(); const width = ref(0); const height = ref(0); const colors = ['#FF1493', '#00FFFF', '#FFE202', '#FFE202', '#FFE202']; diff --git a/packages/frontend/src/components/MkTagCloud.vue b/packages/frontend/src/components/MkTagCloud.vue index 2dfd26edb0..9f7e76f18e 100644 --- a/packages/frontend/src/components/MkTagCloud.vue +++ b/packages/frontend/src/components/MkTagCloud.vue @@ -19,9 +19,9 @@ const computedStyle = getComputedStyle(document.documentElement); const idForCanvas = Array.from(Array(16)).map(() => SAFE_FOR_HTML_ID[Math.floor(Math.random() * SAFE_FOR_HTML_ID.length)]).join(''); const idForTags = Array.from(Array(16)).map(() => SAFE_FOR_HTML_ID[Math.floor(Math.random() * SAFE_FOR_HTML_ID.length)]).join(''); let available = $ref(false); -let rootEl = $ref<HTMLElement | null>(null); -let canvasEl = $ref<HTMLCanvasElement | null>(null); -let tagsEl = $ref<HTMLElement | null>(null); +let rootEl = $shallowRef<HTMLElement | null>(null); +let canvasEl = $shallowRef<HTMLCanvasElement | null>(null); +let tagsEl = $shallowRef<HTMLElement | null>(null); let width = $ref(300); watch($$(available), () => { diff --git a/packages/frontend/src/components/MkTokenGenerateWindow.vue b/packages/frontend/src/components/MkTokenGenerateWindow.vue index b846034a24..8d5b6f8635 100644 --- a/packages/frontend/src/components/MkTokenGenerateWindow.vue +++ b/packages/frontend/src/components/MkTokenGenerateWindow.vue @@ -54,7 +54,7 @@ const emit = defineEmits<{ (ev: 'done', result: { name: string | null, permissions: string[] }): void; }>(); -const dialog = $ref<InstanceType<typeof XModalWindow>>(); +const dialog = $shallowRef<InstanceType<typeof XModalWindow>>(); let name = $ref(props.initialName); let permissions = $ref({}); diff --git a/packages/frontend/src/components/MkTooltip.vue b/packages/frontend/src/components/MkTooltip.vue index 9dba0c7350..399cec36c7 100644 --- a/packages/frontend/src/components/MkTooltip.vue +++ b/packages/frontend/src/components/MkTooltip.vue @@ -10,7 +10,7 @@ </template> <script lang="ts" setup> -import { nextTick, onMounted, onUnmounted, ref } from 'vue'; +import { nextTick, onMounted, onUnmounted, ref, shallowRef } from 'vue'; import * as os from '@/os'; import { calcPopupPosition } from '@/scripts/popup-position'; @@ -34,7 +34,7 @@ const emit = defineEmits<{ (ev: 'closed'): void; }>(); -const el = ref<HTMLElement>(); +const el = shallowRef<HTMLElement>(); const zIndex = os.claimZIndex('high'); function setPosition() { diff --git a/packages/frontend/src/components/MkUpdated.vue b/packages/frontend/src/components/MkUpdated.vue index 48aeb30224..2f2864220e 100644 --- a/packages/frontend/src/components/MkUpdated.vue +++ b/packages/frontend/src/components/MkUpdated.vue @@ -10,14 +10,14 @@ </template> <script lang="ts" setup> -import { ref } from 'vue'; +import { shallowRef } from 'vue'; import MkModal from '@/components/MkModal.vue'; import MkButton from '@/components/MkButton.vue'; import MkSparkle from '@/components/MkSparkle.vue'; import { version } from '@/config'; import { i18n } from '@/i18n'; -const modal = ref<InstanceType<typeof MkModal>>(); +const modal = shallowRef<InstanceType<typeof MkModal>>(); const whatIsNew = () => { modal.value.close(); diff --git a/packages/frontend/src/components/MkUserList.vue b/packages/frontend/src/components/MkUserList.vue index e1f47c7673..b7bc200a55 100644 --- a/packages/frontend/src/components/MkUserList.vue +++ b/packages/frontend/src/components/MkUserList.vue @@ -1,5 +1,5 @@ <template> -<MkPagination ref="pagingComponent" :pagination="pagination"> +<MkPagination :pagination="pagination"> <template #empty> <div class="_fullinfo"> <img src="https://xn--931a.moe/assets/info.jpg" class="_ghost"/> @@ -16,7 +16,7 @@ </template> <script lang="ts" setup> -import { ref } from 'vue'; +import { shallowRef } from 'vue'; import MkUserInfo from '@/components/MkUserInfo.vue'; import MkPagination, { Paging } from '@/components/MkPagination.vue'; import { userPage } from '@/filters/user'; @@ -26,8 +26,6 @@ const props = defineProps<{ pagination: Paging; noGap?: boolean; }>(); - -const pagingComponent = ref<InstanceType<typeof MkPagination>>(); </script> <style lang="scss" scoped> diff --git a/packages/frontend/src/components/MkVisibility.vue b/packages/frontend/src/components/MkVisibility.vue index 229907fbb8..2becb69d5a 100644 --- a/packages/frontend/src/components/MkVisibility.vue +++ b/packages/frontend/src/components/MkVisibility.vue @@ -22,7 +22,7 @@ const props = defineProps<{ }, }>(); -const specified = $ref<HTMLElement>(); +const specified = $shallowRef<HTMLElement>(); if (props.note.visibility === 'specified') { useTooltip($$(specified), async (showing) => { diff --git a/packages/frontend/src/components/MkVisibilityPicker.vue b/packages/frontend/src/components/MkVisibilityPicker.vue index 8f0bcdeae8..4c78659f5c 100644 --- a/packages/frontend/src/components/MkVisibilityPicker.vue +++ b/packages/frontend/src/components/MkVisibilityPicker.vue @@ -1,42 +1,42 @@ <template> <MkModal ref="modal" :z-priority="'high'" :src="src" @click="modal.close()" @closed="emit('closed')"> <div class="gqyayizv _popup"> - <button key="public" class="_button" :class="{ active: v === 'public' }" data-index="1" @click="choose('public')"> - <div><i class="ti ti-world"></i></div> - <div> + <button key="public" class="_button item" :class="{ active: v === 'public' }" data-index="1" @click="choose('public')"> + <div class="icon"><i class="ti ti-world"></i></div> + <div class="body"> <span>{{ i18n.ts._visibility.public }}</span> <span>{{ i18n.ts._visibility.publicDescription }}</span> </div> </button> - <button key="home" class="_button" :class="{ active: v === 'home' }" data-index="2" @click="choose('home')"> - <div><i class="ti ti-home"></i></div> - <div> + <button key="home" class="_button item" :class="{ active: v === 'home' }" data-index="2" @click="choose('home')"> + <div class="icon"><i class="ti ti-home"></i></div> + <div class="body"> <span>{{ i18n.ts._visibility.home }}</span> <span>{{ i18n.ts._visibility.homeDescription }}</span> </div> </button> - <button key="followers" class="_button" :class="{ active: v === 'followers' }" data-index="3" @click="choose('followers')"> - <div><i class="ti ti-lock-open"></i></div> - <div> + <button key="followers" class="_button item" :class="{ active: v === 'followers' }" data-index="3" @click="choose('followers')"> + <div class="icon"><i class="ti ti-lock-open"></i></div> + <div class="body"> <span>{{ i18n.ts._visibility.followers }}</span> <span>{{ i18n.ts._visibility.followersDescription }}</span> </div> </button> - <button key="specified" :disabled="localOnly" class="_button" :class="{ active: v === 'specified' }" data-index="4" @click="choose('specified')"> - <div><i class="ti ti-mail"></i></div> - <div> + <button key="specified" :disabled="localOnly" class="_button item" :class="{ active: v === 'specified' }" data-index="4" @click="choose('specified')"> + <div class="icon"><i class="ti ti-mail"></i></div> + <div class="body"> <span>{{ i18n.ts._visibility.specified }}</span> <span>{{ i18n.ts._visibility.specifiedDescription }}</span> </div> </button> <div class="divider"></div> - <button key="localOnly" class="_button localOnly" :class="{ active: localOnly }" data-index="5" @click="localOnly = !localOnly"> - <div><i class="ti ti-world-off"></i></div> - <div> + <button key="localOnly" class="_button item localOnly" :class="{ active: localOnly }" data-index="5" @click="localOnly = !localOnly"> + <div class="icon"><i class="ti ti-world-off"></i></div> + <div class="body"> <span>{{ i18n.ts._visibility.localOnly }}</span> <span>{{ i18n.ts._visibility.localOnlyDescription }}</span> </div> - <div><i :class="localOnly ? 'ti ti-toggle-right' : 'ti ti-toggle-left'"></i></div> + <div class="toggle"><i :class="localOnly ? 'ti ti-toggle-right' : 'ti ti-toggle-left'"></i></div> </button> </div> </MkModal> @@ -48,7 +48,7 @@ import * as misskey from 'misskey-js'; import MkModal from '@/components/MkModal.vue'; import { i18n } from '@/i18n'; -const modal = $ref<InstanceType<typeof MkModal>>(); +const modal = $shallowRef<InstanceType<typeof MkModal>>(); const props = withDefaults(defineProps<{ currentVisibility: typeof misskey.noteVisibilities[number]; @@ -89,7 +89,7 @@ function choose(visibility: typeof misskey.noteVisibilities[number]): void { border-top: solid 0.5px var(--divider); } - > button { + > .item { display: flex; padding: 8px 14px; font-size: 12px; @@ -115,7 +115,7 @@ function choose(visibility: typeof misskey.noteVisibilities[number]): void { background: inherit; } - > *:nth-child(1) { + > .icon { display: flex; justify-content: center; align-items: center; @@ -127,7 +127,7 @@ function choose(visibility: typeof misskey.noteVisibilities[number]): void { margin-bottom: auto; } - > *:nth-child(2) { + > .body { flex: 1 1 auto; white-space: nowrap; overflow: hidden; @@ -143,7 +143,7 @@ function choose(visibility: typeof misskey.noteVisibilities[number]): void { } } - > *:nth-child(3) { + > .toggle { display: flex; justify-content: center; align-items: center; diff --git a/packages/frontend/src/components/MkWaitingDialog.vue b/packages/frontend/src/components/MkWaitingDialog.vue index f4a9f4f22c..984cdc5266 100644 --- a/packages/frontend/src/components/MkWaitingDialog.vue +++ b/packages/frontend/src/components/MkWaitingDialog.vue @@ -9,10 +9,10 @@ </template> <script lang="ts" setup> -import { watch, ref } from 'vue'; +import { watch, shallowRef } from 'vue'; import MkModal from '@/components/MkModal.vue'; -const modal = ref<InstanceType<typeof MkModal>>(); +const modal = shallowRef<InstanceType<typeof MkModal>>(); const props = defineProps<{ success: boolean; diff --git a/packages/frontend/src/components/MkWindow.vue b/packages/frontend/src/components/MkWindow.vue index dca258421b..0f7e0e4f2e 100644 --- a/packages/frontend/src/components/MkWindow.vue +++ b/packages/frontend/src/components/MkWindow.vue @@ -88,7 +88,7 @@ const emit = defineEmits<{ provide('inWindow', true); -let rootEl = $ref<HTMLElement | null>(); +let rootEl = $shallowRef<HTMLElement | null>(); let showing = $ref(true); let beforeClickedAt = 0; let maximized = $ref(false); diff --git a/packages/frontend/src/components/form/checkbox.vue b/packages/frontend/src/components/form/checkbox.vue index d869b600c9..a8e24dd839 100644 --- a/packages/frontend/src/components/form/checkbox.vue +++ b/packages/frontend/src/components/form/checkbox.vue @@ -35,7 +35,7 @@ const emit = defineEmits<{ (ev: 'update:modelValue', v: boolean): void; }>(); -let button = $ref<HTMLElement>(); +let button = $shallowRef<HTMLElement>(); const checked = toRefs(props).modelValue; const toggle = () => { if (props.disabled) return; diff --git a/packages/frontend/src/components/form/folder.vue b/packages/frontend/src/components/form/folder.vue index d7603e58d1..40bbc97002 100644 --- a/packages/frontend/src/components/form/folder.vue +++ b/packages/frontend/src/components/form/folder.vue @@ -1,5 +1,5 @@ <template> -<div class="dwzlatin" :class="{ opened }" ref="root"> +<div class="dwzlatin" :class="{ opened }"> <div class="header _button" @click="toggle"> <span class="icon"><slot name="icon"></slot></span> <span class="text"><slot name="label"></slot></span> @@ -19,7 +19,7 @@ > <KeepAlive> <div v-show="opened"> - <MkSpacer :margin-min="14" :margin-max="22" :container="root"> + <MkSpacer :margin-min="14" :margin-max="22"> <slot></slot> </MkSpacer> </div> @@ -40,7 +40,6 @@ const props = withDefaults(defineProps<{ let opened = $ref(props.defaultOpen); let openedAtLeastOnce = $ref(props.defaultOpen); -let root = $ref<HTMLElement>(); function enter(el) { const elementHeight = el.getBoundingClientRect().height; @@ -142,6 +141,7 @@ function toggle() { > .body { background: var(--panel); border-radius: 0 0 6px 6px; + container-type: inline-size; } &.opened { diff --git a/packages/frontend/src/components/form/input.vue b/packages/frontend/src/components/form/input.vue index b7e216bfe2..4f3e50c31a 100644 --- a/packages/frontend/src/components/form/input.vue +++ b/packages/frontend/src/components/form/input.vue @@ -34,7 +34,7 @@ </template> <script lang="ts" setup> -import { onMounted, onUnmounted, nextTick, ref, watch, computed, toRefs } from 'vue'; +import { onMounted, onUnmounted, nextTick, ref, shallowRef, watch, computed, toRefs } from 'vue'; import { debounce } from 'throttle-debounce'; import MkButton from '@/components/MkButton.vue'; import { useInterval } from '@/scripts/use-interval'; @@ -74,9 +74,9 @@ const focused = ref(false); const changed = ref(false); const invalid = ref(false); const filled = computed(() => v.value !== '' && v.value != null); -const inputEl = ref<HTMLElement>(); -const prefixEl = ref<HTMLElement>(); -const suffixEl = ref<HTMLElement>(); +const inputEl = shallowRef<HTMLElement>(); +const prefixEl = shallowRef<HTMLElement>(); +const suffixEl = shallowRef<HTMLElement>(); const height = props.small ? 35 : props.large ? 39 : diff --git a/packages/frontend/src/components/form/switch.vue b/packages/frontend/src/components/form/switch.vue index 1ed00ae655..5c9e3a5223 100644 --- a/packages/frontend/src/components/form/switch.vue +++ b/packages/frontend/src/components/form/switch.vue @@ -34,7 +34,7 @@ const emit = defineEmits<{ (ev: 'update:modelValue', v: boolean): void; }>(); -let button = $ref<HTMLElement>(); +let button = $shallowRef<HTMLElement>(); const checked = toRefs(props).modelValue; const toggle = () => { if (props.disabled) return; diff --git a/packages/frontend/src/components/global/MkPageHeader.vue b/packages/frontend/src/components/global/MkPageHeader.vue index 9c7c49ac58..e39cc70185 100644 --- a/packages/frontend/src/components/global/MkPageHeader.vue +++ b/packages/frontend/src/components/global/MkPageHeader.vue @@ -77,9 +77,9 @@ const metadata = injectPageMetadata(); const hideTitle = inject('shouldOmitHeaderTitle', false); const thin_ = props.thin || inject('shouldHeaderThin', false); -const el = $ref<HTMLElement | undefined>(undefined); +const el = $shallowRef<HTMLElement | undefined>(undefined); const tabRefs: Record<string, HTMLElement | null> = {}; -const tabHighlightEl = $ref<HTMLElement | null>(null); +const tabHighlightEl = $shallowRef<HTMLElement | null>(null); const bg = ref<string | undefined>(undefined); let narrow = $ref(false); const hasTabs = $computed(() => props.tabs.length > 0); diff --git a/packages/frontend/src/components/global/MkSpacer.vue b/packages/frontend/src/components/global/MkSpacer.vue index 01e7409801..1ddb230bd6 100644 --- a/packages/frontend/src/components/global/MkSpacer.vue +++ b/packages/frontend/src/components/global/MkSpacer.vue @@ -1,6 +1,6 @@ <template> -<div ref="root" :class="$style.root" :style="{ padding: margin + 'px' }"> - <div ref="content" :class="$style.content"> +<div :class="[$style.root, { [$style.rootMin]: forceSpacerMin }]"> + <div :class="$style.content"> <slot></slot> </div> </div> @@ -14,85 +14,13 @@ const props = withDefaults(defineProps<{ contentMax?: number | null; marginMin?: number; marginMax?: number; - - // MkFolderとかで開閉アニメーションの際にheightを正しく伝えるため - container?: HTMLElement, }>(), { contentMax: null, marginMin: 12, marginMax: 24, }); -let ro: ResizeObserver; -let root = $ref<HTMLElement>(); -let content = $ref<HTMLElement>(); -let margin = $ref(props.marginMin); -const widthHistory = [null, null] as [number | null, number | null]; -const heightHistory = [null, null] as [number | null, number | null]; -const shouldSpacerMin = inject('shouldSpacerMin', false); - -const adjust = (rect: { width: number; height: number; }) => { - if (shouldSpacerMin || deviceKind === 'smartphone') { - margin = props.marginMin; - return; - } - - if (rect.width > (props.contentMax ?? 0) || (rect.width > 360 && window.innerWidth > 400)) { - margin = props.marginMax; - } else { - margin = props.marginMin; - } -}; - -if (props.container) { - const width = props.container.offsetWidth; - const height = props.container.offsetHeight; - adjust({ - width, - height, - }); -} - -onMounted(() => { - ro = new ResizeObserver((entries) => { - /* iOSが対応していない - adjust({ - width: entries[0].borderBoxSize[0].inlineSize, - height: entries[0].borderBoxSize[0].blockSize, - }); - */ - - const width = props.container ? props.container.offsetWidth : root!.offsetWidth; - const height = props.container ? props.container.offsetHeight : root!.offsetHeight; - - //#region Prevent infinite resizing - // https://github.com/misskey-dev/misskey/issues/9076 - const pastWidth = widthHistory.pop(); - widthHistory.unshift(width); - const pastHeight = heightHistory.pop(); - heightHistory.unshift(height); - - - if (pastWidth === width && pastHeight === height) { - return; - } - //#endregion - - adjust({ - width, - height, - }); - }); - ro.observe(root!); - - if (props.contentMax) { - content!.style.maxWidth = `${props.contentMax}px`; - } -}); - -onUnmounted(() => { - ro.disconnect(); -}); +const forceSpacerMin = inject('forceSpacerMin', false) || deviceKind === 'smartphone'; </script> <style lang="scss" module> @@ -100,9 +28,25 @@ onUnmounted(() => { box-sizing: border-box; width: 100%; } +.rootMin { + padding: v-bind('props.marginMin + "px"') !important; +} .content { margin: 0 auto; + max-width: v-bind('props.contentMax + "px"'); container-type: inline-size; } + +@container (max-width: 360px) { + .root { + padding: v-bind('props.marginMin + "px"'); + } +} + +@container (min-width: 361px) { + .root { + padding: v-bind('props.marginMax + "px"'); + } +} </style> diff --git a/packages/frontend/src/components/global/MkStickyContainer.vue b/packages/frontend/src/components/global/MkStickyContainer.vue index 44f4f065a6..a3fee91a36 100644 --- a/packages/frontend/src/components/global/MkStickyContainer.vue +++ b/packages/frontend/src/components/global/MkStickyContainer.vue @@ -18,9 +18,9 @@ const CURRENT_STICKY_TOP = 'CURRENT_STICKY_TOP'; <script lang="ts" setup> import { onMounted, onUnmounted, provide, inject, Ref, ref, watch } from 'vue'; -const rootEl = $ref<HTMLElement>(); -const headerEl = $ref<HTMLElement>(); -const bodyEl = $ref<HTMLElement>(); +const rootEl = $shallowRef<HTMLElement>(); +const headerEl = $shallowRef<HTMLElement>(); +const bodyEl = $shallowRef<HTMLElement>(); let headerHeight = $ref<string | undefined>(); let childStickyTop = $ref(0); diff --git a/packages/frontend/src/components/page/page.vue b/packages/frontend/src/components/page/page.vue index b5cb73c009..87a288befe 100644 --- a/packages/frontend/src/components/page/page.vue +++ b/packages/frontend/src/components/page/page.vue @@ -6,7 +6,6 @@ <script lang="ts"> import { defineComponent, onMounted, nextTick, onUnmounted, PropType } from 'vue'; -import { parse } from '@syuilo/aiscript'; import XBlock from './page.block.vue'; import { Hpml } from '@/scripts/hpml/evaluator'; import { url } from '@/config'; @@ -28,38 +27,11 @@ export default defineComponent({ randomSeed: Math.random(), visitor: $i, url: url, - enableAiScript: !defaultStore.state.disablePagesScript, }); onMounted(() => { nextTick(() => { - if (props.page.script && hpml.aiscript) { - let ast; - try { - ast = parse(props.page.script); - } catch (err) { - console.error(err); - /*os.alert({ - type: 'error', - text: 'Syntax error :(' - });*/ - return; - } - hpml.aiscript.exec(ast).then(() => { - hpml.eval(); - }).catch(err => { - console.error(err); - /*os.alert({ - type: 'error', - text: err - });*/ - }); - } else { - hpml.eval(); - } - }); - onUnmounted(() => { - if (hpml.aiscript) hpml.aiscript.abort(); + hpml.eval(); }); }); diff --git a/packages/frontend/src/pages/about-misskey.vue b/packages/frontend/src/pages/about-misskey.vue index 67f141d458..5085b12527 100644 --- a/packages/frontend/src/pages/about-misskey.vue +++ b/packages/frontend/src/pages/about-misskey.vue @@ -156,7 +156,7 @@ const patrons = [ let easterEggReady = false; let easterEggEmojis = $ref([]); let easterEggEngine = $ref(null); -const containerEl = $ref<HTMLElement>(); +const containerEl = $shallowRef<HTMLElement>(); function iconLoaded() { const emojis = defaultStore.state.reactions; diff --git a/packages/frontend/src/pages/about.federation.vue b/packages/frontend/src/pages/about.federation.vue index 2b20f383d1..1709f06a16 100644 --- a/packages/frontend/src/pages/about.federation.vue +++ b/packages/frontend/src/pages/about.federation.vue @@ -30,15 +30,13 @@ <option value="-followers">{{ i18n.ts.followers }} ({{ i18n.ts.ascendingOrder }})</option> <option value="+caughtAt">{{ i18n.ts.registeredAt }} ({{ i18n.ts.descendingOrder }})</option> <option value="-caughtAt">{{ i18n.ts.registeredAt }} ({{ i18n.ts.ascendingOrder }})</option> - <option value="+lastCommunicatedAt">{{ i18n.ts.lastCommunication }} ({{ i18n.ts.descendingOrder }})</option> - <option value="-lastCommunicatedAt">{{ i18n.ts.lastCommunication }} ({{ i18n.ts.ascendingOrder }})</option> </MkSelect> </FormSplit> </div> <MkPagination v-slot="{items}" ref="instances" :key="host + state" :pagination="pagination"> <div class="dqokceoi"> - <MkA v-for="instance in items" :key="instance.id" v-tooltip.mfm="`Last communicated: ${dateString(instance.lastCommunicatedAt)}\nStatus: ${getStatus(instance)}`" class="instance" :to="`/instance-info/${instance.host}`"> + <MkA v-for="instance in items" :key="instance.id" v-tooltip.mfm="`Status: ${getStatus(instance)}`" class="instance" :to="`/instance-info/${instance.host}`"> <MkInstanceCardMini :instance="instance"/> </MkA> </div> diff --git a/packages/frontend/src/pages/admin/_header_.vue b/packages/frontend/src/pages/admin/_header_.vue index bdb41b2d2c..a342644516 100644 --- a/packages/frontend/src/pages/admin/_header_.vue +++ b/packages/frontend/src/pages/admin/_header_.vue @@ -28,7 +28,7 @@ </template> <script lang="ts" setup> -import { computed, onMounted, onUnmounted, ref, inject, watch, nextTick } from 'vue'; +import { computed, onMounted, onUnmounted, ref, shallowRef, inject, watch, nextTick } from 'vue'; import tinycolor from 'tinycolor2'; import { popupMenu } from '@/os'; import { url } from '@/config'; @@ -64,9 +64,9 @@ const emit = defineEmits<{ const metadata = injectPageMetadata(); -const el = ref<HTMLElement>(null); +const el = shallowRef<HTMLElement>(null); const tabRefs = {}; -const tabHighlightEl = $ref<HTMLElement | null>(null); +const tabHighlightEl = $shallowRef<HTMLElement | null>(null); const bg = ref(null); const height = ref(0); const hasTabs = computed(() => { diff --git a/packages/frontend/src/pages/admin/abuses.vue b/packages/frontend/src/pages/admin/abuses.vue index 973ec871ab..3bff312b8b 100644 --- a/packages/frontend/src/pages/admin/abuses.vue +++ b/packages/frontend/src/pages/admin/abuses.vue @@ -58,7 +58,7 @@ import * as os from '@/os'; import { i18n } from '@/i18n'; import { definePageMetadata } from '@/scripts/page-metadata'; -let reports = $ref<InstanceType<typeof MkPagination>>(); +let reports = $shallowRef<InstanceType<typeof MkPagination>>(); let state = $ref('unresolved'); let reporterOrigin = $ref('combined'); diff --git a/packages/frontend/src/pages/admin/emojis.vue b/packages/frontend/src/pages/admin/emojis.vue index 4bd78a6a5f..3d56ab1962 100644 --- a/packages/frontend/src/pages/admin/emojis.vue +++ b/packages/frontend/src/pages/admin/emojis.vue @@ -68,7 +68,7 @@ </template> <script lang="ts" setup> -import { computed, defineAsyncComponent, defineComponent, ref, toRef } from 'vue'; +import { computed, defineAsyncComponent, defineComponent, ref, shallowRef } from 'vue'; import XHeader from './_header_.vue'; import MkButton from '@/components/MkButton.vue'; import MkInput from '@/components/form/input.vue'; @@ -81,7 +81,7 @@ import * as os from '@/os'; import { i18n } from '@/i18n'; import { definePageMetadata } from '@/scripts/page-metadata'; -const emojisPaginationComponent = ref<InstanceType<typeof MkPagination>>(); +const emojisPaginationComponent = shallowRef<InstanceType<typeof MkPagination>>(); const tab = ref('local'); const query = ref(null); diff --git a/packages/frontend/src/pages/admin/index.vue b/packages/frontend/src/pages/admin/index.vue index 406677229f..c71ebd4e2e 100644 --- a/packages/frontend/src/pages/admin/index.vue +++ b/packages/frontend/src/pages/admin/index.vue @@ -16,7 +16,7 @@ </div> </MkSpacer> </div> - <div v-if="!(narrow && currentPage?.route.name == null)" class="main" style="container-type: inline-size;"> + <div v-if="!(narrow && currentPage?.route.name == null)" class="main"> <RouterView/> </div> </div> diff --git a/packages/frontend/src/pages/admin/metrics.vue b/packages/frontend/src/pages/admin/metrics.vue deleted file mode 100644 index f32b52d30a..0000000000 --- a/packages/frontend/src/pages/admin/metrics.vue +++ /dev/null @@ -1,439 +0,0 @@ -<template> -<div class="_debobigegoItem"> - <div class="_debobigegoLabel"><i class="fas fa-microchip"></i> {{ $ts.cpuAndMemory }}</div> - <div class="_debobigegoPanel xhexznfu"> - <div> - <canvas :ref="cpumem"></canvas> - </div> - <div v-if="serverInfo"> - <div class="_table"> - <div class="_row"> - <div class="_cell"><div class="_label">MEM total</div>{{ bytes(serverInfo.mem.total) }}</div> - <div class="_cell"><div class="_label">MEM used</div>{{ bytes(memUsage) }} ({{ (memUsage / serverInfo.mem.total * 100).toFixed(0) }}%)</div> - <div class="_cell"><div class="_label">MEM free</div>{{ bytes(serverInfo.mem.total - memUsage) }} ({{ ((serverInfo.mem.total - memUsage) / serverInfo.mem.total * 100).toFixed(0) }}%)</div> - </div> - </div> - </div> - </div> -</div> -<div class="_debobigegoItem"> - <div class="_debobigegoLabel"><i class="fas fa-hdd"></i> {{ $ts.disk }}</div> - <div class="_debobigegoPanel xhexznfu"> - <div> - <canvas :ref="disk"></canvas> - </div> - <div v-if="serverInfo"> - <div class="_table"> - <div class="_row"> - <div class="_cell"><div class="_label">Disk total</div>{{ bytes(serverInfo.fs.total) }}</div> - <div class="_cell"><div class="_label">Disk used</div>{{ bytes(serverInfo.fs.used) }} ({{ (serverInfo.fs.used / serverInfo.fs.total * 100).toFixed(0) }}%)</div> - <div class="_cell"><div class="_label">Disk free</div>{{ bytes(serverInfo.fs.total - serverInfo.fs.used) }} ({{ ((serverInfo.fs.total - serverInfo.fs.used) / serverInfo.fs.total * 100).toFixed(0) }}%)</div> - </div> - </div> - </div> - </div> -</div> -<div class="_debobigegoItem"> - <div class="_debobigegoLabel"><i class="fas fa-exchange-alt"></i> {{ $ts.network }}</div> - <div class="_debobigegoPanel xhexznfu"> - <div> - <canvas :ref="net"></canvas> - </div> - <div v-if="serverInfo"> - <div class="_table"> - <div class="_row"> - <div class="_cell"><div class="_label">Interface</div>{{ serverInfo.net.interface }}</div> - </div> - </div> - </div> - </div> -</div> -</template> - -<script lang="ts"> -import { defineComponent, markRaw } from 'vue'; -import { Chart } from 'chart.js'; -import MkwFederation from '../../widgets/federation.vue'; -import MkButton from '@/components/MkButton.vue'; -import MkSelect from '@/components/form/select.vue'; -import MkInput from '@/components/form/input.vue'; -import MkContainer from '@/components/MkContainer.vue'; -import MkFolder from '@/components/MkFolder.vue'; -import { version, url } from '@/config'; -import bytes from '@/filters/bytes'; -import number from '@/filters/number'; -import * as os from '@/os'; -import { stream } from '@/stream'; -import { alpha } from '@/scripts/color'; -import { initChart } from '@/scripts/init-chart'; - -initChart(); - -export default defineComponent({ - components: { - MkButton, - MkSelect, - MkInput, - MkContainer, - MkFolder, - MkwFederation, - }, - - data() { - return { - version, - url, - stats: null, - serverInfo: null, - connection: null, - queueConnection: markRaw(stream.useChannel('queueStats')), - memUsage: 0, - chartCpuMem: null, - chartNet: null, - jobs: [], - logs: [], - logLevel: 'all', - logDomain: '', - modLogs: [], - dbInfo: null, - overviewHeight: '1fr', - queueHeight: '1fr', - paused: false, - }; - }, - - computed: { - gridColor() { - // TODO: var(--panel)の色が暗いか明るいかで判定する - return this.$store.state.darkMode ? 'rgba(255, 255, 255, 0.1)' : 'rgba(0, 0, 0, 0.1)'; - }, - }, - - mounted() { - this.fetchJobs(); - - Chart.defaults.color = getComputedStyle(document.documentElement).getPropertyValue('--fg'); - - os.api('admin/server-info', {}).then(res => { - this.serverInfo = res; - - this.connection = markRaw(stream.useChannel('serverStats')); - this.connection.on('stats', this.onStats); - this.connection.on('statsLog', this.onStatsLog); - this.connection.send('requestLog', { - id: Math.random().toString().substr(2, 8), - length: 150, - }); - - this.$nextTick(() => { - this.queueConnection.send('requestLog', { - id: Math.random().toString().substr(2, 8), - length: 200, - }); - }); - }); - }, - - beforeUnmount() { - if (this.connection) { - this.connection.off('stats', this.onStats); - this.connection.off('statsLog', this.onStatsLog); - this.connection.dispose(); - } - this.queueConnection.dispose(); - }, - - methods: { - cpumem(el) { - if (this.chartCpuMem != null) return; - this.chartCpuMem = markRaw(new Chart(el, { - type: 'line', - data: { - labels: [], - datasets: [{ - label: 'CPU', - pointRadius: 0, - tension: 0, - borderWidth: 2, - borderColor: '#86b300', - backgroundColor: alpha('#86b300', 0.1), - data: [], - }, { - label: 'MEM (active)', - pointRadius: 0, - tension: 0, - borderWidth: 2, - borderColor: '#935dbf', - backgroundColor: alpha('#935dbf', 0.02), - data: [], - }, { - label: 'MEM (used)', - pointRadius: 0, - tension: 0, - borderWidth: 2, - borderColor: '#935dbf', - borderDash: [5, 5], - fill: false, - data: [], - }], - }, - options: { - aspectRatio: 3, - layout: { - padding: { - left: 16, - right: 16, - top: 16, - bottom: 0, - }, - }, - legend: { - position: 'bottom', - labels: { - boxWidth: 16, - }, - }, - scales: { - x: { - gridLines: { - display: false, - color: this.gridColor, - zeroLineColor: this.gridColor, - }, - ticks: { - display: false, - }, - }, - y: { - position: 'right', - gridLines: { - display: true, - color: this.gridColor, - zeroLineColor: this.gridColor, - }, - ticks: { - display: false, - max: 100, - }, - }, - }, - tooltips: { - intersect: false, - mode: 'index', - }, - }, - })); - }, - - net(el) { - if (this.chartNet != null) return; - this.chartNet = markRaw(new Chart(el, { - type: 'line', - data: { - labels: [], - datasets: [{ - label: 'In', - pointRadius: 0, - tension: 0, - borderWidth: 2, - borderColor: '#94a029', - backgroundColor: alpha('#94a029', 0.1), - data: [], - }, { - label: 'Out', - pointRadius: 0, - tension: 0, - borderWidth: 2, - borderColor: '#ff9156', - backgroundColor: alpha('#ff9156', 0.1), - data: [], - }], - }, - options: { - aspectRatio: 3, - layout: { - padding: { - left: 16, - right: 16, - top: 16, - bottom: 0, - }, - }, - legend: { - position: 'bottom', - labels: { - boxWidth: 16, - }, - }, - scales: { - x: { - gridLines: { - display: false, - color: this.gridColor, - zeroLineColor: this.gridColor, - }, - ticks: { - display: false, - }, - }, - y: { - position: 'right', - gridLines: { - display: true, - color: this.gridColor, - zeroLineColor: this.gridColor, - }, - ticks: { - display: false, - }, - }, - }, - tooltips: { - intersect: false, - mode: 'index', - }, - }, - })); - }, - - disk(el) { - if (this.chartDisk != null) return; - this.chartDisk = markRaw(new Chart(el, { - type: 'line', - data: { - labels: [], - datasets: [{ - label: 'Read', - pointRadius: 0, - tension: 0, - borderWidth: 2, - borderColor: '#94a029', - backgroundColor: alpha('#94a029', 0.1), - data: [], - }, { - label: 'Write', - pointRadius: 0, - tension: 0, - borderWidth: 2, - borderColor: '#ff9156', - backgroundColor: alpha('#ff9156', 0.1), - data: [], - }], - }, - options: { - aspectRatio: 3, - layout: { - padding: { - left: 16, - right: 16, - top: 16, - bottom: 0, - }, - }, - legend: { - position: 'bottom', - labels: { - boxWidth: 16, - }, - }, - scales: { - x: { - gridLines: { - display: false, - color: this.gridColor, - zeroLineColor: this.gridColor, - }, - ticks: { - display: false, - }, - }, - y: { - position: 'right', - gridLines: { - display: true, - color: this.gridColor, - zeroLineColor: this.gridColor, - }, - ticks: { - display: false, - }, - }, - }, - tooltips: { - intersect: false, - mode: 'index', - }, - }, - })); - }, - - fetchJobs() { - os.api('admin/queue/deliver-delayed', {}).then(jobs => { - this.jobs = jobs; - }); - }, - - onStats(stats) { - if (this.paused) return; - - const cpu = (stats.cpu * 100).toFixed(0); - const memActive = (stats.mem.active / this.serverInfo.mem.total * 100).toFixed(0); - const memUsed = (stats.mem.used / this.serverInfo.mem.total * 100).toFixed(0); - this.memUsage = stats.mem.active; - - this.chartCpuMem.data.labels.push(''); - this.chartCpuMem.data.datasets[0].data.push(cpu); - this.chartCpuMem.data.datasets[1].data.push(memActive); - this.chartCpuMem.data.datasets[2].data.push(memUsed); - this.chartNet.data.labels.push(''); - this.chartNet.data.datasets[0].data.push(stats.net.rx); - this.chartNet.data.datasets[1].data.push(stats.net.tx); - this.chartDisk.data.labels.push(''); - this.chartDisk.data.datasets[0].data.push(stats.fs.r); - this.chartDisk.data.datasets[1].data.push(stats.fs.w); - if (this.chartCpuMem.data.datasets[0].data.length > 150) { - this.chartCpuMem.data.labels.shift(); - this.chartCpuMem.data.datasets[0].data.shift(); - this.chartCpuMem.data.datasets[1].data.shift(); - this.chartCpuMem.data.datasets[2].data.shift(); - this.chartNet.data.labels.shift(); - this.chartNet.data.datasets[0].data.shift(); - this.chartNet.data.datasets[1].data.shift(); - this.chartDisk.data.labels.shift(); - this.chartDisk.data.datasets[0].data.shift(); - this.chartDisk.data.datasets[1].data.shift(); - } - this.chartCpuMem.update(); - this.chartNet.update(); - this.chartDisk.update(); - }, - - onStatsLog(statsLog) { - for (const stats of [...statsLog].reverse()) { - this.onStats(stats); - } - }, - - bytes, - - number, - - pause() { - this.paused = true; - }, - - resume() { - this.paused = false; - }, - }, -}); -</script> - -<style lang="scss" scoped> -.xhexznfu { - > div:nth-child(2) { - padding: 16px; - border-top: solid 0.5px var(--divider); - } -} -</style> diff --git a/packages/frontend/src/pages/admin/overview.active-users.vue b/packages/frontend/src/pages/admin/overview.active-users.vue index d760d90ef1..14b09f34e9 100644 --- a/packages/frontend/src/pages/admin/overview.active-users.vue +++ b/packages/frontend/src/pages/admin/overview.active-users.vue @@ -12,18 +12,17 @@ import { markRaw, version as vueVersion, onMounted, onBeforeUnmount, nextTick } import { Chart } from 'chart.js'; import { enUS } from 'date-fns/locale'; import tinycolor from 'tinycolor2'; +import gradient from 'chartjs-plugin-gradient'; import * as os from '@/os'; -import 'chartjs-adapter-date-fns'; import { defaultStore } from '@/store'; import { useChartTooltip } from '@/scripts/use-chart-tooltip'; -import gradient from 'chartjs-plugin-gradient'; import { chartVLine } from '@/scripts/chart-vline'; import { alpha } from '@/scripts/color'; import { initChart } from '@/scripts/init-chart'; initChart(); -const chartEl = $ref<HTMLCanvasElement>(null); +const chartEl = $shallowRef<HTMLCanvasElement>(null); const now = new Date(); let chartInstance: Chart = null; const chartLimit = 7; diff --git a/packages/frontend/src/pages/admin/overview.ap-requests.vue b/packages/frontend/src/pages/admin/overview.ap-requests.vue index 5dcb67474f..61a0667080 100644 --- a/packages/frontend/src/pages/admin/overview.ap-requests.vue +++ b/packages/frontend/src/pages/admin/overview.ap-requests.vue @@ -34,8 +34,8 @@ import { initChart } from '@/scripts/init-chart'; initChart(); const chartLimit = 50; -const chartEl = $ref<HTMLCanvasElement>(); -const chartEl2 = $ref<HTMLCanvasElement>(); +const chartEl = $shallowRef<HTMLCanvasElement>(); +const chartEl2 = $shallowRef<HTMLCanvasElement>(); let fetching = $ref(true); const { handler: externalTooltipHandler } = useChartTooltip(); diff --git a/packages/frontend/src/pages/admin/overview.instances.vue b/packages/frontend/src/pages/admin/overview.instances.vue index ae10017aa8..15dbdc4639 100644 --- a/packages/frontend/src/pages/admin/overview.instances.vue +++ b/packages/frontend/src/pages/admin/overview.instances.vue @@ -22,7 +22,7 @@ const fetching = ref(true); const fetch = async () => { const fetchedInstances = await os.api('federation/instances', { - sort: '+lastCommunicatedAt', + sort: '+latestRequestReceivedAt', limit: 6, }); instances.value = fetchedInstances; diff --git a/packages/frontend/src/pages/admin/overview.pie.vue b/packages/frontend/src/pages/admin/overview.pie.vue index b6f0d1b705..416e963356 100644 --- a/packages/frontend/src/pages/admin/overview.pie.vue +++ b/packages/frontend/src/pages/admin/overview.pie.vue @@ -3,7 +3,7 @@ </template> <script lang="ts" setup> -import { onMounted, onUnmounted, ref } from 'vue'; +import { onMounted, onUnmounted, ref, shallowRef } from 'vue'; import { Chart } from 'chart.js'; import number from '@/filters/number'; import { defaultStore } from '@/store'; @@ -16,7 +16,7 @@ const props = defineProps<{ data: { name: string; value: number; color: string; onClick?: () => void }[]; }>(); -const chartEl = ref<HTMLCanvasElement>(null); +const chartEl = shallowRef<HTMLCanvasElement>(null); const { handler: externalTooltipHandler } = useChartTooltip({ position: 'middle', diff --git a/packages/frontend/src/pages/admin/overview.queue.chart.vue b/packages/frontend/src/pages/admin/overview.queue.chart.vue index 1765577d45..0162d53665 100644 --- a/packages/frontend/src/pages/admin/overview.queue.chart.vue +++ b/packages/frontend/src/pages/admin/overview.queue.chart.vue @@ -3,7 +3,7 @@ </template> <script lang="ts" setup> -import { watch, onMounted, onUnmounted, ref } from 'vue'; +import { watch, onMounted, onUnmounted, ref, shallowRef } from 'vue'; import { Chart } from 'chart.js'; import number from '@/filters/number'; import * as os from '@/os'; @@ -19,7 +19,7 @@ const props = defineProps<{ type: string; }>(); -const chartEl = ref<HTMLCanvasElement>(null); +const chartEl = shallowRef<HTMLCanvasElement>(null); const { handler: externalTooltipHandler } = useChartTooltip(); diff --git a/packages/frontend/src/pages/admin/overview.queue.vue b/packages/frontend/src/pages/admin/overview.queue.vue index 72ebddc72f..7e58882938 100644 --- a/packages/frontend/src/pages/admin/overview.queue.vue +++ b/packages/frontend/src/pages/admin/overview.queue.vue @@ -43,10 +43,10 @@ const activeSincePrevTick = ref(0); const active = ref(0); const delayed = ref(0); const waiting = ref(0); -let chartProcess = $ref<InstanceType<typeof XChart>>(); -let chartActive = $ref<InstanceType<typeof XChart>>(); -let chartDelayed = $ref<InstanceType<typeof XChart>>(); -let chartWaiting = $ref<InstanceType<typeof XChart>>(); +let chartProcess = $shallowRef<InstanceType<typeof XChart>>(); +let chartActive = $shallowRef<InstanceType<typeof XChart>>(); +let chartDelayed = $shallowRef<InstanceType<typeof XChart>>(); +let chartWaiting = $shallowRef<InstanceType<typeof XChart>>(); const props = defineProps<{ domain: string; diff --git a/packages/frontend/src/pages/admin/overview.vue b/packages/frontend/src/pages/admin/overview.vue index d656e55200..2e0b49c5a3 100644 --- a/packages/frontend/src/pages/admin/overview.vue +++ b/packages/frontend/src/pages/admin/overview.vue @@ -77,12 +77,11 @@ import * as os from '@/os'; import { stream } from '@/stream'; import { i18n } from '@/i18n'; import { definePageMetadata } from '@/scripts/page-metadata'; -import 'chartjs-adapter-date-fns'; import { defaultStore } from '@/store'; import MkFileListForAdmin from '@/components/MkFileListForAdmin.vue'; import MkFolder from '@/components/MkFolder.vue'; -const rootEl = $ref<HTMLElement>(); +const rootEl = $shallowRef<HTMLElement>(); let serverInfo: any = $ref(null); let topSubInstancesForPie: any = $ref(null); let topPubInstancesForPie: any = $ref(null); @@ -153,7 +152,7 @@ onMounted(async () => { }); os.api('federation/instances', { - sort: '+lastCommunicatedAt', + sort: '+latestRequestReceivedAt', limit: 25, }).then(res => { activeInstances = res; diff --git a/packages/frontend/src/pages/admin/queue.chart.chart.vue b/packages/frontend/src/pages/admin/queue.chart.chart.vue index ae8d9ae4de..a0c05df983 100644 --- a/packages/frontend/src/pages/admin/queue.chart.chart.vue +++ b/packages/frontend/src/pages/admin/queue.chart.chart.vue @@ -3,7 +3,7 @@ </template> <script lang="ts" setup> -import { watch, onMounted, onUnmounted, ref } from 'vue'; +import { watch, onMounted, onUnmounted, ref, shallowRef } from 'vue'; import { Chart } from 'chart.js'; import number from '@/filters/number'; import * as os from '@/os'; @@ -19,7 +19,7 @@ const props = defineProps<{ type: string; }>(); -const chartEl = ref<HTMLCanvasElement>(null); +const chartEl = shallowRef<HTMLCanvasElement>(null); const { handler: externalTooltipHandler } = useChartTooltip(); diff --git a/packages/frontend/src/pages/admin/queue.chart.vue b/packages/frontend/src/pages/admin/queue.chart.vue index 186a22c43e..7f1dc2cd77 100644 --- a/packages/frontend/src/pages/admin/queue.chart.vue +++ b/packages/frontend/src/pages/admin/queue.chart.vue @@ -53,10 +53,10 @@ const active = ref(0); const delayed = ref(0); const waiting = ref(0); const jobs = ref([]); -let chartProcess = $ref<InstanceType<typeof XChart>>(); -let chartActive = $ref<InstanceType<typeof XChart>>(); -let chartDelayed = $ref<InstanceType<typeof XChart>>(); -let chartWaiting = $ref<InstanceType<typeof XChart>>(); +let chartProcess = $shallowRef<InstanceType<typeof XChart>>(); +let chartActive = $shallowRef<InstanceType<typeof XChart>>(); +let chartDelayed = $shallowRef<InstanceType<typeof XChart>>(); +let chartWaiting = $shallowRef<InstanceType<typeof XChart>>(); const props = defineProps<{ domain: string; diff --git a/packages/frontend/src/pages/admin/users.vue b/packages/frontend/src/pages/admin/users.vue index 24ce98a02f..16fa45b1fc 100644 --- a/packages/frontend/src/pages/admin/users.vue +++ b/packages/frontend/src/pages/admin/users.vue @@ -65,7 +65,7 @@ import { definePageMetadata } from '@/scripts/page-metadata'; import MkUserCardMini from '@/components/MkUserCardMini.vue'; import { dateString } from '@/filters/date'; -let paginationComponent = $ref<InstanceType<typeof MkPagination>>(); +let paginationComponent = $shallowRef<InstanceType<typeof MkPagination>>(); let sort = $ref('+createdAt'); let state = $ref('all'); diff --git a/packages/frontend/src/pages/antenna-timeline.vue b/packages/frontend/src/pages/antenna-timeline.vue index 1d5c3aa1d3..af7e95d543 100644 --- a/packages/frontend/src/pages/antenna-timeline.vue +++ b/packages/frontend/src/pages/antenna-timeline.vue @@ -34,8 +34,8 @@ const props = defineProps<{ let antenna = $ref(null); let queue = $ref(0); -let rootEl = $ref<HTMLElement>(); -let tlEl = $ref<InstanceType<typeof XTimeline>>(); +let rootEl = $shallowRef<HTMLElement>(); +let tlEl = $shallowRef<InstanceType<typeof XTimeline>>(); const keymap = $computed(() => ({ 't': focus, })); diff --git a/packages/frontend/src/pages/explore.users.vue b/packages/frontend/src/pages/explore.users.vue index bfee0a6c07..611ca0f003 100644 --- a/packages/frontend/src/pages/explore.users.vue +++ b/packages/frontend/src/pages/explore.users.vue @@ -72,7 +72,7 @@ const props = defineProps<{ }>(); let origin = $ref('local'); -let tagsEl = $ref<InstanceType<typeof MkFolder>>(); +let tagsEl = $shallowRef<InstanceType<typeof MkFolder>>(); let tagsLocal = $ref([]); let tagsRemote = $ref([]); diff --git a/packages/frontend/src/pages/explore.vue b/packages/frontend/src/pages/explore.vue index 3f6c239bc1..4494f6154d 100644 --- a/packages/frontend/src/pages/explore.vue +++ b/packages/frontend/src/pages/explore.vue @@ -51,7 +51,7 @@ const props = withDefaults(defineProps<{ }); let tab = $ref(props.initialTab); -let tagsEl = $ref<InstanceType<typeof MkFolder>>(); +let tagsEl = $shallowRef<InstanceType<typeof MkFolder>>(); let searchQuery = $ref(null); let searchOrigin = $ref('combined'); diff --git a/packages/frontend/src/pages/favorites.vue b/packages/frontend/src/pages/favorites.vue index ab47efec71..7fd660f93b 100644 --- a/packages/frontend/src/pages/favorites.vue +++ b/packages/frontend/src/pages/favorites.vue @@ -2,7 +2,7 @@ <MkStickyContainer> <template #header><MkPageHeader/></template> <MkSpacer :content-max="800"> - <MkPagination ref="pagingComponent" :pagination="pagination"> + <MkPagination :pagination="pagination"> <template #empty> <div class="_fullinfo"> <img src="https://xn--931a.moe/assets/info.jpg" class="_ghost"/> @@ -33,8 +33,6 @@ const pagination = { limit: 10, }; -const pagingComponent = ref<InstanceType<typeof MkPagination>>(); - definePageMetadata({ title: i18n.ts.favorites, icon: 'ti ti-star', diff --git a/packages/frontend/src/pages/follow-requests.vue b/packages/frontend/src/pages/follow-requests.vue index b9d614b356..99401e1fc7 100644 --- a/packages/frontend/src/pages/follow-requests.vue +++ b/packages/frontend/src/pages/follow-requests.vue @@ -35,14 +35,14 @@ </template> <script lang="ts" setup> -import { ref, computed } from 'vue'; +import { shallowRef, computed } from 'vue'; import MkPagination from '@/components/MkPagination.vue'; import { userPage, acct } from '@/filters/user'; import * as os from '@/os'; import { i18n } from '@/i18n'; import { definePageMetadata } from '@/scripts/page-metadata'; -const paginationComponent = ref<InstanceType<typeof MkPagination>>(); +const paginationComponent = shallowRef<InstanceType<typeof MkPagination>>(); const pagination = { endpoint: 'following/requests/list' as const, diff --git a/packages/frontend/src/pages/instance-info.vue b/packages/frontend/src/pages/instance-info.vue index f750fdcee2..55771b0e30 100644 --- a/packages/frontend/src/pages/instance-info.vue +++ b/packages/frontend/src/pages/instance-info.vue @@ -40,14 +40,6 @@ <template #key>{{ i18n.ts.updatedAt }}</template> <template #value><MkTime mode="detail" :time="instance.infoUpdatedAt"/></template> </MkKeyValue> - <MkKeyValue oneline style="margin: 1em 0;"> - <template #key>{{ i18n.ts.latestRequestSentAt }}</template> - <template #value><MkTime v-if="instance.latestRequestSentAt" :time="instance.latestRequestSentAt"/><span v-else>N/A</span></template> - </MkKeyValue> - <MkKeyValue oneline style="margin: 1em 0;"> - <template #key>{{ i18n.ts.latestStatus }}</template> - <template #value>{{ instance.latestStatus ? instance.latestStatus : 'N/A' }}</template> - </MkKeyValue> <MkKeyValue oneline style="margin: 1em 0;"> <template #key>{{ i18n.ts.latestRequestReceivedAt }}</template> <template #value><MkTime v-if="instance.latestRequestReceivedAt" :time="instance.latestRequestReceivedAt"/><span v-else>N/A</span></template> diff --git a/packages/frontend/src/pages/messaging/messaging-room.form.vue b/packages/frontend/src/pages/messaging/messaging-room.form.vue index 84572815c0..2c54c6f71f 100644 --- a/packages/frontend/src/pages/messaging/messaging-room.form.vue +++ b/packages/frontend/src/pages/messaging/messaging-room.form.vue @@ -46,8 +46,8 @@ const props = defineProps<{ group?: Misskey.entities.UserGroup | null; }>(); -let textEl = $ref<HTMLTextAreaElement>(); -let fileEl = $ref<HTMLInputElement>(); +let textEl = $shallowRef<HTMLTextAreaElement>(); +let fileEl = $shallowRef<HTMLInputElement>(); let text = $ref<string>(''); let file = $ref<Misskey.entities.DriveFile | null>(null); diff --git a/packages/frontend/src/pages/messaging/messaging-room.vue b/packages/frontend/src/pages/messaging/messaging-room.vue index 280e6a903b..f0a36fb8b1 100644 --- a/packages/frontend/src/pages/messaging/messaging-room.vue +++ b/packages/frontend/src/pages/messaging/messaging-room.vue @@ -71,9 +71,9 @@ const props = defineProps<{ groupId?: string; }>(); -let rootEl = $ref<HTMLDivElement>(); -let formEl = $ref<InstanceType<typeof XForm>>(); -let pagingComponent = $ref<InstanceType<typeof MkPagination>>(); +let rootEl = $shallowRef<HTMLDivElement>(); +let formEl = $shallowRef<InstanceType<typeof XForm>>(); +let pagingComponent = $shallowRef<InstanceType<typeof MkPagination>>(); let fetching = $ref(true); let user: Misskey.entities.UserDetailed | null = $ref(null); diff --git a/packages/frontend/src/pages/my-clips/index.vue b/packages/frontend/src/pages/my-clips/index.vue index dd6b5b3a37..6c0508134f 100644 --- a/packages/frontend/src/pages/my-clips/index.vue +++ b/packages/frontend/src/pages/my-clips/index.vue @@ -29,7 +29,7 @@ const pagination = { limit: 10, }; -const pagingComponent = $ref<InstanceType<typeof MkPagination>>(); +const pagingComponent = $shallowRef<InstanceType<typeof MkPagination>>(); async function create() { const { canceled, result } = await os.form(i18n.ts.createNewClip, { diff --git a/packages/frontend/src/pages/my-lists/index.vue b/packages/frontend/src/pages/my-lists/index.vue index 3476436b27..510e0173df 100644 --- a/packages/frontend/src/pages/my-lists/index.vue +++ b/packages/frontend/src/pages/my-lists/index.vue @@ -25,7 +25,7 @@ import * as os from '@/os'; import { i18n } from '@/i18n'; import { definePageMetadata } from '@/scripts/page-metadata'; -const pagingComponent = $ref<InstanceType<typeof MkPagination>>(); +const pagingComponent = $shallowRef<InstanceType<typeof MkPagination>>(); const pagination = { endpoint: 'users/lists/list' as const, diff --git a/packages/frontend/src/pages/scratchpad.vue b/packages/frontend/src/pages/scratchpad.vue index edb2d8e18c..9db17efc03 100644 --- a/packages/frontend/src/pages/scratchpad.vue +++ b/packages/frontend/src/pages/scratchpad.vue @@ -27,7 +27,7 @@ import 'prismjs/components/prism-javascript'; import 'prismjs/themes/prism-okaidia.css'; import { PrismEditor } from 'vue-prism-editor'; import 'vue-prism-editor/dist/prismeditor.min.css'; -import { AiScript, parse, utils } from '@syuilo/aiscript'; +import { Interpreter, Parser, utils } from '@syuilo/aiscript'; import MkContainer from '@/components/MkContainer.vue'; import MkButton from '@/components/MkButton.vue'; import { createAiScriptEnv } from '@/scripts/aiscript/api'; @@ -36,6 +36,8 @@ import { $i } from '@/account'; import { i18n } from '@/i18n'; import { definePageMetadata } from '@/scripts/page-metadata'; +const parser = new Parser(); + const code = ref(''); const logs = ref<any[]>([]); @@ -50,7 +52,7 @@ watch(code, () => { async function run() { logs.value = []; - const aiscript = new AiScript(createAiScriptEnv({ + const aiscript = new Interpreter(createAiScriptEnv({ storageKey: 'scratchpad', token: $i?.token, }), { @@ -84,7 +86,7 @@ async function run() { let ast; try { - ast = parse(code.value); + ast = parser.parse(code.value); } catch (error) { os.alert({ type: 'error', diff --git a/packages/frontend/src/pages/settings/general.vue b/packages/frontend/src/pages/settings/general.vue index 84d99d2fd7..b426ccfa0a 100644 --- a/packages/frontend/src/pages/settings/general.vue +++ b/packages/frontend/src/pages/settings/general.vue @@ -27,7 +27,6 @@ <FormSwitch v-model="imageNewTab" class="_formBlock">{{ i18n.ts.openImageInNewTab }}</FormSwitch> <FormSwitch v-model="enableInfiniteScroll" class="_formBlock">{{ i18n.ts.enableInfiniteScroll }}</FormSwitch> <FormSwitch v-model="useReactionPickerForContextMenu" class="_formBlock">{{ i18n.ts.useReactionPickerForContextMenu }}</FormSwitch> - <FormSwitch v-model="disablePagesScript" class="_formBlock">{{ i18n.ts.disablePagesScript }}</FormSwitch> <FormSelect v-model="serverDisconnectedBehavior" class="_formBlock"> <template #label>{{ i18n.ts.whenServerDisconnected }}</template> @@ -141,7 +140,6 @@ const disableShowingAnimatedImages = computed(defaultStore.makeGetterSetter('dis const loadRawImages = computed(defaultStore.makeGetterSetter('loadRawImages')); const imageNewTab = computed(defaultStore.makeGetterSetter('imageNewTab')); const nsfw = computed(defaultStore.makeGetterSetter('nsfw')); -const disablePagesScript = computed(defaultStore.makeGetterSetter('disablePagesScript')); const showFixedPostForm = computed(defaultStore.makeGetterSetter('showFixedPostForm')); const numberOfPageCache = computed(defaultStore.makeGetterSetter('numberOfPageCache')); const instanceTicker = computed(defaultStore.makeGetterSetter('instanceTicker')); diff --git a/packages/frontend/src/pages/settings/index.vue b/packages/frontend/src/pages/settings/index.vue index 9517e3a5c8..119a75b650 100644 --- a/packages/frontend/src/pages/settings/index.vue +++ b/packages/frontend/src/pages/settings/index.vue @@ -22,7 +22,7 @@ </template> <script setup lang="ts"> -import { computed, defineAsyncComponent, inject, nextTick, onActivated, onMounted, onUnmounted, provide, ref, watch } from 'vue'; +import { computed, defineAsyncComponent, inject, nextTick, onActivated, onMounted, onUnmounted, provide, ref, shallowRef, watch } from 'vue'; import { i18n } from '@/i18n'; import MkInfo from '@/components/MkInfo.vue'; import MkSuperMenu from '@/components/MkSuperMenu.vue'; @@ -40,7 +40,7 @@ const indexInfo = { hideHeader: true, }; const INFO = ref(indexInfo); -const el = ref<HTMLElement | null>(null); +const el = shallowRef<HTMLElement | null>(null); const childInfo = ref(null); const router = useRouter(); diff --git a/packages/frontend/src/pages/settings/notifications.vue b/packages/frontend/src/pages/settings/notifications.vue index e85fede157..c1b7130245 100644 --- a/packages/frontend/src/pages/settings/notifications.vue +++ b/packages/frontend/src/pages/settings/notifications.vue @@ -34,7 +34,7 @@ import { i18n } from '@/i18n'; import { definePageMetadata } from '@/scripts/page-metadata'; import MkPushNotificationAllowButton from '@/components/MkPushNotificationAllowButton.vue'; -let allowButton = $ref<InstanceType<typeof MkPushNotificationAllowButton>>(); +let allowButton = $shallowRef<InstanceType<typeof MkPushNotificationAllowButton>>(); let pushRegistrationInServer = $computed(() => allowButton?.pushRegistrationInServer); let sendReadMessage = $computed(() => pushRegistrationInServer?.sendReadMessage || false); diff --git a/packages/frontend/src/pages/settings/plugin.install.vue b/packages/frontend/src/pages/settings/plugin.install.vue index 550bba242e..40ad9a95dd 100644 --- a/packages/frontend/src/pages/settings/plugin.install.vue +++ b/packages/frontend/src/pages/settings/plugin.install.vue @@ -14,8 +14,7 @@ <script lang="ts" setup> import { defineAsyncComponent, nextTick, ref } from 'vue'; -import { AiScript, parse } from '@syuilo/aiscript'; -import { serialize } from '@syuilo/aiscript/built/serializer'; +import { Interpreter, Parser, utils } from '@syuilo/aiscript'; import { v4 as uuid } from 'uuid'; import FormTextarea from '@/components/form/textarea.vue'; import FormButton from '@/components/MkButton.vue'; @@ -26,23 +25,41 @@ import { unisonReload } from '@/scripts/unison-reload'; import { i18n } from '@/i18n'; import { definePageMetadata } from '@/scripts/page-metadata'; +const parser = new Parser(); const code = ref(null); -function installPlugin({ id, meta, ast, token }) { +function installPlugin({ id, meta, src, token }) { ColdDeviceStorage.set('plugins', ColdDeviceStorage.get('plugins').concat({ ...meta, id, active: true, configData: {}, token: token, - ast: ast, + src: src, })); } async function install() { + if (code.value == null) return; + + const lv = utils.getLangVersion(code.value); + if (lv == null) { + os.alert({ + type: 'error', + text: 'No language version annotation found :(', + }); + return; + } else if (lv !== '0.12.0') { + os.alert({ + type: 'error', + text: `aiscript version '${lv}' is not supported :(`, + }); + return; + } + let ast; try { - ast = parse(code.value); + ast = parser.parse(code.value); } catch (err) { os.alert({ type: 'error', @@ -51,7 +68,7 @@ async function install() { return; } - const meta = AiScript.collectMetadata(ast); + const meta = Interpreter.collectMetadata(ast); if (meta == null) { os.alert({ type: 'error', @@ -103,7 +120,7 @@ async function install() { name, version, author, description, permissions, config, }, token, - ast: serialize(ast), + src: code.value, }); os.success(); diff --git a/packages/frontend/src/pages/settings/preferences-backups.vue b/packages/frontend/src/pages/settings/preferences-backups.vue index 8b7548f25b..a713c1262d 100644 --- a/packages/frontend/src/pages/settings/preferences-backups.vue +++ b/packages/frontend/src/pages/settings/preferences-backups.vue @@ -62,7 +62,6 @@ const defaultStoreSaveKeys: (keyof typeof defaultStore['state'])[] = [ 'loadRawImages', 'imageNewTab', 'disableShowingAnimatedImages', - 'disablePagesScript', 'emojiStyle', 'disableDrawer', 'useBlurEffectForModal', diff --git a/packages/frontend/src/pages/timeline.vue b/packages/frontend/src/pages/timeline.vue index fbbe43f2c0..75f62d38f7 100644 --- a/packages/frontend/src/pages/timeline.vue +++ b/packages/frontend/src/pages/timeline.vue @@ -41,8 +41,8 @@ const keymap = { 't': focus, }; -const tlComponent = $ref<InstanceType<typeof XTimeline>>(); -const rootEl = $ref<HTMLElement>(); +const tlComponent = $shallowRef<InstanceType<typeof XTimeline>>(); +const rootEl = $shallowRef<HTMLElement>(); let queue = $ref(0); const src = $computed({ get: () => defaultStore.reactiveState.tl.value.src, set: (x) => saveSrc(x) }); diff --git a/packages/frontend/src/pages/user-list-timeline.vue b/packages/frontend/src/pages/user-list-timeline.vue index a223dee319..542c280594 100644 --- a/packages/frontend/src/pages/user-list-timeline.vue +++ b/packages/frontend/src/pages/user-list-timeline.vue @@ -34,8 +34,8 @@ const props = defineProps<{ let list = $ref(null); let queue = $ref(0); -let tlEl = $ref<InstanceType<typeof XTimeline>>(); -let rootEl = $ref<HTMLElement>(); +let tlEl = $shallowRef<InstanceType<typeof XTimeline>>(); +let rootEl = $shallowRef<HTMLElement>(); watch(() => props.listId, async () => { list = await os.api('users/lists/show', { diff --git a/packages/frontend/src/pages/user/activity.heatmap.vue b/packages/frontend/src/pages/user/activity.heatmap.vue index 000653ea5c..252985d113 100644 --- a/packages/frontend/src/pages/user/activity.heatmap.vue +++ b/packages/frontend/src/pages/user/activity.heatmap.vue @@ -14,7 +14,6 @@ import { enUS } from 'date-fns/locale'; import tinycolor from 'tinycolor2'; import * as misskey from 'misskey-js'; import * as os from '@/os'; -import 'chartjs-adapter-date-fns'; import { defaultStore } from '@/store'; import { useChartTooltip } from '@/scripts/use-chart-tooltip'; import { chartVLine } from '@/scripts/chart-vline'; @@ -28,8 +27,8 @@ const props = defineProps<{ user: misskey.entities.User; }>(); -const rootEl = $ref<HTMLDivElement>(null); -const chartEl = $ref<HTMLCanvasElement>(null); +const rootEl = $shallowRef<HTMLDivElement>(null); +const chartEl = $shallowRef<HTMLCanvasElement>(null); const now = new Date(); let chartInstance: Chart = null; let fetching = $ref(true); diff --git a/packages/frontend/src/pages/user/activity.pv.vue b/packages/frontend/src/pages/user/activity.pv.vue index 25d708e71a..7715b66673 100644 --- a/packages/frontend/src/pages/user/activity.pv.vue +++ b/packages/frontend/src/pages/user/activity.pv.vue @@ -3,6 +3,7 @@ <MkLoading v-if="fetching"/> <div v-show="!fetching" :class="$style.root" class="_panel"> <canvas ref="chartEl"></canvas> + <MkChartLegend ref="legendEl" style="margin-top: 8px;"/> </div> </div> </template> @@ -13,14 +14,15 @@ import { Chart } from 'chart.js'; import { enUS } from 'date-fns/locale'; import tinycolor from 'tinycolor2'; import * as misskey from 'misskey-js'; +import gradient from 'chartjs-plugin-gradient'; import * as os from '@/os'; -import 'chartjs-adapter-date-fns'; import { defaultStore } from '@/store'; import { useChartTooltip } from '@/scripts/use-chart-tooltip'; -import gradient from 'chartjs-plugin-gradient'; import { chartVLine } from '@/scripts/chart-vline'; import { alpha } from '@/scripts/color'; import { initChart } from '@/scripts/init-chart'; +import { chartLegend } from '@/scripts/chart-legend'; +import MkChartLegend from '@/components/MkChartLegend.vue'; initChart(); @@ -28,7 +30,8 @@ const props = defineProps<{ user: misskey.entities.User; }>(); -const chartEl = $ref<HTMLCanvasElement>(null); +const chartEl = $shallowRef<HTMLCanvasElement>(null); +let legendEl = $shallowRef<InstanceType<typeof MkChartLegend>>(); const now = new Date(); let chartInstance: Chart = null; const chartLimit = 30; @@ -154,14 +157,7 @@ async function renderChart() { }, }, legend: { - display: true, - position: 'bottom', - padding: { - left: 0, - right: 0, - top: 8, - bottom: 0, - }, + display: false, }, tooltip: { enabled: false, @@ -174,7 +170,7 @@ async function renderChart() { gradient, }, }, - plugins: [chartVLine(vLineColor)], + plugins: [chartVLine(vLineColor), chartLegend(legendEl)], }); fetching = false; diff --git a/packages/frontend/src/plugin.ts b/packages/frontend/src/plugin.ts index 3a00cd0455..c19fe2b08d 100644 --- a/packages/frontend/src/plugin.ts +++ b/packages/frontend/src/plugin.ts @@ -1,16 +1,17 @@ -import { AiScript, utils, values } from '@syuilo/aiscript'; -import { deserialize } from '@syuilo/aiscript/built/serializer'; -import { jsToVal } from '@syuilo/aiscript/built/interpreter/util'; +import { Interpreter, Parser, utils, values } from '@syuilo/aiscript'; import { createAiScriptEnv } from '@/scripts/aiscript/api'; import { inputText } from '@/os'; import { noteActions, notePostInterruptors, noteViewInterruptors, postFormActions, userActions } from '@/store'; -const pluginContexts = new Map<string, AiScript>(); +const parser = new Parser(); +const pluginContexts = new Map<string, Interpreter>(); export function install(plugin) { + // 後方互換性のため + if (plugin.src == null) return; console.info('Plugin installed:', plugin.name, 'v' + plugin.version); - const aiscript = new AiScript(createPluginEnv({ + const aiscript = new Interpreter(createPluginEnv({ plugin: plugin, storageKey: 'plugins:' + plugin.id, }), { @@ -32,13 +33,13 @@ export function install(plugin) { initPlugin({ plugin, aiscript }); - aiscript.exec(deserialize(plugin.ast)); + aiscript.exec(parser.parse(plugin.src)); } function createPluginEnv(opts) { const config = new Map(); for (const [k, v] of Object.entries(opts.plugin.config || {})) { - config.set(k, jsToVal(typeof opts.plugin.configData[k] !== 'undefined' ? opts.plugin.configData[k] : v.default)); + config.set(k, utils.jsToVal(typeof opts.plugin.configData[k] !== 'undefined' ? opts.plugin.configData[k] : v.default)); } return { diff --git a/packages/frontend/src/scripts/chart-legend.ts b/packages/frontend/src/scripts/chart-legend.ts new file mode 100644 index 0000000000..6a5370cc87 --- /dev/null +++ b/packages/frontend/src/scripts/chart-legend.ts @@ -0,0 +1,12 @@ +import { Plugin } from 'chart.js'; +import MkChartLegend from '@/components/MkChartLegend.vue'; + +export const chartLegend = (legend: InstanceType<typeof MkChartLegend>) => ({ + id: 'htmlLegend', + afterUpdate(chart, args, options) { + // Reuse the built-in legendItems generator + const items = chart.options.plugins.legend.labels.generateLabels(chart); + + legend.update(chart, items); + }, +}) as Plugin; diff --git a/packages/frontend/src/scripts/chart-vline.ts b/packages/frontend/src/scripts/chart-vline.ts index 10021583e0..f321443834 100644 --- a/packages/frontend/src/scripts/chart-vline.ts +++ b/packages/frontend/src/scripts/chart-vline.ts @@ -1,3 +1,5 @@ +import { Plugin } from 'chart.js'; + export const chartVLine = (vLineColor: string) => ({ id: 'vLine', beforeDraw(chart, args, options) { @@ -18,4 +20,4 @@ export const chartVLine = (vLineColor: string) => ({ ctx.restore(); } }, -}); +}) as Plugin; diff --git a/packages/frontend/src/scripts/hpml/evaluator.ts b/packages/frontend/src/scripts/hpml/evaluator.ts index 196b3142a1..d4090ea15c 100644 --- a/packages/frontend/src/scripts/hpml/evaluator.ts +++ b/packages/frontend/src/scripts/hpml/evaluator.ts @@ -1,13 +1,11 @@ import autobind from 'autobind-decorator'; -import { PageVar, envVarsDef, Fn, HpmlScope, HpmlError } from '.'; -import { version } from '@/config'; -import { AiScript, utils, values } from '@syuilo/aiscript'; -import { createAiScriptEnv } from '../aiscript/api'; +import { markRaw, ref, Ref, unref } from 'vue'; import { collectPageVars } from '../collect-page-vars'; import { initHpmlLib, initAiLib } from './lib'; -import * as os from '@/os'; -import { markRaw, ref, Ref, unref } from 'vue'; import { Expr, isLiteralValue, Variable } from './expr'; +import { PageVar, envVarsDef, Fn, HpmlScope, HpmlError } from '.'; +import { version } from '@/config'; +import * as os from '@/os'; /** * Hpml evaluator @@ -16,7 +14,6 @@ export class Hpml { private variables: Variable[]; private pageVars: PageVar[]; private envVars: Record<keyof typeof envVarsDef, any>; - public aiscript?: AiScript; public pageVarUpdatedCallback?: values.VFn; public canvases: Record<string, HTMLCanvasElement> = {}; public vars: Ref<Record<string, any>> = ref({}); @@ -24,7 +21,6 @@ export class Hpml { private opts: { randomSeed: string; visitor?: any; url?: string; - enableAiScript: boolean; }; constructor(page: Hpml['page'], opts: Hpml['opts']) { @@ -33,31 +29,6 @@ export class Hpml { this.pageVars = collectPageVars(this.page.content); this.opts = opts; - if (this.opts.enableAiScript) { - this.aiscript = markRaw(new AiScript({ ...createAiScriptEnv({ - storageKey: 'pages:' + this.page.id, - }), ...initAiLib(this) }, { - in: (q) => { - return new Promise(ok => { - os.inputText({ - title: q, - }).then(({ canceled, result: a }) => { - ok(a); - }); - }); - }, - out: (value) => { - console.log(value); - }, - log: (type, params) => { - }, - })); - - this.aiscript.scope.opts.onUpdated = (name, value) => { - this.eval(); - }; - } - const date = new Date(); this.envVars = { @@ -74,7 +45,7 @@ export class Hpml { IS_CAT: opts.visitor ? opts.visitor.isCat : false, SEED: opts.randomSeed ? opts.randomSeed : '', YMD: `${date.getFullYear()}/${date.getMonth() + 1}/${date.getDate()}`, - AISCRIPT_DISABLED: !this.opts.enableAiScript, + AISCRIPT_DISABLED: true, NULL: null, }; @@ -99,13 +70,6 @@ export class Hpml { }); } - @autobind - public callAiScript(fn: string) { - try { - if (this.aiscript) this.aiscript.execFn(this.aiscript.scope.get(fn), []); - } catch (err) {} - } - @autobind public registerCanvas(id: string, canvas: any) { this.canvases[id] = canvas; @@ -116,9 +80,6 @@ export class Hpml { const pageVar = this.pageVars.find(v => v.name === name); if (pageVar !== undefined) { pageVar.value = value; - if (this.pageVarUpdatedCallback) { - if (this.aiscript) this.aiscript.execFn(this.pageVarUpdatedCallback, [values.STR(name), utils.jsToVal(value)]); - } } else { throw new HpmlError(`No such page var '${name}'`); } @@ -180,18 +141,6 @@ export class Hpml { return scope.getState(expr.value); } - if (expr.type === 'aiScriptVar') { - if (this.aiscript) { - try { - return utils.valToJs(this.aiscript.scope.get(expr.value)); - } catch (err) { - return null; - } - } else { - return null; - } - } - // Define user function if (expr.type === 'fn') { return { diff --git a/packages/frontend/src/scripts/hpml/lib.ts b/packages/frontend/src/scripts/hpml/lib.ts index b684876a7f..02d663b31b 100644 --- a/packages/frontend/src/scripts/hpml/lib.ts +++ b/packages/frontend/src/scripts/hpml/lib.ts @@ -1,9 +1,8 @@ import tinycolor from 'tinycolor2'; -import { Hpml } from './evaluator'; -import { values, utils } from '@syuilo/aiscript'; -import { Fn, HpmlScope } from '.'; -import { Expr } from './expr'; import seedrandom from 'seedrandom'; +import { Hpml } from './evaluator'; +import { Expr } from './expr'; +import { Fn, HpmlScope } from '.'; /* TODO: https://www.chartjs.org/docs/latest/configuration/canvas-background.html#color // https://stackoverflow.com/questions/38493564/chart-area-background-color-chartjs diff --git a/packages/frontend/src/scripts/init-chart.ts b/packages/frontend/src/scripts/init-chart.ts index 005ac5e271..fc18869009 100644 --- a/packages/frontend/src/scripts/init-chart.ts +++ b/packages/frontend/src/scripts/init-chart.ts @@ -20,6 +20,7 @@ import gradient from 'chartjs-plugin-gradient'; import zoomPlugin from 'chartjs-plugin-zoom'; import { MatrixController, MatrixElement } from 'chartjs-chart-matrix'; import { defaultStore } from '@/store'; +import 'chartjs-adapter-date-fns'; export function initChart() { Chart.register( diff --git a/packages/frontend/src/store.ts b/packages/frontend/src/store.ts index 8e3e6b36da..4b1f47c2bc 100644 --- a/packages/frontend/src/store.ts +++ b/packages/frontend/src/store.ts @@ -170,10 +170,6 @@ export const defaultStore = markRaw(new Storage('base', { where: 'device', default: false, }, - disablePagesScript: { - where: 'device', - default: false, - }, emojiStyle: { where: 'device', default: 'twemoji', // twemoji / fluentEmoji / native diff --git a/packages/frontend/src/ui/_common_/statusbar-federation.vue b/packages/frontend/src/ui/_common_/statusbar-federation.vue index 7c3de32ac9..70d683d755 100644 --- a/packages/frontend/src/ui/_common_/statusbar-federation.vue +++ b/packages/frontend/src/ui/_common_/statusbar-federation.vue @@ -44,7 +44,7 @@ let key = $ref(0); const tick = () => { os.api('federation/instances', { - sort: '+lastCommunicatedAt', + sort: '+latestRequestReceivedAt', limit: 30, }).then(res => { instances.value = res; diff --git a/packages/frontend/src/ui/classic.vue b/packages/frontend/src/ui/classic.vue index 6369bb8976..280e69e7dd 100644 --- a/packages/frontend/src/ui/classic.vue +++ b/packages/frontend/src/ui/classic.vue @@ -64,7 +64,7 @@ let fullView = $ref(false); let globalHeaderHeight = $ref(0); const wallpaper = localStorage.getItem('wallpaper') != null; const showMenuOnTop = $computed(() => defaultStore.state.menuDisplay === 'top'); -let live2d = $ref<HTMLIFrameElement>(); +let live2d = $shallowRef<HTMLIFrameElement>(); let widgetsLeft = $ref(); let widgetsRight = $ref(); @@ -76,7 +76,7 @@ provideMetadataReceiver((info) => { } }); provide('shouldHeaderThin', showMenuOnTop); -provide('shouldSpacerMin', true); +provide('forceSpacerMin', true); function attachSticky(el) { const sticky = new StickySidebar(el, defaultStore.state.menuDisplay === 'top' ? 0 : 16, defaultStore.state.menuDisplay === 'top' ? 60 : 0); // TODO: ヘッダーの高さを60pxと決め打ちしているのを直す diff --git a/packages/frontend/src/ui/deck.vue b/packages/frontend/src/ui/deck.vue index 6efb2ce290..b0306ab832 100644 --- a/packages/frontend/src/ui/deck.vue +++ b/packages/frontend/src/ui/deck.vue @@ -125,7 +125,7 @@ function showSettings() { os.pageWindow('/settings/deck'); } -let columnsEl = $ref<HTMLElement>(); +let columnsEl = $shallowRef<HTMLElement>(); const addColumn = async (ev) => { const columns = [ diff --git a/packages/frontend/src/ui/deck/antenna-column.vue b/packages/frontend/src/ui/deck/antenna-column.vue index ba14530662..53d744676c 100644 --- a/packages/frontend/src/ui/deck/antenna-column.vue +++ b/packages/frontend/src/ui/deck/antenna-column.vue @@ -26,7 +26,7 @@ const emit = defineEmits<{ (ev: 'parent-focus', direction: 'up' | 'down' | 'left' | 'right'): void; }>(); -let timeline = $ref<InstanceType<typeof XTimeline>>(); +let timeline = $shallowRef<InstanceType<typeof XTimeline>>(); onMounted(() => { if (props.column.antennaId == null) { diff --git a/packages/frontend/src/ui/deck/column.vue b/packages/frontend/src/ui/deck/column.vue index 5de5528b1d..775bdf6c1e 100644 --- a/packages/frontend/src/ui/deck/column.vue +++ b/packages/frontend/src/ui/deck/column.vue @@ -40,7 +40,7 @@ import { MenuItem } from '@/types/menu'; provide('shouldHeaderThin', true); provide('shouldOmitHeaderTitle', true); -provide('shouldSpacerMin', true); +provide('forceSpacerMin', true); const props = withDefaults(defineProps<{ column: Column; @@ -59,7 +59,7 @@ const emit = defineEmits<{ (ev: 'change-active-state', v: boolean): void; }>(); -let body = $ref<HTMLDivElement>(); +let body = $shallowRef<HTMLDivElement>(); let dragging = $ref(false); watch($$(dragging), v => os.deckGlobalEvents.emit(v ? 'column.dragStart' : 'column.dragEnd')); diff --git a/packages/frontend/src/ui/deck/list-column.vue b/packages/frontend/src/ui/deck/list-column.vue index d9f3f7b4e7..e31446ebb2 100644 --- a/packages/frontend/src/ui/deck/list-column.vue +++ b/packages/frontend/src/ui/deck/list-column.vue @@ -26,7 +26,7 @@ const emit = defineEmits<{ (ev: 'parent-focus', direction: 'up' | 'down' | 'left' | 'right'): void; }>(); -let timeline = $ref<InstanceType<typeof XTimeline>>(); +let timeline = $shallowRef<InstanceType<typeof XTimeline>>(); if (props.column.listId == null) { setList(); diff --git a/packages/frontend/src/ui/universal.vue b/packages/frontend/src/ui/universal.vue index 865616f192..9e1fee5b6b 100644 --- a/packages/frontend/src/ui/universal.vue +++ b/packages/frontend/src/ui/universal.vue @@ -86,7 +86,7 @@ window.addEventListener('resize', () => { }); let pageMetadata = $ref<null | ComputedRef<PageMetadata>>(); -const widgetsEl = $ref<HTMLElement>(); +const widgetsEl = $shallowRef<HTMLElement>(); const widgetsShowing = $ref(false); provide('router', mainRouter); @@ -287,7 +287,7 @@ const wallpaper = localStorage.getItem('wallpaper') != null; z-index: 1000; bottom: 0; left: 0; - padding: 12px 12px max(12px, calc(env(safe-area-inset-bottom, 0px) + 8px)) 12px; + padding: 12px 12px max(12px, env(safe-area-inset-bottom, 0px)) 12px; display: grid; grid-template-columns: 1fr 1fr 1fr 1fr 1fr; grid-gap: 8px; @@ -333,6 +333,11 @@ const wallpaper = localStorage.getItem('wallpaper') != null; opacity: 0.5; } } + + &.post { + background: linear-gradient(90deg, var(--buttonGradateA), var(--buttonGradateB)); + color: var(--fgOnAccent); + } } } diff --git a/packages/frontend/src/ui/universal.widgets.vue b/packages/frontend/src/ui/universal.widgets.vue index 35de23ebfa..d4210f6988 100644 --- a/packages/frontend/src/ui/universal.widgets.vue +++ b/packages/frontend/src/ui/universal.widgets.vue @@ -31,7 +31,7 @@ const emit = defineEmits<{ (ev: 'mounted', el?: Element): void; }>(); -let rootEl = $ref<HTMLDivElement>(); +let rootEl = $shallowRef<HTMLDivElement>(); const widgets = $computed(() => { if (props.place === null) return defaultStore.reactiveState.widgets.value; diff --git a/packages/frontend/src/widgets/aichan.vue b/packages/frontend/src/widgets/aichan.vue index 828490fd9c..ab5b375ae4 100644 --- a/packages/frontend/src/widgets/aichan.vue +++ b/packages/frontend/src/widgets/aichan.vue @@ -5,7 +5,7 @@ </template> <script lang="ts" setup> -import { onMounted, onUnmounted, reactive, ref } from 'vue'; +import { onMounted, onUnmounted, reactive, ref, shallowRef } from 'vue'; import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget'; import { GetFormResultType } from '@/scripts/form'; @@ -32,7 +32,7 @@ const { widgetProps, configure } = useWidgetPropsManager(name, emit, ); -const live2d = ref<HTMLIFrameElement>(); +const live2d = shallowRef<HTMLIFrameElement>(); const touched = () => { //if (this.live2d) this.live2d.changeExpression('gurugurume'); diff --git a/packages/frontend/src/widgets/aiscript.vue b/packages/frontend/src/widgets/aiscript.vue index 4009edb8b8..dcc73db201 100644 --- a/packages/frontend/src/widgets/aiscript.vue +++ b/packages/frontend/src/widgets/aiscript.vue @@ -14,7 +14,7 @@ <script lang="ts" setup> import { onMounted, onUnmounted, ref, watch } from 'vue'; -import { AiScript, parse, utils } from '@syuilo/aiscript'; +import { Interpreter, Parser, utils } from '@syuilo/aiscript'; import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget'; import { GetFormResultType } from '@/scripts/form'; import * as os from '@/os'; @@ -52,6 +52,8 @@ const { widgetProps, configure } = useWidgetPropsManager(name, emit, ); +const parser = new Parser(); + const logs = ref<{ id: string; text: string; @@ -60,7 +62,7 @@ const logs = ref<{ const run = async () => { logs.value = []; - const aiscript = new AiScript(createAiScriptEnv({ + const aiscript = new Interpreter(createAiScriptEnv({ storageKey: 'widget', token: $i?.token, }), { @@ -94,7 +96,7 @@ const run = async () => { let ast; try { - ast = parse(widgetProps.script); + ast = parser.parse(widgetProps.script); } catch (err) { os.alert({ type: 'error', diff --git a/packages/frontend/src/widgets/button.vue b/packages/frontend/src/widgets/button.vue index f0148d7f4e..f65b115cc0 100644 --- a/packages/frontend/src/widgets/button.vue +++ b/packages/frontend/src/widgets/button.vue @@ -8,7 +8,7 @@ <script lang="ts" setup> import { onMounted, onUnmounted, ref, watch } from 'vue'; -import { AiScript, parse, utils } from '@syuilo/aiscript'; +import { Interpreter, Parser, utils } from '@syuilo/aiscript'; import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget'; import { GetFormResultType } from '@/scripts/form'; import * as os from '@/os'; @@ -48,8 +48,10 @@ const { widgetProps, configure } = useWidgetPropsManager(name, emit, ); +const parser = new Parser(); + const run = async () => { - const aiscript = new AiScript(createAiScriptEnv({ + const aiscript = new Interpreter(createAiScriptEnv({ storageKey: 'widget', token: $i?.token, }), { @@ -72,7 +74,7 @@ const run = async () => { let ast; try { - ast = parse(widgetProps.script); + ast = parser.parse(widgetProps.script); } catch (err) { os.alert({ type: 'error', diff --git a/packages/frontend/src/widgets/federation.vue b/packages/frontend/src/widgets/federation.vue index 221972bc6f..a701ca5673 100644 --- a/packages/frontend/src/widgets/federation.vue +++ b/packages/frontend/src/widgets/federation.vue @@ -58,7 +58,7 @@ const fetching = ref(true); const fetch = async () => { const fetchedInstances = await os.api('federation/instances', { - sort: '+lastCommunicatedAt', + sort: '+latestRequestReceivedAt', limit: 5, }); const fetchedCharts = await Promise.all(fetchedInstances.map(i => os.apiGet('charts/instance', { host: i.host, limit: 16, span: 'hour' }))); diff --git a/packages/frontend/src/widgets/instance-cloud.vue b/packages/frontend/src/widgets/instance-cloud.vue index 4965616995..1068c5ac4b 100644 --- a/packages/frontend/src/widgets/instance-cloud.vue +++ b/packages/frontend/src/widgets/instance-cloud.vue @@ -45,7 +45,7 @@ const { widgetProps, configure } = useWidgetPropsManager(name, emit, ); -let cloud = $ref<InstanceType<typeof MkTagCloud> | null>(); +let cloud = $shallowRef<InstanceType<typeof MkTagCloud> | null>(); let activeInstances = $shallowRef(null); function onInstanceClick(i) { @@ -54,7 +54,7 @@ function onInstanceClick(i) { useInterval(() => { os.api('federation/instances', { - sort: '+lastCommunicatedAt', + sort: '+latestRequestReceivedAt', limit: 25, }).then(res => { activeInstances = res; diff --git a/packages/frontend/src/widgets/slideshow.vue b/packages/frontend/src/widgets/slideshow.vue index e317b8ab94..2c937d85c5 100644 --- a/packages/frontend/src/widgets/slideshow.vue +++ b/packages/frontend/src/widgets/slideshow.vue @@ -12,7 +12,7 @@ </template> <script lang="ts" setup> -import { nextTick, onMounted, onUnmounted, reactive, ref } from 'vue'; +import { nextTick, onMounted, onUnmounted, reactive, ref, shallowRef } from 'vue'; import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget'; import { GetFormResultType } from '@/scripts/form'; import * as os from '@/os'; @@ -49,8 +49,8 @@ const { widgetProps, configure, save } = useWidgetPropsManager(name, const images = ref([]); const fetching = ref(true); -const slideA = ref<HTMLElement>(); -const slideB = ref<HTMLElement>(); +const slideA = shallowRef<HTMLElement>(); +const slideB = shallowRef<HTMLElement>(); const change = () => { if (images.value.length === 0) return; diff --git a/yarn.lock b/yarn.lock index 54f9f9c0bf..9eaf29f1b3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1973,16 +1973,15 @@ __metadata: languageName: node linkType: hard -"@syuilo/aiscript@npm:0.11.1": - version: 0.11.1 - resolution: "@syuilo/aiscript@npm:0.11.1" +"@syuilo/aiscript@npm:0.12.0": + version: 0.12.0 + resolution: "@syuilo/aiscript@npm:0.12.0" dependencies: autobind-decorator: 2.4.0 - chalk: 4.0.0 seedrandom: 3.0.5 stringz: 2.1.0 - uuid: 7.0.3 - checksum: c5e15045abdf1393f1da9c58f25dd301bd2b6c5808f2ca58334e5d488c227b189ec5200ec86326ed381380a9ff76dbc05fd30882f562383be76b83dc4fabb11b + uuid: 8.3.2 + checksum: 82b52a6c602a8c3090b9457a0e9de99898b03cd8f054855b2f57439534257ef2780013a53eaeeef68c9893d96d3ec02fc6d0ede56396c2bcf054cf43b2297b67 languageName: node linkType: hard @@ -4136,7 +4135,6 @@ __metadata: "@sinonjs/fake-timers": 10.0.2 "@swc/core": 1.3.24 "@swc/jest": 0.2.24 - "@syuilo/aiscript": 0.11.1 "@tensorflow/tfjs": ^4.1.0 "@tensorflow/tfjs-node": 4.1.0 "@types/accepts": 1.3.5 @@ -4870,16 +4868,6 @@ __metadata: languageName: node linkType: hard -"chalk@npm:4.0.0": - version: 4.0.0 - resolution: "chalk@npm:4.0.0" - dependencies: - ansi-styles: ^4.1.0 - supports-color: ^7.1.0 - checksum: a9580afd4af8ffa8add8edb565d1b3f77efb880c5d887d3bb72a948d1bfb2bc764db2ceb6d62a60103aa384f3da71eb1969c7f68e886055e0a3438550e809cde - languageName: node - linkType: hard - "chalk@npm:5.2.0": version: 5.2.0 resolution: "chalk@npm:5.2.0" @@ -8039,7 +8027,7 @@ __metadata: "@rollup/plugin-alias": 4.0.2 "@rollup/plugin-json": 6.0.0 "@rollup/pluginutils": 5.0.2 - "@syuilo/aiscript": 0.11.1 + "@syuilo/aiscript": 0.12.0 "@tabler/icons": ^1.118.0 "@types/escape-regexp": 0.0.1 "@types/glob": 8.0.0 @@ -16916,15 +16904,6 @@ __metadata: languageName: node linkType: hard -"uuid@npm:7.0.3": - version: 7.0.3 - resolution: "uuid@npm:7.0.3" - bin: - uuid: dist/bin/uuid - checksum: f5b7b5cc28accac68d5c083fd51cca64896639ebd4cca88c6cfb363801aaa83aa439c86dfc8446ea250a7a98d17afd2ad9e88d9d4958c79a412eccb93bae29de - languageName: node - linkType: hard - "uuid@npm:8.0.0": version: 8.0.0 resolution: "uuid@npm:8.0.0" @@ -16934,6 +16913,15 @@ __metadata: languageName: node linkType: hard +"uuid@npm:8.3.2, uuid@npm:^8.3.0, uuid@npm:^8.3.2": + version: 8.3.2 + resolution: "uuid@npm:8.3.2" + bin: + uuid: dist/bin/uuid + checksum: 5575a8a75c13120e2f10e6ddc801b2c7ed7d8f3c8ac22c7ed0c7b2ba6383ec0abda88c905085d630e251719e0777045ae3236f04c812184b7c765f63a70e58df + languageName: node + linkType: hard + "uuid@npm:9.0.0": version: 9.0.0 resolution: "uuid@npm:9.0.0" @@ -16952,15 +16940,6 @@ __metadata: languageName: node linkType: hard -"uuid@npm:^8.3.0, uuid@npm:^8.3.2": - version: 8.3.2 - resolution: "uuid@npm:8.3.2" - bin: - uuid: dist/bin/uuid - checksum: 5575a8a75c13120e2f10e6ddc801b2c7ed7d8f3c8ac22c7ed0c7b2ba6383ec0abda88c905085d630e251719e0777045ae3236f04c812184b7c765f63a70e58df - languageName: node - linkType: hard - "v8-to-istanbul@npm:^9.0.1": version: 9.0.1 resolution: "v8-to-istanbul@npm:9.0.1"