Merge remote-branch 'misskey/develop'

This commit is contained in:
NoriDev 2023-11-23 16:03:31 +09:00
commit c9a4f543ba
98 changed files with 1354 additions and 610 deletions

View file

@ -5,19 +5,35 @@
- -
### Client ### Client
- - Fix: ページ一覧ページの表示がモバイル環境において崩れているのを修正
### Server ### Server
- -
--> -->
## 2023.x.x (unreleased)
### General
- Feat: メールアドレスの認証にverifymail.ioを使えるように (cherry-pick from https://github.com/TeamNijimiss/misskey/commit/971ba07a44550f68d2ba31c62066db2d43a0caed)
- Feat: モデレーターがユーザーのアイコンもしくはバナー画像を未設定状態にできる機能を追加 (cherry-pick from https://github.com/TeamNijimiss/misskey/commit/e0eb5a752f6e5616d6312bb7c9790302f9dbff83)
### Client
- fix: 「設定のバックアップ」で一部の項目がバックアップに含まれていなかった問題を修正
- Fix: ウィジェットのジョブキューにて音声の発音方法変更に追従できていなかったのを修正 #12367
### Server
- Fix: 時間経過により無効化されたアンテナを再有効化したとき、サーバ再起動までその状況が反映されないのを修正 #12303
- Fix: ロールタイムラインが保存されない問題を修正
- Fix: api.jsonの生成ロジックを改善 #12402
## 2023.11.1 ## 2023.11.1
### General ### General
- Feat: 管理者がコントロールパネルからメールアドレスの照会を行えるようになりました - Feat: 管理者がコントロールパネルからメールアドレスの照会を行えるようになりました
- Enhance: ローカリゼーションの更新 - Enhance: ローカリゼーションの更新
- Enhance: 依存関係の更新 - Enhance: 依存関係の更新
- Enhance: json-schema(OpenAPIの戻り値として使用されるスキーマ定義)を出来る限り最新化 #12311
### Client ### Client
- Enhance: MFMでルビを振れるように - Enhance: MFMでルビを振れるように

View file

@ -651,6 +651,10 @@ output: "Output"
script: "Script" script: "Script"
disablePagesScript: "Disable AiScript on Pages" disablePagesScript: "Disable AiScript on Pages"
updateRemoteUser: "Update remote user information" updateRemoteUser: "Update remote user information"
unsetUserAvatar: "Delete user icon"
unsetUserAvatarConfirm: "Are you sure that you want to delete this user's icon?"
unsetUserBanner: "Delete user banner"
unsetUserBannerConfirm: "Are you sure that you want to delete this user's banner?"
deleteAllFiles: "Delete all files" deleteAllFiles: "Delete all files"
deleteAllFilesConfirm: "Are you sure that you want to delete all files?" deleteAllFilesConfirm: "Are you sure that you want to delete all files?"
removeAllFollowing: "Unfollow all followed users" removeAllFollowing: "Unfollow all followed users"

6
locales/index.d.ts vendored
View file

@ -654,6 +654,10 @@ export interface Locale {
"script": string; "script": string;
"disablePagesScript": string; "disablePagesScript": string;
"updateRemoteUser": string; "updateRemoteUser": string;
"unsetUserAvatar": string;
"unsetUserAvatarConfirm": string;
"unsetUserBanner": string;
"unsetUserBannerConfirm": string;
"deleteAllFiles": string; "deleteAllFiles": string;
"deleteAllFilesConfirm": string; "deleteAllFilesConfirm": string;
"removeAllFollowing": string; "removeAllFollowing": string;
@ -2724,6 +2728,8 @@ export interface Locale {
"createAvatarDecoration": string; "createAvatarDecoration": string;
"updateAvatarDecoration": string; "updateAvatarDecoration": string;
"deleteAvatarDecoration": string; "deleteAvatarDecoration": string;
"unsetUserAvatar": string;
"unsetUserBanner": string;
}; };
"_fileViewer": { "_fileViewer": {
"title": string; "title": string;

View file

@ -651,6 +651,10 @@ output: "出力"
script: "スクリプト" script: "スクリプト"
disablePagesScript: "Pagesのスクリプトを無効にする" disablePagesScript: "Pagesのスクリプトを無効にする"
updateRemoteUser: "リモートユーザー情報の更新" updateRemoteUser: "リモートユーザー情報の更新"
unsetUserAvatar: "アイコンを解除"
unsetUserAvatarConfirm: "アイコンを解除しますか?"
unsetUserBanner: "バナーを解除"
unsetUserBannerConfirm: "バナーを解除しますか?"
deleteAllFiles: "すべてのファイルを削除" deleteAllFiles: "すべてのファイルを削除"
deleteAllFilesConfirm: "すべてのファイルを削除しますか?" deleteAllFilesConfirm: "すべてのファイルを削除しますか?"
removeAllFollowing: "フォローを全解除" removeAllFollowing: "フォローを全解除"
@ -2622,6 +2626,8 @@ _moderationLogTypes:
createAvatarDecoration: "アイコンデコレーションを作成" createAvatarDecoration: "アイコンデコレーションを作成"
updateAvatarDecoration: "アイコンデコレーションを更新" updateAvatarDecoration: "アイコンデコレーションを更新"
deleteAvatarDecoration: "アイコンデコレーションを削除" deleteAvatarDecoration: "アイコンデコレーションを削除"
unsetUserAvatar: "ユーザーのアイコンを解除"
unsetUserBanner: "ユーザーのバナーを解除"
_fileViewer: _fileViewer:
title: "ファイルの詳細" title: "ファイルの詳細"

View file

@ -53,7 +53,7 @@
"js-yaml": "4.1.0", "js-yaml": "4.1.0",
"postcss": "8.4.31", "postcss": "8.4.31",
"terser": "5.24.0", "terser": "5.24.0",
"typescript": "5.2.2" "typescript": "5.3.2"
}, },
"devDependencies": { "devDependencies": {
"@typescript-eslint/eslint-plugin": "6.11.0", "@typescript-eslint/eslint-plugin": "6.11.0",

View file

@ -0,0 +1,8 @@
import { loadConfig } from './built/config.js'
import { genOpenapiSpec } from './built/server/api/openapi/gen-spec.js'
import { writeFileSync } from "node:fs";
const config = loadConfig();
const spec = genOpenapiSpec(config);
writeFileSync('./built/api.json', JSON.stringify(spec), 'utf-8');

View file

@ -0,0 +1,18 @@
/*
* SPDX-FileCopyrightText: syuilo and other misskey, cherrypick contributors
* SPDX-License-Identifier: AGPL-3.0-only
*/
export class SupportVerifyMailApi1700303245007 {
name = 'SupportVerifyMailApi1700303245007'
async up(queryRunner) {
await queryRunner.query(`ALTER TABLE "meta" ADD "verifymailAuthKey" character varying(1024)`);
await queryRunner.query(`ALTER TABLE "meta" ADD "enableVerifymailApi" boolean NOT NULL DEFAULT false`);
}
async down(queryRunner) {
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "enableVerifymailApi"`);
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "verifymailAuthKey"`);
}
}

View file

@ -7,8 +7,8 @@
"node": ">=18.16.0" "node": ">=18.16.0"
}, },
"scripts": { "scripts": {
"start": "node ./built/index.js", "start": "node ./built/boot/entry.js",
"start:test": "NODE_ENV=test node ./built/index.js", "start:test": "NODE_ENV=test node ./built/boot/entry.js",
"migrate": "pnpm typeorm migration:run -d ormconfig.js", "migrate": "pnpm typeorm migration:run -d ormconfig.js",
"revert": "pnpm typeorm migration:revert -d ormconfig.js", "revert": "pnpm typeorm migration:revert -d ormconfig.js",
"check:connect": "node ./check_connect.js", "check:connect": "node ./check_connect.js",
@ -24,6 +24,7 @@
"jest-clear": "cross-env NODE_ENV=test node --experimental-vm-modules --experimental-import-meta-resolve node_modules/jest/bin/jest.js --clearCache", "jest-clear": "cross-env NODE_ENV=test node --experimental-vm-modules --experimental-import-meta-resolve node_modules/jest/bin/jest.js --clearCache",
"test": "pnpm jest", "test": "pnpm jest",
"test-and-coverage": "pnpm jest-and-coverage", "test-and-coverage": "pnpm jest-and-coverage",
"generate-api-json": "node ./generate_api_json.js",
"schema:sync": "pnpm typeorm schema:sync -d ormconfig.js" "schema:sync": "pnpm typeorm schema:sync -d ormconfig.js"
}, },
"optionalDependencies": { "optionalDependencies": {
@ -170,7 +171,7 @@
"tsconfig-paths": "4.2.0", "tsconfig-paths": "4.2.0",
"twemoji-parser": "14.0.0", "twemoji-parser": "14.0.0",
"typeorm": "0.3.17", "typeorm": "0.3.17",
"typescript": "5.2.2", "typescript": "5.3.2",
"ulid": "2.3.0", "ulid": "2.3.0",
"vary": "1.1.2", "vary": "1.1.2",
"web-push": "3.6.6", "web-push": "3.6.6",

View file

@ -63,11 +63,21 @@ export class AntennaService implements OnApplicationShutdown {
lastUsedAt: new Date(body.lastUsedAt), lastUsedAt: new Date(body.lastUsedAt),
}); });
break; break;
case 'antennaUpdated': case 'antennaUpdated': {
this.antennas[this.antennas.findIndex(a => a.id === body.id)] = { const idx = this.antennas.findIndex(a => a.id === body.id);
if (idx >= 0) {
this.antennas[idx] = {
...body, ...body,
lastUsedAt: new Date(body.lastUsedAt), lastUsedAt: new Date(body.lastUsedAt),
}; };
} else {
// サーバ起動時にactiveじゃなかった場合、リストに持っていないので追加する必要あり
this.antennas.push({
...body,
lastUsedAt: new Date(body.lastUsedAt),
});
}
}
break; break;
case 'antennaDeleted': case 'antennaDeleted':
this.antennas = this.antennas.filter(a => a.id !== body.id); this.antennas = this.antennas.filter(a => a.id !== body.id);

View file

@ -3,9 +3,11 @@
* SPDX-License-Identifier: AGPL-3.0-only * SPDX-License-Identifier: AGPL-3.0-only
*/ */
import { URLSearchParams } from 'node:url';
import * as nodemailer from 'nodemailer'; import * as nodemailer from 'nodemailer';
import { Inject, Injectable } from '@nestjs/common'; import { Inject, Injectable } from '@nestjs/common';
import { validate as validateEmail } from 'deep-email-validator'; import { validate as validateEmail } from 'deep-email-validator';
import { SubOutputFormat } from 'deep-email-validator/dist/output/output.js';
import { MetaService } from '@/core/MetaService.js'; import { MetaService } from '@/core/MetaService.js';
import { DI } from '@/di-symbols.js'; import { DI } from '@/di-symbols.js';
import type { Config } from '@/config.js'; import type { Config } from '@/config.js';
@ -13,6 +15,7 @@ import type Logger from '@/logger.js';
import type { UserProfilesRepository } from '@/models/_.js'; import type { UserProfilesRepository } from '@/models/_.js';
import { LoggerService } from '@/core/LoggerService.js'; import { LoggerService } from '@/core/LoggerService.js';
import { bindThis } from '@/decorators.js'; import { bindThis } from '@/decorators.js';
import { HttpRequestService } from '@/core/HttpRequestService.js';
@Injectable() @Injectable()
export class EmailService { export class EmailService {
@ -27,6 +30,7 @@ export class EmailService {
private metaService: MetaService, private metaService: MetaService,
private loggerService: LoggerService, private loggerService: LoggerService,
private httpRequestService: HttpRequestService,
) { ) {
this.logger = this.loggerService.getLogger('email'); this.logger = this.loggerService.getLogger('email');
} }
@ -160,7 +164,14 @@ export class EmailService {
email: emailAddress, email: emailAddress,
}); });
const validated = meta.enableActiveEmailValidation ? await validateEmail({ const verifymailApi = meta.enableVerifymailApi && meta.verifymailAuthKey != null;
let validated;
if (meta.enableActiveEmailValidation && meta.verifymailAuthKey) {
if (verifymailApi) {
validated = await this.verifyMail(emailAddress, meta.verifymailAuthKey);
} else {
validated = meta.enableActiveEmailValidation ? await validateEmail({
email: emailAddress, email: emailAddress,
validateRegex: true, validateRegex: true,
validateMx: true, validateMx: true,
@ -168,6 +179,10 @@ export class EmailService {
validateDisposable: true, // 捨てアドかどうかチェック validateDisposable: true, // 捨てアドかどうかチェック
validateSMTP: false, // 日本だと25ポートが殆どのプロバイダーで塞がれていてタイムアウトになるので validateSMTP: false, // 日本だと25ポートが殆どのプロバイダーで塞がれていてタイムアウトになるので
}) : { valid: true, reason: null }; }) : { valid: true, reason: null };
}
} else {
validated = { valid: true, reason: null };
}
const available = exist === 0 && validated.valid; const available = exist === 0 && validated.valid;
@ -182,4 +197,65 @@ export class EmailService {
null, null,
}; };
} }
private async verifyMail(emailAddress: string, verifymailAuthKey: string): Promise<{
valid: boolean;
reason: 'used' | 'format' | 'disposable' | 'mx' | 'smtp' | null;
}> {
const endpoint = 'https://verifymail.io/api/' + emailAddress + '?key=' + verifymailAuthKey;
const res = await this.httpRequestService.send(endpoint, {
method: 'GET',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
Accept: 'application/json, */*',
},
});
const json = (await res.json()) as {
block: boolean;
catch_all: boolean;
deliverable_email: boolean;
disposable: boolean;
domain: string;
email_address: string;
email_provider: string;
mx: boolean;
mx_fallback: boolean;
mx_host: string[];
mx_ip: string[];
mx_priority: { [key: string]: number };
privacy: boolean;
related_domains: string[];
};
if (json.email_address === undefined) {
return {
valid: false,
reason: 'format',
};
}
if (json.deliverable_email !== undefined && !json.deliverable_email) {
return {
valid: false,
reason: 'smtp',
};
}
if (json.disposable) {
return {
valid: false,
reason: 'disposable',
};
}
if (json.mx !== undefined && !json.mx) {
return {
valid: false,
reason: 'mx',
};
}
return {
valid: true,
reason: null,
};
}
} }

View file

@ -89,6 +89,9 @@ export class RoleService implements OnApplicationShutdown {
@Inject(DI.redis) @Inject(DI.redis)
private redisClient: Redis.Redis, private redisClient: Redis.Redis,
@Inject(DI.redisForTimelines)
private redisForTimelines: Redis.Redis,
@Inject(DI.redisForSub) @Inject(DI.redisForSub)
private redisForSub: Redis.Redis, private redisForSub: Redis.Redis,
@ -479,7 +482,7 @@ export class RoleService implements OnApplicationShutdown {
public async addNoteToRoleTimeline(note: Packed<'Note'>): Promise<void> { public async addNoteToRoleTimeline(note: Packed<'Note'>): Promise<void> {
const roles = await this.getUserRoles(note.userId); const roles = await this.getUserRoles(note.userId);
const redisPipeline = this.redisClient.pipeline(); const redisPipeline = this.redisForTimelines.pipeline();
for (const role of roles) { for (const role of roles) {
this.funoutTimelineService.push(`roleTimeline:${role.id}`, note.id, 1000, redisPipeline); this.funoutTimelineService.push(`roleTimeline:${role.id}`, note.id, 1000, redisPipeline);

View file

@ -222,12 +222,14 @@ export class NotificationEntityService implements OnModuleInit {
}); });
} else if (notification.type === 'renote:grouped') { } else if (notification.type === 'renote:grouped') {
const users = await Promise.all(notification.userIds.map(userId => { const users = await Promise.all(notification.userIds.map(userId => {
const user = hint?.packedUsers != null const packedUser = hint?.packedUsers != null ? hint.packedUsers.get(userId) : null;
? hint.packedUsers.get(userId) if (packedUser) {
: this.userEntityService.pack(userId!, { id: meId }, { return packedUser;
}
return this.userEntityService.pack(userId, { id: meId }, {
detail: false, detail: false,
}); });
return user;
})); }));
return await awaitAll({ return await awaitAll({
id: notification.id, id: notification.id,

View file

@ -559,6 +559,17 @@ export class MiMeta {
}) })
public enableActiveEmailValidation: boolean; public enableActiveEmailValidation: boolean;
@Column('boolean', {
default: false,
})
public enableVerifymailApi: boolean;
@Column('varchar', {
length: 1024,
nullable: true,
})
public verifymailAuthKey: string | null;
@Column('boolean', { @Column('boolean', {
default: true, default: true,
}) })

View file

@ -42,11 +42,15 @@ export const packedAnnouncementSchema = {
type: 'string', type: 'string',
optional: false, nullable: false, optional: false, nullable: false,
}, },
forYou: { needConfirmationToRead: {
type: 'boolean', type: 'boolean',
optional: false, nullable: false, optional: false, nullable: false,
}, },
needConfirmationToRead: { silence: {
type: 'boolean',
optional: false, nullable: false,
},
forYou: {
type: 'boolean', type: 'boolean',
optional: false, nullable: false, optional: false, nullable: false,
}, },

View file

@ -19,7 +19,7 @@ export const packedChannelSchema = {
}, },
lastNotedAt: { lastNotedAt: {
type: 'string', type: 'string',
optional: false, nullable: true, nullable: true, optional: false,
format: 'date-time', format: 'date-time',
}, },
name: { name: {
@ -28,38 +28,18 @@ export const packedChannelSchema = {
}, },
description: { description: {
type: 'string', type: 'string',
nullable: true, optional: false, optional: false, nullable: true,
},
bannerUrl: {
type: 'string',
format: 'url',
nullable: true, optional: false,
},
isArchived: {
type: 'boolean',
optional: false, nullable: false,
},
notesCount: {
type: 'number',
nullable: false, optional: false,
},
usersCount: {
type: 'number',
nullable: false, optional: false,
},
isFollowing: {
type: 'boolean',
optional: true, nullable: false,
},
isFavorited: {
type: 'boolean',
optional: true, nullable: false,
}, },
userId: { userId: {
type: 'string', type: 'string',
nullable: true, optional: false, nullable: true, optional: false,
format: 'id', format: 'id',
}, },
bannerUrl: {
type: 'string',
format: 'url',
nullable: true, optional: false,
},
pinnedNoteIds: { pinnedNoteIds: {
type: 'array', type: 'array',
nullable: false, optional: false, nullable: false, optional: false,
@ -72,6 +52,18 @@ export const packedChannelSchema = {
type: 'string', type: 'string',
optional: false, nullable: false, optional: false, nullable: false,
}, },
isArchived: {
type: 'boolean',
optional: false, nullable: false,
},
usersCount: {
type: 'number',
nullable: false, optional: false,
},
notesCount: {
type: 'number',
nullable: false, optional: false,
},
isSensitive: { isSensitive: {
type: 'boolean', type: 'boolean',
optional: false, nullable: false, optional: false, nullable: false,
@ -80,5 +72,22 @@ export const packedChannelSchema = {
type: 'boolean', type: 'boolean',
optional: false, nullable: false, optional: false, nullable: false,
}, },
isFollowing: {
type: 'boolean',
optional: true, nullable: false,
},
isFavorited: {
type: 'boolean',
optional: true, nullable: false,
},
pinnedNotes: {
type: 'array',
optional: true, nullable: false,
items: {
type: 'object',
optional: false, nullable: false,
ref: 'Note',
},
},
}, },
} as const; } as const;

View file

@ -44,13 +44,13 @@ export const packedClipSchema = {
type: 'boolean', type: 'boolean',
optional: false, nullable: false, optional: false, nullable: false,
}, },
isFavorited: {
type: 'boolean',
optional: true, nullable: false,
},
favoritedCount: { favoritedCount: {
type: 'number', type: 'number',
optional: false, nullable: false, optional: false, nullable: false,
}, },
isFavorited: {
type: 'boolean',
optional: true, nullable: false,
},
}, },
} as const; } as const;

View file

@ -74,7 +74,7 @@ export const packedDriveFileSchema = {
}, },
url: { url: {
type: 'string', type: 'string',
optional: false, nullable: true, optional: false, nullable: false,
format: 'url', format: 'url',
}, },
thumbnailUrl: { thumbnailUrl: {

View file

@ -21,6 +21,12 @@ export const packedDriveFolderSchema = {
type: 'string', type: 'string',
optional: false, nullable: false, optional: false, nullable: false,
}, },
parentId: {
type: 'string',
optional: false, nullable: true,
format: 'id',
example: 'xxxxxxxxxx',
},
foldersCount: { foldersCount: {
type: 'number', type: 'number',
optional: true, nullable: false, optional: true, nullable: false,
@ -29,12 +35,6 @@ export const packedDriveFolderSchema = {
type: 'number', type: 'number',
optional: true, nullable: false, optional: true, nullable: false,
}, },
parentId: {
type: 'string',
optional: false, nullable: true,
format: 'id',
example: 'xxxxxxxxxx',
},
parent: { parent: {
type: 'object', type: 'object',
optional: true, nullable: true, optional: true, nullable: true,

View file

@ -79,6 +79,10 @@ export const packedFederationInstanceSchema = {
type: 'string', type: 'string',
optional: false, nullable: true, optional: false, nullable: true,
}, },
isSilenced: {
type: 'boolean',
optional: false, nullable: false,
},
iconUrl: { iconUrl: {
type: 'string', type: 'string',
optional: false, nullable: true, optional: false, nullable: true,
@ -93,11 +97,6 @@ export const packedFederationInstanceSchema = {
type: 'string', type: 'string',
optional: false, nullable: true, optional: false, nullable: true,
}, },
isSilenced: {
type: 'boolean',
optional: false,
nullable: false,
},
infoUpdatedAt: { infoUpdatedAt: {
type: 'string', type: 'string',
optional: false, nullable: true, optional: false, nullable: true,

View file

@ -22,6 +22,16 @@ export const packedFlashSchema = {
optional: false, nullable: false, optional: false, nullable: false,
format: 'date-time', format: 'date-time',
}, },
userId: {
type: 'string',
optional: false, nullable: false,
format: 'id',
},
user: {
type: 'object',
ref: 'UserLite',
optional: false, nullable: false,
},
title: { title: {
type: 'string', type: 'string',
optional: false, nullable: false, optional: false, nullable: false,
@ -34,16 +44,6 @@ export const packedFlashSchema = {
type: 'string', type: 'string',
optional: false, nullable: false, optional: false, nullable: false,
}, },
userId: {
type: 'string',
optional: false, nullable: false,
format: 'id',
},
user: {
type: 'object',
ref: 'UserLite',
optional: false, nullable: false,
},
likedCount: { likedCount: {
type: 'number', type: 'number',
optional: false, nullable: true, optional: false, nullable: true,

View file

@ -22,16 +22,16 @@ export const packedFollowingSchema = {
optional: false, nullable: false, optional: false, nullable: false,
format: 'id', format: 'id',
}, },
followee: {
type: 'object',
optional: true, nullable: false,
ref: 'UserDetailed',
},
followerId: { followerId: {
type: 'string', type: 'string',
optional: false, nullable: false, optional: false, nullable: false,
format: 'id', format: 'id',
}, },
followee: {
type: 'object',
optional: true, nullable: false,
ref: 'UserDetailed',
},
follower: { follower: {
type: 'object', type: 'object',
optional: true, nullable: false, optional: true, nullable: false,

View file

@ -22,14 +22,6 @@ export const packedGalleryPostSchema = {
optional: false, nullable: false, optional: false, nullable: false,
format: 'date-time', format: 'date-time',
}, },
title: {
type: 'string',
optional: false, nullable: false,
},
description: {
type: 'string',
optional: false, nullable: true,
},
userId: { userId: {
type: 'string', type: 'string',
optional: false, nullable: false, optional: false, nullable: false,
@ -40,6 +32,14 @@ export const packedGalleryPostSchema = {
ref: 'UserLite', ref: 'UserLite',
optional: false, nullable: false, optional: false, nullable: false,
}, },
title: {
type: 'string',
optional: false, nullable: false,
},
description: {
type: 'string',
optional: false, nullable: true,
},
fileIds: { fileIds: {
type: 'array', type: 'array',
optional: true, nullable: false, optional: true, nullable: false,
@ -70,5 +70,13 @@ export const packedGalleryPostSchema = {
type: 'boolean', type: 'boolean',
optional: false, nullable: false, optional: false, nullable: false,
}, },
likedCount: {
type: 'number',
optional: false, nullable: false,
},
isLiked: {
type: 'boolean',
optional: true, nullable: false,
},
}, },
} as const; } as const;

View file

@ -149,9 +149,6 @@ export const packedNoteSchema = {
channel: { channel: {
type: 'object', type: 'object',
optional: true, nullable: true, optional: true, nullable: true,
items: {
type: 'object',
optional: false, nullable: false,
properties: { properties: {
id: { id: {
type: 'string', type: 'string',
@ -159,12 +156,19 @@ export const packedNoteSchema = {
}, },
name: { name: {
type: 'string', type: 'string',
optional: false, nullable: true, optional: false, nullable: false,
},
color: {
type: 'string',
optional: false, nullable: false,
}, },
isSensitive: { isSensitive: {
type: 'boolean', type: 'boolean',
optional: true, nullable: false, optional: false, nullable: false,
}, },
allowRenoteToExternal: {
type: 'boolean',
optional: false, nullable: false,
}, },
}, },
}, },

View file

@ -42,13 +42,9 @@ export const packedNotificationSchema = {
type: 'string', type: 'string',
optional: true, nullable: true, optional: true, nullable: true,
}, },
choice: { achievement: {
type: 'number', type: 'string',
optional: true, nullable: true, optional: true, nullable: false,
},
invitation: {
type: 'object',
optional: true, nullable: true,
}, },
body: { body: {
type: 'string', type: 'string',
@ -81,7 +77,6 @@ export const packedNotificationSchema = {
required: ['user', 'reaction'], required: ['user', 'reaction'],
}, },
}, },
},
users: { users: {
type: 'array', type: 'array',
optional: true, nullable: true, optional: true, nullable: true,
@ -91,4 +86,5 @@ export const packedNotificationSchema = {
optional: false, nullable: false, optional: false, nullable: false,
}, },
}, },
},
} as const; } as const;

View file

@ -22,6 +22,32 @@ export const packedPageSchema = {
optional: false, nullable: false, optional: false, nullable: false,
format: 'date-time', format: 'date-time',
}, },
userId: {
type: 'string',
optional: false, nullable: false,
format: 'id',
},
user: {
type: 'object',
ref: 'UserLite',
optional: false, nullable: false,
},
content: {
type: 'array',
optional: false, nullable: false,
items: {
type: 'object',
optional: false, nullable: false,
},
},
variables: {
type: 'array',
optional: false, nullable: false,
items: {
type: 'object',
optional: false, nullable: false,
},
},
title: { title: {
type: 'string', type: 'string',
optional: false, nullable: false, optional: false, nullable: false,
@ -34,23 +60,47 @@ export const packedPageSchema = {
type: 'string', type: 'string',
optional: false, nullable: true, optional: false, nullable: true,
}, },
content: { hideTitleWhenPinned: {
type: 'array', type: 'boolean',
optional: false, nullable: false, optional: false, nullable: false,
}, },
variables: { alignCenter: {
type: 'array', type: 'boolean',
optional: false, nullable: false, optional: false, nullable: false,
}, },
userId: { font: {
type: 'string', type: 'string',
optional: false, nullable: false, optional: false, nullable: false,
format: 'id',
}, },
user: { script: {
type: 'object', type: 'string',
ref: 'UserLite',
optional: false, nullable: false, optional: false, nullable: false,
}, },
eyeCatchingImageId: {
type: 'string',
optional: false, nullable: true,
},
eyeCatchingImage: {
type: 'object',
optional: false, nullable: true,
ref: 'DriveFile',
},
attachedFiles: {
type: 'array',
optional: false, nullable: false,
items: {
type: 'object',
optional: false, nullable: false,
ref: 'DriveFile',
},
},
likedCount: {
type: 'number',
optional: false, nullable: false,
},
isLiked: {
type: 'boolean',
optional: true, nullable: false,
},
}, },
} as const; } as const;

View file

@ -49,11 +49,6 @@ export const packedUserLiteSchema = {
nullable: false, optional: false, nullable: false, optional: false,
format: 'id', format: 'id',
}, },
url: {
type: 'string',
format: 'url',
nullable: false, optional: false,
},
angle: { angle: {
type: 'number', type: 'number',
nullable: false, optional: true, nullable: false, optional: true,
@ -62,18 +57,13 @@ export const packedUserLiteSchema = {
type: 'boolean', type: 'boolean',
nullable: false, optional: true, nullable: false, optional: true,
}, },
url: {
type: 'string',
format: 'url',
nullable: false, optional: false,
}, },
}, },
}, },
isAdmin: {
type: 'boolean',
nullable: false, optional: true,
default: false,
},
isModerator: {
type: 'boolean',
nullable: false, optional: true,
default: false,
}, },
isBot: { isBot: {
type: 'boolean', type: 'boolean',
@ -83,12 +73,67 @@ export const packedUserLiteSchema = {
type: 'boolean', type: 'boolean',
nullable: false, optional: true, nullable: false, optional: true,
}, },
instance: {
type: 'object',
nullable: false, optional: true,
properties: {
name: {
type: 'string',
nullable: true, optional: false,
},
softwareName: {
type: 'string',
nullable: true, optional: false,
},
softwareVersion: {
type: 'string',
nullable: true, optional: false,
},
iconUrl: {
type: 'string',
nullable: true, optional: false,
},
faviconUrl: {
type: 'string',
nullable: true, optional: false,
},
themeColor: {
type: 'string',
nullable: true, optional: false,
},
},
},
emojis: {
type: 'object',
nullable: false, optional: false,
},
onlineStatus: { onlineStatus: {
type: 'string', type: 'string',
format: 'url', nullable: false, optional: false,
nullable: true, optional: false,
enum: ['unknown', 'online', 'active', 'offline'], enum: ['unknown', 'online', 'active', 'offline'],
}, },
badgeRoles: {
type: 'array',
nullable: false, optional: true,
items: {
type: 'object',
nullable: false, optional: false,
properties: {
name: {
type: 'string',
nullable: false, optional: false,
},
iconUrl: {
type: 'string',
nullable: true, optional: false,
},
displayOrder: {
type: 'number',
nullable: false, optional: false,
},
},
},
},
}, },
} as const; } as const;
@ -105,21 +150,18 @@ export const packedUserDetailedNotMeOnlySchema = {
format: 'uri', format: 'uri',
nullable: true, optional: false, nullable: true, optional: false,
}, },
movedToUri: { movedTo: {
type: 'string', type: 'string',
format: 'uri', format: 'uri',
nullable: true, nullable: true, optional: false,
optional: false,
}, },
alsoKnownAs: { alsoKnownAs: {
type: 'array', type: 'array',
nullable: true, nullable: true, optional: false,
optional: false,
items: { items: {
type: 'string', type: 'string',
format: 'id', format: 'id',
nullable: false, nullable: false, optional: false,
optional: false,
}, },
}, },
createdAt: { createdAt: {
@ -249,6 +291,11 @@ export const packedUserDetailedNotMeOnlySchema = {
type: 'boolean', type: 'boolean',
nullable: false, optional: false, nullable: false, optional: false,
}, },
ffVisibility: {
type: 'string',
nullable: false, optional: false,
enum: ['public', 'followers', 'private'],
},
twoFactorEnabled: { twoFactorEnabled: {
type: 'boolean', type: 'boolean',
nullable: false, optional: false, nullable: false, optional: false,
@ -264,6 +311,57 @@ export const packedUserDetailedNotMeOnlySchema = {
nullable: false, optional: false, nullable: false, optional: false,
default: false, default: false,
}, },
roles: {
type: 'array',
nullable: false, optional: false,
items: {
type: 'object',
nullable: false, optional: false,
properties: {
id: {
type: 'string',
nullable: false, optional: false,
format: 'id',
},
name: {
type: 'string',
nullable: false, optional: false,
},
color: {
type: 'string',
nullable: true, optional: false,
},
iconUrl: {
type: 'string',
nullable: true, optional: false,
},
description: {
type: 'string',
nullable: false, optional: false,
},
isModerator: {
type: 'boolean',
nullable: false, optional: false,
},
isAdministrator: {
type: 'boolean',
nullable: false, optional: false,
},
displayOrder: {
type: 'number',
nullable: false, optional: false,
},
},
},
},
memo: {
type: 'string',
nullable: true, optional: false,
},
moderationNote: {
type: 'string',
nullable: false, optional: true,
},
//#region relations //#region relations
isFollowing: { isFollowing: {
type: 'boolean', type: 'boolean',
@ -297,10 +395,6 @@ export const packedUserDetailedNotMeOnlySchema = {
type: 'boolean', type: 'boolean',
nullable: false, optional: true, nullable: false, optional: true,
}, },
memo: {
type: 'string',
nullable: false, optional: true,
},
notify: { notify: {
type: 'string', type: 'string',
nullable: false, optional: true, nullable: false, optional: true,
@ -326,29 +420,37 @@ export const packedMeDetailedOnlySchema = {
nullable: true, optional: false, nullable: true, optional: false,
format: 'id', format: 'id',
}, },
injectFeaturedNote: { isModerator: {
type: 'boolean', type: 'boolean',
nullable: true, optional: false, nullable: true, optional: false,
}, },
isAdmin: {
type: 'boolean',
nullable: true, optional: false,
},
injectFeaturedNote: {
type: 'boolean',
nullable: false, optional: false,
},
receiveAnnouncementEmail: { receiveAnnouncementEmail: {
type: 'boolean', type: 'boolean',
nullable: true, optional: false, nullable: false, optional: false,
}, },
alwaysMarkNsfw: { alwaysMarkNsfw: {
type: 'boolean', type: 'boolean',
nullable: true, optional: false, nullable: false, optional: false,
}, },
autoSensitive: { autoSensitive: {
type: 'boolean', type: 'boolean',
nullable: true, optional: false, nullable: false, optional: false,
}, },
carefulBot: { carefulBot: {
type: 'boolean', type: 'boolean',
nullable: true, optional: false, nullable: false, optional: false,
}, },
autoAcceptFollowed: { autoAcceptFollowed: {
type: 'boolean', type: 'boolean',
nullable: true, optional: false, nullable: false, optional: false,
}, },
noCrawle: { noCrawle: {
type: 'boolean', type: 'boolean',
@ -387,6 +489,15 @@ export const packedMeDetailedOnlySchema = {
type: 'boolean', type: 'boolean',
nullable: false, optional: false, nullable: false, optional: false,
}, },
unreadAnnouncements: {
type: 'array',
nullable: false, optional: false,
items: {
type: 'object',
nullable: false, optional: false,
ref: 'Announcement',
},
},
hasUnreadAntenna: { hasUnreadAntenna: {
type: 'boolean', type: 'boolean',
nullable: false, optional: false, nullable: false, optional: false,
@ -395,6 +506,10 @@ export const packedMeDetailedOnlySchema = {
type: 'boolean', type: 'boolean',
nullable: false, optional: false, nullable: false, optional: false,
}, },
hasUnreadChannel: {
type: 'boolean',
nullable: false, optional: false,
},
hasUnreadNotification: { hasUnreadNotification: {
type: 'boolean', type: 'boolean',
nullable: false, optional: false, nullable: false, optional: false,
@ -433,12 +548,132 @@ export const packedMeDetailedOnlySchema = {
}, },
emailNotificationTypes: { emailNotificationTypes: {
type: 'array', type: 'array',
nullable: true, optional: false, nullable: false, optional: false,
items: { items: {
type: 'string', type: 'string',
nullable: false, optional: false, nullable: false, optional: false,
}, },
}, },
achievements: {
type: 'array',
nullable: false, optional: false,
items: {
type: 'object',
nullable: false, optional: false,
properties: {
name: {
type: 'string',
nullable: false, optional: false,
},
unlockedAt: {
type: 'number',
nullable: false, optional: false,
},
},
},
},
loggedInDays: {
type: 'number',
nullable: false, optional: false,
},
policies: {
type: 'object',
nullable: false, optional: false,
properties: {
gtlAvailable: {
type: 'boolean',
nullable: false, optional: false,
},
ltlAvailable: {
type: 'boolean',
nullable: false, optional: false,
},
canPublicNote: {
type: 'boolean',
nullable: false, optional: false,
},
canInvite: {
type: 'boolean',
nullable: false, optional: false,
},
inviteLimit: {
type: 'number',
nullable: false, optional: false,
},
inviteLimitCycle: {
type: 'number',
nullable: false, optional: false,
},
inviteExpirationTime: {
type: 'number',
nullable: false, optional: false,
},
canManageCustomEmojis: {
type: 'boolean',
nullable: false, optional: false,
},
canManageAvatarDecorations: {
type: 'boolean',
nullable: false, optional: false,
},
canSearchNotes: {
type: 'boolean',
nullable: false, optional: false,
},
canUseTranslator: {
type: 'boolean',
nullable: false, optional: false,
},
canHideAds: {
type: 'boolean',
nullable: false, optional: false,
},
driveCapacityMb: {
type: 'number',
nullable: false, optional: false,
},
alwaysMarkNsfw: {
type: 'boolean',
nullable: false, optional: false,
},
pinLimit: {
type: 'number',
nullable: false, optional: false,
},
antennaLimit: {
type: 'number',
nullable: false, optional: false,
},
wordMuteLimit: {
type: 'number',
nullable: false, optional: false,
},
webhookLimit: {
type: 'number',
nullable: false, optional: false,
},
clipLimit: {
type: 'number',
nullable: false, optional: false,
},
noteEachClipsLimit: {
type: 'number',
nullable: false, optional: false,
},
userListLimit: {
type: 'number',
nullable: false, optional: false,
},
userEachUserListsLimit: {
type: 'number',
nullable: false, optional: false,
},
rateLimitFactor: {
type: 'number',
nullable: false, optional: false,
},
},
},
//#region secrets //#region secrets
email: { email: {
type: 'string', type: 'string',
@ -515,5 +750,13 @@ export const packedUserSchema = {
type: 'object', type: 'object',
ref: 'UserDetailed', ref: 'UserDetailed',
}, },
{
type: 'object',
ref: 'UserDetailedNotMe',
},
{
type: 'object',
ref: 'MeDetailed',
},
], ],
} as const; } as const;

View file

@ -29,6 +29,8 @@ import * as ep___admin_avatarDecorations_delete from './endpoints/admin/avatar-d
import * as ep___admin_avatarDecorations_list from './endpoints/admin/avatar-decorations/list.js'; import * as ep___admin_avatarDecorations_list from './endpoints/admin/avatar-decorations/list.js';
import * as ep___admin_avatarDecorations_update from './endpoints/admin/avatar-decorations/update.js'; import * as ep___admin_avatarDecorations_update from './endpoints/admin/avatar-decorations/update.js';
import * as ep___admin_deleteAllFilesOfAUser from './endpoints/admin/delete-all-files-of-a-user.js'; import * as ep___admin_deleteAllFilesOfAUser from './endpoints/admin/delete-all-files-of-a-user.js';
import * as ep___admin_unsetUserAvatar from './endpoints/admin/unset-user-avatar.js';
import * as ep___admin_unsetUserBanner from './endpoints/admin/unset-user-banner.js';
import * as ep___admin_drive_cleanRemoteFiles from './endpoints/admin/drive/clean-remote-files.js'; import * as ep___admin_drive_cleanRemoteFiles from './endpoints/admin/drive/clean-remote-files.js';
import * as ep___admin_drive_cleanup from './endpoints/admin/drive/cleanup.js'; import * as ep___admin_drive_cleanup from './endpoints/admin/drive/cleanup.js';
import * as ep___admin_drive_files from './endpoints/admin/drive/files.js'; import * as ep___admin_drive_files from './endpoints/admin/drive/files.js';
@ -417,6 +419,8 @@ const $admin_avatarDecorations_delete: Provider = { provide: 'ep:admin/avatar-de
const $admin_avatarDecorations_list: Provider = { provide: 'ep:admin/avatar-decorations/list', useClass: ep___admin_avatarDecorations_list.default }; const $admin_avatarDecorations_list: Provider = { provide: 'ep:admin/avatar-decorations/list', useClass: ep___admin_avatarDecorations_list.default };
const $admin_avatarDecorations_update: Provider = { provide: 'ep:admin/avatar-decorations/update', useClass: ep___admin_avatarDecorations_update.default }; const $admin_avatarDecorations_update: Provider = { provide: 'ep:admin/avatar-decorations/update', useClass: ep___admin_avatarDecorations_update.default };
const $admin_deleteAllFilesOfAUser: Provider = { provide: 'ep:admin/delete-all-files-of-a-user', useClass: ep___admin_deleteAllFilesOfAUser.default }; const $admin_deleteAllFilesOfAUser: Provider = { provide: 'ep:admin/delete-all-files-of-a-user', useClass: ep___admin_deleteAllFilesOfAUser.default };
const $admin_unsetUserAvatar: Provider = { provide: 'ep:admin/unset-user-avatar', useClass: ep___admin_unsetUserAvatar.default };
const $admin_unsetUserBanner: Provider = { provide: 'ep:admin/unset-user-banner', useClass: ep___admin_unsetUserBanner.default };
const $admin_drive_cleanRemoteFiles: Provider = { provide: 'ep:admin/drive/clean-remote-files', useClass: ep___admin_drive_cleanRemoteFiles.default }; const $admin_drive_cleanRemoteFiles: Provider = { provide: 'ep:admin/drive/clean-remote-files', useClass: ep___admin_drive_cleanRemoteFiles.default };
const $admin_drive_cleanup: Provider = { provide: 'ep:admin/drive/cleanup', useClass: ep___admin_drive_cleanup.default }; const $admin_drive_cleanup: Provider = { provide: 'ep:admin/drive/cleanup', useClass: ep___admin_drive_cleanup.default };
const $admin_drive_files: Provider = { provide: 'ep:admin/drive/files', useClass: ep___admin_drive_files.default }; const $admin_drive_files: Provider = { provide: 'ep:admin/drive/files', useClass: ep___admin_drive_files.default };
@ -810,6 +814,8 @@ const $retention: Provider = { provide: 'ep:retention', useClass: ep___retention
$admin_avatarDecorations_list, $admin_avatarDecorations_list,
$admin_avatarDecorations_update, $admin_avatarDecorations_update,
$admin_deleteAllFilesOfAUser, $admin_deleteAllFilesOfAUser,
$admin_unsetUserAvatar,
$admin_unsetUserBanner,
$admin_drive_cleanRemoteFiles, $admin_drive_cleanRemoteFiles,
$admin_drive_cleanup, $admin_drive_cleanup,
$admin_drive_files, $admin_drive_files,
@ -1196,6 +1202,8 @@ const $retention: Provider = { provide: 'ep:retention', useClass: ep___retention
$admin_avatarDecorations_list, $admin_avatarDecorations_list,
$admin_avatarDecorations_update, $admin_avatarDecorations_update,
$admin_deleteAllFilesOfAUser, $admin_deleteAllFilesOfAUser,
$admin_unsetUserAvatar,
$admin_unsetUserBanner,
$admin_drive_cleanRemoteFiles, $admin_drive_cleanRemoteFiles,
$admin_drive_cleanup, $admin_drive_cleanup,
$admin_drive_files, $admin_drive_files,

View file

@ -28,6 +28,8 @@ import * as ep___admin_avatarDecorations_delete from './endpoints/admin/avatar-d
import * as ep___admin_avatarDecorations_list from './endpoints/admin/avatar-decorations/list.js'; import * as ep___admin_avatarDecorations_list from './endpoints/admin/avatar-decorations/list.js';
import * as ep___admin_avatarDecorations_update from './endpoints/admin/avatar-decorations/update.js'; import * as ep___admin_avatarDecorations_update from './endpoints/admin/avatar-decorations/update.js';
import * as ep___admin_deleteAllFilesOfAUser from './endpoints/admin/delete-all-files-of-a-user.js'; import * as ep___admin_deleteAllFilesOfAUser from './endpoints/admin/delete-all-files-of-a-user.js';
import * as ep___admin_unsetUserAvatar from './endpoints/admin/unset-user-avatar.js';
import * as ep___admin_unsetUserBanner from './endpoints/admin/unset-user-banner.js';
import * as ep___admin_drive_cleanRemoteFiles from './endpoints/admin/drive/clean-remote-files.js'; import * as ep___admin_drive_cleanRemoteFiles from './endpoints/admin/drive/clean-remote-files.js';
import * as ep___admin_drive_cleanup from './endpoints/admin/drive/cleanup.js'; import * as ep___admin_drive_cleanup from './endpoints/admin/drive/cleanup.js';
import * as ep___admin_drive_files from './endpoints/admin/drive/files.js'; import * as ep___admin_drive_files from './endpoints/admin/drive/files.js';
@ -414,6 +416,8 @@ const eps = [
['admin/avatar-decorations/list', ep___admin_avatarDecorations_list], ['admin/avatar-decorations/list', ep___admin_avatarDecorations_list],
['admin/avatar-decorations/update', ep___admin_avatarDecorations_update], ['admin/avatar-decorations/update', ep___admin_avatarDecorations_update],
['admin/delete-all-files-of-a-user', ep___admin_deleteAllFilesOfAUser], ['admin/delete-all-files-of-a-user', ep___admin_deleteAllFilesOfAUser],
['admin/unset-user-avatar', ep___admin_unsetUserAvatar],
['admin/unset-user-banner', ep___admin_unsetUserBanner],
['admin/drive/clean-remote-files', ep___admin_drive_cleanRemoteFiles], ['admin/drive/clean-remote-files', ep___admin_drive_cleanRemoteFiles],
['admin/drive/cleanup', ep___admin_drive_cleanup], ['admin/drive/cleanup', ep___admin_drive_cleanup],
['admin/drive/files', ep___admin_drive_files], ['admin/drive/files', ep___admin_drive_files],

View file

@ -22,7 +22,7 @@ export const paramDef = {
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
sinceId: { type: 'string', format: 'misskey:id' }, sinceId: { type: 'string', format: 'misskey:id' },
untilId: { type: 'string', format: 'misskey:id' }, untilId: { type: 'string', format: 'misskey:id' },
publishing: { type: 'boolean', default: false }, publishing: { type: 'boolean', default: null, nullable: true},
}, },
required: [], required: [],
} as const; } as const;
@ -37,8 +37,10 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
) { ) {
super(meta, paramDef, async (ps, me) => { super(meta, paramDef, async (ps, me) => {
const query = this.queryService.makePaginationQuery(this.adsRepository.createQueryBuilder('ad'), ps.sinceId, ps.untilId); const query = this.queryService.makePaginationQuery(this.adsRepository.createQueryBuilder('ad'), ps.sinceId, ps.untilId);
if (ps.publishing) { if (ps.publishing === true) {
query.andWhere('ad.expiresAt > :now', { now: new Date() }).andWhere('ad.startsAt <= :now', { now: new Date() }); query.andWhere('ad.expiresAt > :now', { now: new Date() }).andWhere('ad.startsAt <= :now', { now: new Date() });
} else if (ps.publishing === false) {
query.andWhere('ad.expiresAt <= :now', { now: new Date() }).orWhere('ad.startsAt > :now', { now: new Date() });
} }
const ads = await query.limit(ps.limit).getMany(); const ads = await query.limit(ps.limit).getMany();

View file

@ -319,6 +319,14 @@ export const meta = {
type: 'boolean', type: 'boolean',
optional: false, nullable: false, optional: false, nullable: false,
}, },
enableVerifymailApi: {
type: 'boolean',
optional: false, nullable: false,
},
verifymailAuthKey: {
type: 'string',
optional: false, nullable: true,
},
enableChartsForRemoteUser: { enableChartsForRemoteUser: {
type: 'boolean', type: 'boolean',
optional: false, nullable: false, optional: false, nullable: false,
@ -516,6 +524,8 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
ctav3Glossary: instance.ctav3Glossary, ctav3Glossary: instance.ctav3Glossary,
enableIpLogging: instance.enableIpLogging, enableIpLogging: instance.enableIpLogging,
enableActiveEmailValidation: instance.enableActiveEmailValidation, enableActiveEmailValidation: instance.enableActiveEmailValidation,
enableVerifymailApi: instance.enableVerifymailApi,
verifymailAuthKey: instance.verifymailAuthKey,
enableChartsForRemoteUser: instance.enableChartsForRemoteUser, enableChartsForRemoteUser: instance.enableChartsForRemoteUser,
enableChartsForFederatedInstances: instance.enableChartsForFederatedInstances, enableChartsForFederatedInstances: instance.enableChartsForFederatedInstances,
enableServerMachineStats: instance.enableServerMachineStats, enableServerMachineStats: instance.enableServerMachineStats,

View file

@ -0,0 +1,60 @@
/*
* SPDX-FileCopyrightText: syuilo and other misskey, cherrypick contributors
* SPDX-License-Identifier: AGPL-3.0-only
*/
import { Inject, Injectable } from '@nestjs/common';
import type { UsersRepository } from '@/models/_.js';
import { Endpoint } from '@/server/api/endpoint-base.js';
import { DI } from '@/di-symbols.js';
import { ModerationLogService } from '@/core/ModerationLogService.js';
export const meta = {
tags: ['admin'],
requireCredential: true,
requireModerator: true,
} as const;
export const paramDef = {
type: 'object',
properties: {
userId: { type: 'string', format: 'misskey:id' },
},
required: ['userId'],
} as const;
// eslint-disable-next-line import/no-default-export
@Injectable()
export default class extends Endpoint<typeof meta, typeof paramDef> {
constructor(
@Inject(DI.usersRepository)
private usersRepository: UsersRepository,
private moderationLogService: ModerationLogService,
) {
super(meta, paramDef, async (ps, me) => {
const user = await this.usersRepository.findOneBy({ id: ps.userId });
if (user == null) {
throw new Error('user not found');
}
if (user.avatarId == null) return;
await this.usersRepository.update(user.id, {
avatar: null,
avatarId: null,
avatarUrl: null,
avatarBlurhash: null,
});
this.moderationLogService.log(me, 'unsetUserAvatar', {
userId: user.id,
userUsername: user.username,
userHost: user.host,
fileId: user.avatarId,
});
});
}
}

View file

@ -0,0 +1,60 @@
/*
* SPDX-FileCopyrightText: syuilo and other misskey, cherrypick contributors
* SPDX-License-Identifier: AGPL-3.0-only
*/
import { Inject, Injectable } from '@nestjs/common';
import type { UsersRepository } from '@/models/_.js';
import { Endpoint } from '@/server/api/endpoint-base.js';
import { DI } from '@/di-symbols.js';
import { ModerationLogService } from '@/core/ModerationLogService.js';
export const meta = {
tags: ['admin'],
requireCredential: true,
requireModerator: true,
} as const;
export const paramDef = {
type: 'object',
properties: {
userId: { type: 'string', format: 'misskey:id' },
},
required: ['userId'],
} as const;
// eslint-disable-next-line import/no-default-export
@Injectable()
export default class extends Endpoint<typeof meta, typeof paramDef> {
constructor(
@Inject(DI.usersRepository)
private usersRepository: UsersRepository,
private moderationLogService: ModerationLogService,
) {
super(meta, paramDef, async (ps, me) => {
const user = await this.usersRepository.findOneBy({ id: ps.userId });
if (user == null) {
throw new Error('user not found');
}
if (user.bannerId == null) return;
await this.usersRepository.update(user.id, {
banner: null,
bannerId: null,
bannerUrl: null,
bannerBlurhash: null,
});
this.moderationLogService.log(me, 'unsetUserBanner', {
userId: user.id,
userUsername: user.username,
userHost: user.host,
fileId: user.bannerId,
});
});
}
}

View file

@ -134,6 +134,8 @@ export const paramDef = {
objectStorageRemoteS3ForcePathStyle: { type: 'boolean' }, objectStorageRemoteS3ForcePathStyle: { type: 'boolean' },
enableIpLogging: { type: 'boolean' }, enableIpLogging: { type: 'boolean' },
enableActiveEmailValidation: { type: 'boolean' }, enableActiveEmailValidation: { type: 'boolean' },
enableVerifymailApi: { type: 'boolean' },
verifymailAuthKey: { type: 'string', nullable: true },
enableChartsForRemoteUser: { type: 'boolean' }, enableChartsForRemoteUser: { type: 'boolean' },
enableChartsForFederatedInstances: { type: 'boolean' }, enableChartsForFederatedInstances: { type: 'boolean' },
enableServerMachineStats: { type: 'boolean' }, enableServerMachineStats: { type: 'boolean' },
@ -561,6 +563,18 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
set.enableActiveEmailValidation = ps.enableActiveEmailValidation; set.enableActiveEmailValidation = ps.enableActiveEmailValidation;
} }
if (ps.enableVerifymailApi !== undefined) {
set.enableVerifymailApi = ps.enableVerifymailApi;
}
if (ps.verifymailAuthKey !== undefined) {
if (ps.verifymailAuthKey === '') {
set.verifymailAuthKey = null;
} else {
set.verifymailAuthKey = ps.verifymailAuthKey;
}
}
if (ps.enableChartsForRemoteUser !== undefined) { if (ps.enableChartsForRemoteUser !== undefined) {
set.enableChartsForRemoteUser = ps.enableChartsForRemoteUser; set.enableChartsForRemoteUser = ps.enableChartsForRemoteUser;
} }

View file

@ -13,6 +13,7 @@ import { DI } from '@/di-symbols.js';
import { NoteEntityService } from '@/core/entities/NoteEntityService.js'; import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
import { IdService } from '@/core/IdService.js'; import { IdService } from '@/core/IdService.js';
import { FunoutTimelineService } from '@/core/FunoutTimelineService.js'; import { FunoutTimelineService } from '@/core/FunoutTimelineService.js';
import { GlobalEventService } from '@/core/GlobalEventService.js';
import { ApiError } from '../../error.js'; import { ApiError } from '../../error.js';
export const meta = { export const meta = {
@ -71,6 +72,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
private queryService: QueryService, private queryService: QueryService,
private noteReadService: NoteReadService, private noteReadService: NoteReadService,
private funoutTimelineService: FunoutTimelineService, private funoutTimelineService: FunoutTimelineService,
private globalEventService: GlobalEventService,
) { ) {
super(meta, paramDef, async (ps, me) => { super(meta, paramDef, async (ps, me) => {
const untilId = ps.untilId ?? (ps.untilDate ? this.idService.gen(ps.untilDate!) : null); const untilId = ps.untilId ?? (ps.untilDate ? this.idService.gen(ps.untilDate!) : null);
@ -85,10 +87,16 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
throw new ApiError(meta.errors.noSuchAntenna); throw new ApiError(meta.errors.noSuchAntenna);
} }
this.antennasRepository.update(antenna.id, { // falseだった場合はアンテナの配信先が増えたことを通知したい
isActive: true, const needPublishEvent = !antenna.isActive;
lastUsedAt: new Date(),
}); antenna.isActive = true;
antenna.lastUsedAt = new Date();
this.antennasRepository.update(antenna.id, antenna);
if (needPublishEvent) {
this.globalEventService.publishInternalEvent('antennaUpdated', antenna);
}
let noteIds = await this.funoutTimelineService.get(`antennaTimeline:${antenna.id}`, untilId, sinceId); let noteIds = await this.funoutTimelineService.get(`antennaTimeline:${antenna.id}`, untilId, sinceId);
noteIds = noteIds.slice(0, ps.limit); noteIds = noteIds.slice(0, ps.limit);

View file

@ -16,12 +16,9 @@ export const meta = {
requireCredential: false, requireCredential: false,
res: { res: {
oneOf: [{
type: 'object', type: 'object',
optional: false, nullable: true,
ref: 'FederationInstance', ref: 'FederationInstance',
}, {
type: 'null',
}],
}, },
} as const; } as const;

View file

@ -4,7 +4,7 @@
*/ */
import type { Config } from '@/config.js'; import type { Config } from '@/config.js';
import endpoints from '../endpoints.js'; import endpoints, { IEndpoint } from '../endpoints.js';
import { errors as basicErrors } from './errors.js'; import { errors as basicErrors } from './errors.js';
import { schemas, convertSchemaToOpenApiSchema } from './schemas.js'; import { schemas, convertSchemaToOpenApiSchema } from './schemas.js';
@ -34,16 +34,17 @@ export function genOpenapiSpec(config: Config) {
schemas: schemas, schemas: schemas,
securitySchemes: { securitySchemes: {
ApiKeyAuth: { bearerAuth: {
type: 'apiKey', type: 'http',
in: 'body', scheme: 'bearer',
name: 'i',
}, },
}, },
}, },
}; };
for (const endpoint of endpoints.filter(ep => !ep.meta.secure)) { // 書き換えたりするのでディープコピーしておく。そのまま編集するとメモリ上の値が汚れて次回以降の出力に影響する
const copiedEndpoints = JSON.parse(JSON.stringify(endpoints)) as IEndpoint[];
for (const endpoint of copiedEndpoints.filter(ep => !ep.meta.secure)) {
const errors = {} as any; const errors = {} as any;
if (endpoint.meta.errors) { if (endpoint.meta.errors) {
@ -80,6 +81,13 @@ export function genOpenapiSpec(config: Config) {
schema.required = [...schema.required ?? [], 'file']; schema.required = [...schema.required ?? [], 'file'];
} }
if (schema.required && schema.required.length <= 0) {
// 空配列は許可されない
schema.required = undefined;
}
const hasBody = (schema.type === 'object' && schema.properties && Object.keys(schema.properties).length >= 1);
const info = { const info = {
operationId: endpoint.name, operationId: endpoint.name,
summary: endpoint.name, summary: endpoint.name,
@ -93,9 +101,10 @@ export function genOpenapiSpec(config: Config) {
} : {}), } : {}),
...(endpoint.meta.requireCredential ? { ...(endpoint.meta.requireCredential ? {
security: [{ security: [{
ApiKeyAuth: [], bearerAuth: [],
}], }],
} : {}), } : {}),
...(hasBody ? {
requestBody: { requestBody: {
required: true, required: true,
content: { content: {
@ -104,6 +113,7 @@ export function genOpenapiSpec(config: Config) {
}, },
}, },
}, },
} : {}),
responses: { responses: {
...(endpoint.meta.res ? { ...(endpoint.meta.res ? {
'200': { '200': {
@ -119,6 +129,11 @@ export function genOpenapiSpec(config: Config) {
description: 'OK (without any results)', description: 'OK (without any results)',
}, },
}), }),
...(endpoint.meta.res?.optional === true || endpoint.meta.res?.nullable === true ? {
'204': {
description: 'OK (without any results)',
},
} : {}),
'400': { '400': {
description: 'Client error', description: 'Client error',
content: { content: {
@ -191,6 +206,7 @@ export function genOpenapiSpec(config: Config) {
}; };
spec.paths['/' + endpoint.name] = { spec.paths['/' + endpoint.name] = {
...(endpoint.meta.allowGet ? { get: info } : {}),
post: info, post: info,
}; };
} }

View file

@ -7,10 +7,16 @@ import type { Schema } from '@/misc/json-schema.js';
import { refs } from '@/misc/json-schema.js'; import { refs } from '@/misc/json-schema.js';
export function convertSchemaToOpenApiSchema(schema: Schema) { export function convertSchemaToOpenApiSchema(schema: Schema) {
const res: any = schema; // optional, refはスキーマ定義に含まれないので分離しておく
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const { optional, ref, ...res }: any = schema;
if (schema.type === 'object' && schema.properties) { if (schema.type === 'object' && schema.properties) {
res.required = Object.entries(schema.properties).filter(([k, v]) => !v.optional).map(([k]) => k); const required = Object.entries(schema.properties).filter(([k, v]) => !v.optional).map(([k]) => k);
if (required.length > 0) {
// 空配列は許可されない
res.required = required;
}
for (const k of Object.keys(schema.properties)) { for (const k of Object.keys(schema.properties)) {
res.properties[k] = convertSchemaToOpenApiSchema(schema.properties[k]); res.properties[k] = convertSchemaToOpenApiSchema(schema.properties[k]);

View file

@ -64,6 +64,8 @@ export const moderationLogTypes = [
'createAvatarDecoration', 'createAvatarDecoration',
'updateAvatarDecoration', 'updateAvatarDecoration',
'deleteAvatarDecoration', 'deleteAvatarDecoration',
'unsetUserAvatar',
'unsetUserBanner',
] as const; ] as const;
export type ModerationLogPayloads = { export type ModerationLogPayloads = {
@ -238,6 +240,18 @@ export type ModerationLogPayloads = {
avatarDecorationId: string; avatarDecorationId: string;
avatarDecoration: any; avatarDecoration: any;
}; };
unsetUserAvatar: {
userId: string;
userUsername: string;
userHost: string | null;
fileId: string;
};
unsetUserBanner: {
userId: string;
userUsername: string;
userHost: string | null;
fileId: string;
};
}; };
export type Serialized<T> = { export type Serialized<T> = {

View file

@ -345,6 +345,18 @@ export type Endpoints = {
}; };
res: null; res: null;
}; };
'admin/unset-user-avatar': {
req: {
userId: User['id'];
};
res: null;
};
'admin/unset-user-banner': {
req: {
userId: User['id'];
};
res: null;
};
'admin/delete-logs': { 'admin/delete-logs': {
req: NoParams; req: NoParams;
res: null; res: null;
@ -2738,10 +2750,16 @@ type ModerationLog = {
} | { } | {
type: 'resolveAbuseReport'; type: 'resolveAbuseReport';
info: ModerationLogPayloads['resolveAbuseReport']; info: ModerationLogPayloads['resolveAbuseReport'];
} | {
type: 'unsetUserAvatar';
info: ModerationLogPayloads['unsetUserAvatar'];
} | {
type: 'unsetUserBanner';
info: ModerationLogPayloads['unsetUserBanner'];
}); });
// @public (undocumented) // @public (undocumented)
export const moderationLogTypes: readonly ["updateServerSettings", "suspend", "unsuspend", "updateUserNote", "addCustomEmoji", "updateCustomEmoji", "deleteCustomEmoji", "assignRole", "unassignRole", "createRole", "updateRole", "deleteRole", "clearQueue", "promoteQueue", "deleteDriveFile", "deleteNote", "createGlobalAnnouncement", "createUserAnnouncement", "updateGlobalAnnouncement", "updateUserAnnouncement", "deleteGlobalAnnouncement", "deleteUserAnnouncement", "resetPassword", "suspendRemoteInstance", "unsuspendRemoteInstance", "markSensitiveDriveFile", "unmarkSensitiveDriveFile", "resolveAbuseReport", "createInvitation", "createAd", "updateAd", "deleteAd", "createAvatarDecoration", "updateAvatarDecoration", "deleteAvatarDecoration"]; export const moderationLogTypes: readonly ["updateServerSettings", "suspend", "unsuspend", "updateUserNote", "addCustomEmoji", "updateCustomEmoji", "deleteCustomEmoji", "assignRole", "unassignRole", "createRole", "updateRole", "deleteRole", "clearQueue", "promoteQueue", "deleteDriveFile", "deleteNote", "createGlobalAnnouncement", "createUserAnnouncement", "updateGlobalAnnouncement", "updateUserAnnouncement", "deleteGlobalAnnouncement", "deleteUserAnnouncement", "resetPassword", "suspendRemoteInstance", "unsuspendRemoteInstance", "markSensitiveDriveFile", "unmarkSensitiveDriveFile", "resolveAbuseReport", "createInvitation", "createAd", "updateAd", "deleteAd", "createAvatarDecoration", "updateAvatarDecoration", "deleteAvatarDecoration", "unsetUserAvatar", "unsetUserBanner"];
// @public (undocumented) // @public (undocumented)
export const mutedNoteReasons: readonly ["word", "manual", "spam", "other"]; export const mutedNoteReasons: readonly ["word", "manual", "spam", "other"];
@ -3108,8 +3126,8 @@ type UserSorting = '+follower' | '-follower' | '+createdAt' | '-createdAt' | '+u
// Warnings were encountered during analysis: // Warnings were encountered during analysis:
// //
// src/api.types.ts:16:32 - (ae-forgotten-export) The symbol "TODO" needs to be exported by the entry point index.d.ts // src/api.types.ts:16:32 - (ae-forgotten-export) The symbol "TODO" needs to be exported by the entry point index.d.ts
// src/api.types.ts:18:25 - (ae-forgotten-export) The symbol "NoParams" needs to be exported by the entry point index.d.ts // src/api.types.ts:20:25 - (ae-forgotten-export) The symbol "NoParams" needs to be exported by the entry point index.d.ts
// src/api.types.ts:661:18 - (ae-forgotten-export) The symbol "ShowUserReq" needs to be exported by the entry point index.d.ts // src/api.types.ts:663:18 - (ae-forgotten-export) The symbol "ShowUserReq" needs to be exported by the entry point index.d.ts
// src/entities.ts:116:2 - (ae-forgotten-export) The symbol "notificationTypes_2" needs to be exported by the entry point index.d.ts // src/entities.ts:116:2 - (ae-forgotten-export) The symbol "notificationTypes_2" needs to be exported by the entry point index.d.ts
// src/entities.ts:637:2 - (ae-forgotten-export) The symbol "ModerationLogPayloads" needs to be exported by the entry point index.d.ts // src/entities.ts:637:2 - (ae-forgotten-export) The symbol "ModerationLogPayloads" needs to be exported by the entry point index.d.ts
// src/streaming.types.ts:33:4 - (ae-forgotten-export) The symbol "FIXME" needs to be exported by the entry point index.d.ts // src/streaming.types.ts:33:4 - (ae-forgotten-export) The symbol "FIXME" needs to be exported by the entry point index.d.ts

View file

@ -32,7 +32,7 @@
"jest-websocket-mock": "2.5.0", "jest-websocket-mock": "2.5.0",
"mock-socket": "9.3.1", "mock-socket": "9.3.1",
"tsd": "0.29.0", "tsd": "0.29.0",
"typescript": "5.2.2" "typescript": "5.3.2"
}, },
"files": [ "files": [
"built" "built"

View file

@ -15,6 +15,8 @@ export type Endpoints = {
// admin // admin
'admin/abuse-user-reports': { req: TODO; res: TODO; }; 'admin/abuse-user-reports': { req: TODO; res: TODO; };
'admin/delete-all-files-of-a-user': { req: { userId: User['id']; }; res: null; }; 'admin/delete-all-files-of-a-user': { req: { userId: User['id']; }; res: null; };
'admin/unset-user-avatar': { req: { userId: User['id']; }; res: null; };
'admin/unset-user-banner': { req: { userId: User['id']; }; res: null; };
'admin/delete-logs': { req: NoParams; res: null; }; 'admin/delete-logs': { req: NoParams; res: null; };
'admin/get-index-stats': { req: TODO; res: TODO; }; 'admin/get-index-stats': { req: TODO; res: TODO; };
'admin/get-table-stats': { req: TODO; res: TODO; }; 'admin/get-table-stats': { req: TODO; res: TODO; };

View file

@ -81,6 +81,8 @@ export const moderationLogTypes = [
'createAvatarDecoration', 'createAvatarDecoration',
'updateAvatarDecoration', 'updateAvatarDecoration',
'deleteAvatarDecoration', 'deleteAvatarDecoration',
'unsetUserAvatar',
'unsetUserBanner',
] as const; ] as const;
export type ModerationLogPayloads = { export type ModerationLogPayloads = {
@ -255,4 +257,16 @@ export type ModerationLogPayloads = {
avatarDecorationId: string; avatarDecorationId: string;
avatarDecoration: any; avatarDecoration: any;
}; };
unsetUserAvatar: {
userId: string;
userUsername: string;
userHost: string | null;
fileId: string;
};
unsetUserBanner: {
userId: string;
userUsername: string;
userHost: string | null;
fileId: string;
};
}; };

View file

@ -737,4 +737,10 @@ export type ModerationLog = {
} | { } | {
type: 'resolveAbuseReport'; type: 'resolveAbuseReport';
info: ModerationLogPayloads['resolveAbuseReport']; info: ModerationLogPayloads['resolveAbuseReport'];
} | {
type: 'unsetUserAvatar';
info: ModerationLogPayloads['unsetUserAvatar'];
} | {
type: 'unsetUserBanner';
info: ModerationLogPayloads['unsetUserBanner'];
}); });

View file

@ -74,7 +74,7 @@
"tsc-alias": "1.8.8", "tsc-alias": "1.8.8",
"tsconfig-paths": "4.2.0", "tsconfig-paths": "4.2.0",
"twemoji-parser": "14.0.0", "twemoji-parser": "14.0.0",
"typescript": "5.2.2", "typescript": "5.3.2",
"uuid": "9.0.1", "uuid": "9.0.1",
"v-code-diff": "1.7.2", "v-code-diff": "1.7.2",
"vanilla-tilt": "1.8.1", "vanilla-tilt": "1.8.1",

View file

@ -265,7 +265,7 @@ export async function mainBoot() {
main.on('unreadMessagingMessage', () => { main.on('unreadMessagingMessage', () => {
updateAccount({ hasUnreadMessagingMessage: true }); updateAccount({ hasUnreadMessagingMessage: true });
sound.play('chatBg'); sound.play('chatBg');
vibrate(ColdDeviceStorage.get('vibrateChatBg') ? [50, 40] : ''); vibrate(defaultStore.state.vibrateChatBg ? [50, 40] : []);
}); });
main.on('readAllAntennas', () => { main.on('readAllAntennas', () => {

View file

@ -35,7 +35,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<script lang="ts" setup> <script lang="ts" setup>
import { nextTick, onMounted } from 'vue'; import { nextTick, onMounted } from 'vue';
import { vibrate } from '@/scripts/vibrate.js'; import { vibrate } from '@/scripts/vibrate.js';
import { ColdDeviceStorage } from '@/store.js'; import { defaultStore } from '@/store.js';
const props = defineProps<{ const props = defineProps<{
type?: 'button' | 'submit' | 'reset'; type?: 'button' | 'submit' | 'reset';
@ -101,7 +101,7 @@ function onMousedown(evt: MouseEvent): void {
const scale = calcCircleScale(target.clientWidth, target.clientHeight, circleCenterX, circleCenterY); const scale = calcCircleScale(target.clientWidth, target.clientHeight, circleCenterX, circleCenterY);
vibrate(ColdDeviceStorage.get('vibrateSystem') ? 10 : ''); vibrate(defaultStore.state.vibrateSystem ? 10 : []);
window.setTimeout(() => { window.setTimeout(() => {
ripple.style.transform = 'scale(' + (scale / 2) + ')'; ripple.style.transform = 'scale(' + (scale / 2) + ')';

View file

@ -30,7 +30,7 @@ SPDX-License-Identifier: AGPL-3.0-only
> >
<div v-show="showBody" ref="contentEl" :class="[$style.content, { [$style.omitted]: omitted }]"> <div v-show="showBody" ref="contentEl" :class="[$style.content, { [$style.omitted]: omitted }]">
<slot></slot> <slot></slot>
<button v-if="omitted" v-vibrate="ColdDeviceStorage.get('vibrateSystem') ? 5 : ''" :class="$style.fade" class="_button" @click="() => { ignoreOmit = true; omitted = false; }"> <button v-if="omitted" v-vibrate="defaultStore.state.vibrateSystem ? 5 : []" :class="$style.fade" class="_button" @click="() => { ignoreOmit = true; omitted = false; }">
<span :class="$style.fadeLabel">{{ i18n.ts.showMore }}</span> <span :class="$style.fadeLabel">{{ i18n.ts.showMore }}</span>
</button> </button>
</div> </div>
@ -40,7 +40,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<script lang="ts" setup> <script lang="ts" setup>
import { onMounted, onUnmounted, ref, shallowRef, watch } from 'vue'; import { onMounted, onUnmounted, ref, shallowRef, watch } from 'vue';
import { ColdDeviceStorage, defaultStore } from '@/store.js'; import { defaultStore } from '@/store.js';
import { i18n } from '@/i18n.js'; import { i18n } from '@/i18n.js';
const props = withDefaults(defineProps<{ const props = withDefaults(defineProps<{

View file

@ -13,7 +13,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<button <button
v-for="emoji in searchResultCustom" v-for="emoji in searchResultCustom"
:key="emoji.name" :key="emoji.name"
v-vibrate="ColdDeviceStorage.get('vibrateSystem') ? 50 : ''" v-vibrate="defaultStore.state.vibrateSystem ? 50 : []"
class="_button item" class="_button item"
:title="emoji.name" :title="emoji.name"
tabindex="0" tabindex="0"
@ -116,7 +116,7 @@ import * as os from '@/os.js';
import { isTouchUsing } from '@/scripts/touch.js'; import { isTouchUsing } from '@/scripts/touch.js';
import { deviceKind } from '@/scripts/device-kind.js'; import { deviceKind } from '@/scripts/device-kind.js';
import { i18n } from '@/i18n.js'; import { i18n } from '@/i18n.js';
import { ColdDeviceStorage, defaultStore } from '@/store.js'; import { defaultStore } from '@/store.js';
import { customEmojiCategories, customEmojis, customEmojisMap } from '@/custom-emojis.js'; import { customEmojiCategories, customEmojis, customEmojisMap } from '@/custom-emojis.js';
import { $i } from '@/account.js'; import { $i } from '@/account.js';

View file

@ -7,7 +7,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<div ref="rootEl" :class="$style.root" role="group" :aria-expanded="opened"> <div ref="rootEl" :class="$style.root" role="group" :aria-expanded="opened">
<MkStickyContainer> <MkStickyContainer>
<template #header> <template #header>
<div v-vibrate="ColdDeviceStorage.get('vibrateSystem') ? 5 : ''" :class="[$style.header, { [$style.opened]: opened, [$style.inactive]: inactive || isArchived }]" class="_button" role="button" data-cy-folder-header @click="toggle"> <div v-vibrate="defaultStore.state.vibrateSystem ? 5 : []" :class="[$style.header, { [$style.opened]: opened, [$style.inactive]: inactive || isArchived }]" class="_button" role="button" data-cy-folder-header @click="toggle">
<div :class="$style.headerIcon"><slot name="icon"></slot></div> <div :class="$style.headerIcon"><slot name="icon"></slot></div>
<div :class="$style.headerText"> <div :class="$style.headerText">
<div> <div>
@ -52,7 +52,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<script lang="ts" setup> <script lang="ts" setup>
import { nextTick, onMounted } from 'vue'; import { nextTick, onMounted } from 'vue';
import { ColdDeviceStorage, defaultStore } from '@/store.js'; import { defaultStore } from '@/store.js';
const props = withDefaults(defineProps<{ const props = withDefaults(defineProps<{
defaultOpen?: boolean; defaultOpen?: boolean;

View file

@ -47,7 +47,7 @@ import { $i } from '@/account.js';
import { userName } from '@/filters/user.js'; import { userName } from '@/filters/user.js';
import { globalEvents } from '@/events.js'; import { globalEvents } from '@/events.js';
import { vibrate } from '@/scripts/vibrate.js'; import { vibrate } from '@/scripts/vibrate.js';
import { ColdDeviceStorage, defaultStore } from '@/store.js'; import { defaultStore } from '@/store.js';
let showFollowButton = $ref(false); let showFollowButton = $ref(false);
@ -119,7 +119,7 @@ async function onClick() {
...props.user, ...props.user,
withReplies: defaultStore.state.defaultWithReplies, withReplies: defaultStore.state.defaultWithReplies,
}); });
vibrate(ColdDeviceStorage.get('vibrateSystem') ? [30, 40, 100] : ''); vibrate(defaultStore.state.vibrateSystem ? [30, 40, 100] : []);
hasPendingFollowRequestFromYou = true; hasPendingFollowRequestFromYou = true;
claimAchievement('following1'); claimAchievement('following1');

View file

@ -6,7 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<template> <template>
<div role="menu"> <div role="menu">
<div <div
ref="itemsEl" v-hotkey="keymap" v-vibrate="ColdDeviceStorage.get('vibrateSystem') ? 5 : ''" ref="itemsEl" v-hotkey="keymap" v-vibrate="defaultStore.state.vibrateSystem ? 5 : []"
class="_shadow" class="_shadow"
:class="[$style.root, { [$style.center]: align === 'center', [$style.asDrawer]: asDrawer, _popup: !defaultStore.state.useBlurEffect || !defaultStore.state.useBlurEffectForModal || !defaultStore.state.removeModalBgColorForBlur, _popupAcrylic: defaultStore.state.useBlurEffect && defaultStore.state.useBlurEffectForModal && defaultStore.state.removeModalBgColorForBlur }]" :class="[$style.root, { [$style.center]: align === 'center', [$style.asDrawer]: asDrawer, _popup: !defaultStore.state.useBlurEffect || !defaultStore.state.useBlurEffectForModal || !defaultStore.state.removeModalBgColorForBlur, _popupAcrylic: defaultStore.state.useBlurEffect && defaultStore.state.useBlurEffectForModal && defaultStore.state.removeModalBgColorForBlur }]"
:style="{ width: (width && !asDrawer) ? width + 'px' : '', maxHeight: maxHeight ? maxHeight + 'px' : '' }" :style="{ width: (width && !asDrawer) ? width + 'px' : '', maxHeight: maxHeight ? maxHeight + 'px' : '' }"
@ -74,7 +74,7 @@ const childrenCache = new WeakMap<MenuParent, MenuItem[]>();
</script> </script>
<script lang="ts" setup> <script lang="ts" setup>
import { ColdDeviceStorage, defaultStore } from '@/store.js'; import { defaultStore } from '@/store.js';
const XChild = defineAsyncComponent(() => import('./MkMenu.child.vue')); const XChild = defineAsyncComponent(() => import('./MkMenu.child.vue'));
const props = defineProps<{ const props = defineProps<{

View file

@ -9,7 +9,7 @@ SPDX-License-Identifier: AGPL-3.0-only
v-show="!isDeleted" v-show="!isDeleted"
ref="el" ref="el"
v-hotkey="keymap" v-hotkey="keymap"
v-vibrate="ColdDeviceStorage.get('vibrateSystem') ? 5 : ''" v-vibrate="defaultStore.state.vibrateSystem ? 5 : []"
:class="[$style.root, { [$style.showActionsOnlyHover]: defaultStore.state.showNoteActionsOnlyHover, [$style.radius]: defaultStore.state.showGapBetweenNotesInTimeline && mainRouter.currentRoute.value.name === 'my-notifications' }]" :class="[$style.root, { [$style.showActionsOnlyHover]: defaultStore.state.showNoteActionsOnlyHover, [$style.radius]: defaultStore.state.showGapBetweenNotesInTimeline && mainRouter.currentRoute.value.name === 'my-notifications' }]"
:tabindex="!isDeleted ? '-1' : undefined" :tabindex="!isDeleted ? '-1' : undefined"
> >
@ -112,13 +112,13 @@ SPDX-License-Identifier: AGPL-3.0-only
</div> </div>
<MkPoll v-if="appearNote.poll" :note="appearNote" :class="$style.poll"/> <MkPoll v-if="appearNote.poll" :note="appearNote" :class="$style.poll"/>
<MkUrlPreview v-for="url in urls" :key="url" :url="url" :compact="true" :detail="false" :class="$style.urlPreview"/> <MkUrlPreview v-for="url in urls" :key="url" :url="url" :compact="true" :detail="false" :class="$style.urlPreview"/>
<button v-if="(isLong || (isMFM && defaultStore.state.collapseDefault) || (appearNote.files.length > 0 && defaultStore.state.allMediaNoteCollapse)) && collapsed" v-vibrate="ColdDeviceStorage.get('vibrateSystem') ? 5 : ''" :class="$style.collapsed" class="_button" @click="collapsed = false"> <button v-if="(isLong || (isMFM && defaultStore.state.collapseDefault) || (appearNote.files.length > 0 && defaultStore.state.allMediaNoteCollapse)) && collapsed" v-vibrate="defaultStore.state.vibrateSystem ? 5 : []" :class="$style.collapsed" class="_button" @click="collapsed = false">
<span :class="$style.collapsedLabel"> <span :class="$style.collapsedLabel">
{{ i18n.ts.showMore }} {{ i18n.ts.showMore }}
<span v-if="appearNote.files.length > 0" :class="$style.label">({{ collapseLabel }})</span> <span v-if="appearNote.files.length > 0" :class="$style.label">({{ collapseLabel }})</span>
</span> </span>
</button> </button>
<button v-else-if="(isLong || (isMFM && defaultStore.state.collapseDefault) || (appearNote.files.length > 0 && defaultStore.state.allMediaNoteCollapse)) && !collapsed" v-vibrate="ColdDeviceStorage.get('vibrateSystem') ? 5 : ''" :class="$style.showLess" class="_button" @click="collapsed = true"> <button v-else-if="(isLong || (isMFM && defaultStore.state.collapseDefault) || (appearNote.files.length > 0 && defaultStore.state.allMediaNoteCollapse)) && !collapsed" v-vibrate="defaultStore.state.vibrateSystem ? 5 : []" :class="$style.showLess" class="_button" @click="collapsed = true">
<span :class="$style.showLessLabel">{{ i18n.ts.showLess }}</span> <span :class="$style.showLessLabel">{{ i18n.ts.showLess }}</span>
</button> </button>
</div> </div>
@ -132,7 +132,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</template> </template>
</MkReactionsViewer> </MkReactionsViewer>
<footer :class="$style.footer"> <footer :class="$style.footer">
<button v-if="!note.isHidden" v-vibrate="ColdDeviceStorage.get('vibrateSystem') ? 5 : ''" v-tooltip="i18n.ts.reply" :class="$style.footerButton" class="_button" @click="reply()"> <button v-if="!note.isHidden" v-vibrate="defaultStore.state.vibrateSystem ? 5 : []" v-tooltip="i18n.ts.reply" :class="$style.footerButton" class="_button" @click="reply()">
<i class="ti ti-arrow-back-up"></i> <i class="ti ti-arrow-back-up"></i>
<p v-if="appearNote.repliesCount > 0" :class="$style.footerButtonCount">{{ appearNote.repliesCount }}</p> <p v-if="appearNote.repliesCount > 0" :class="$style.footerButtonCount">{{ appearNote.repliesCount }}</p>
</button> </button>
@ -142,7 +142,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<button <button
v-if="canRenote" v-if="canRenote"
ref="renoteButton" ref="renoteButton"
v-vibrate="ColdDeviceStorage.get('vibrateSystem') ? [30, 30, 60] : ''" v-vibrate="defaultStore.state.vibrateSystem ? [30, 30, 60] : []"
v-tooltip="i18n.ts.renote" v-tooltip="i18n.ts.renote"
:class="$style.footerButton" :class="$style.footerButton"
class="_button" class="_button"
@ -154,26 +154,26 @@ SPDX-License-Identifier: AGPL-3.0-only
<button v-else :class="$style.footerButton" class="_button" disabled> <button v-else :class="$style.footerButton" class="_button" disabled>
<i class="ti ti-ban"></i> <i class="ti ti-ban"></i>
</button> </button>
<button v-if="appearNote.myReaction == null" ref="heartReactButton" v-vibrate="ColdDeviceStorage.get('vibrateSystem') ? [30, 50, 50] : ''" v-tooltip="i18n.ts.like" :class="$style.footerButton" class="_button" @mousedown="heartReact()"> <button v-if="appearNote.myReaction == null" ref="heartReactButton" v-vibrate="defaultStore.state.vibrateSystem ? [30, 50, 50] : []" v-tooltip="i18n.ts.like" :class="$style.footerButton" class="_button" @mousedown="heartReact()">
<i class="ti ti-heart"></i> <i class="ti ti-heart"></i>
</button> </button>
<button v-if="appearNote.reactionAcceptance !== 'likeOnly'" ref="reactButton" v-vibrate="ColdDeviceStorage.get('vibrateSystem') ? [30, 50, 50] : ''" :class="$style.footerButton" class="_button" @mousedown="react()"> <button v-if="appearNote.reactionAcceptance !== 'likeOnly'" ref="reactButton" v-vibrate="defaultStore.state.vibrateSystem ? [30, 50, 50] : []" :class="$style.footerButton" class="_button" @mousedown="react()">
<i v-if="appearNote.myReaction == null" v-tooltip="i18n.ts.reaction" class="ti ti-mood-plus"></i> <i v-if="appearNote.myReaction == null" v-tooltip="i18n.ts.reaction" class="ti ti-mood-plus"></i>
<i v-else v-tooltip="i18n.ts.editReaction" class="ti ti-mood-edit"></i> <i v-else v-tooltip="i18n.ts.editReaction" class="ti ti-mood-edit"></i>
</button> </button>
<button v-if="appearNote.myReaction != null && appearNote.reactionAcceptance == 'likeOnly'" ref="reactButton" v-vibrate="ColdDeviceStorage.get('vibrateSystem') ? [30, 50, 50] : ''" v-tooltip="i18n.ts.removeReaction" :class="$style.footerButton" class="_button" @click="undoReact(appearNote)"> <button v-if="appearNote.myReaction != null && appearNote.reactionAcceptance == 'likeOnly'" ref="reactButton" v-vibrate="defaultStore.state.vibrateSystem ? [30, 50, 50] : []" v-tooltip="i18n.ts.removeReaction" :class="$style.footerButton" class="_button" @click="undoReact(appearNote)">
<i class="ti ti-heart-minus"></i> <i class="ti ti-heart-minus"></i>
</button> </button>
<button v-if="canRenote && defaultStore.state.renoteQuoteButtonSeparation" v-vibrate="ColdDeviceStorage.get('vibrateSystem') ? 5 : ''" v-tooltip="i18n.ts.quote" class="_button" :class="$style.footerButton" @click="quote()"> <button v-if="canRenote && defaultStore.state.renoteQuoteButtonSeparation" v-vibrate="defaultStore.state.vibrateSystem ? 5 : []" v-tooltip="i18n.ts.quote" class="_button" :class="$style.footerButton" @click="quote()">
<i class="ti ti-quote"></i> <i class="ti ti-quote"></i>
</button> </button>
<button v-if="defaultStore.state.showClipButtonInNoteFooter" ref="clipButton" v-vibrate="ColdDeviceStorage.get('vibrateSystem') ? 5 : ''" v-tooltip="i18n.ts.clip" :class="$style.footerButton" class="_button" @mousedown="clip()"> <button v-if="defaultStore.state.showClipButtonInNoteFooter" ref="clipButton" v-vibrate="defaultStore.state.vibrateSystem ? 5 : []" v-tooltip="i18n.ts.clip" :class="$style.footerButton" class="_button" @mousedown="clip()">
<i class="ti ti-paperclip"></i> <i class="ti ti-paperclip"></i>
</button> </button>
<MkA v-if="defaultStore.state.infoButtonForNoteActionsEnabled && defaultStore.state.showNoteActionsOnlyHover" v-tooltip="i18n.ts.details" :to="notePage(note)" :class="$style.footerButton" style="text-decoration: none;" class="_button"> <MkA v-if="defaultStore.state.infoButtonForNoteActionsEnabled && defaultStore.state.showNoteActionsOnlyHover" v-tooltip="i18n.ts.details" :to="notePage(note)" :class="$style.footerButton" style="text-decoration: none;" class="_button">
<i class="ti ti-info-circle"></i> <i class="ti ti-info-circle"></i>
</MkA> </MkA>
<button ref="menuButton" v-vibrate="ColdDeviceStorage.get('vibrateSystem') ? 5 : ''" v-tooltip="i18n.ts.more" :class="$style.footerButton" class="_button" @mousedown="menu()"> <button ref="menuButton" v-vibrate="defaultStore.state.vibrateSystem ? 5 : []" v-tooltip="i18n.ts.more" :class="$style.footerButton" class="_button" @mousedown="menu()">
<i class="ti ti-dots"></i> <i class="ti ti-dots"></i>
</button> </button>
</footer> </footer>
@ -210,7 +210,7 @@ import { focusPrev, focusNext } from '@/scripts/focus.js';
import { checkWordMute } from '@/scripts/check-word-mute.js'; import { checkWordMute } from '@/scripts/check-word-mute.js';
import { userPage } from '@/filters/user.js'; import { userPage } from '@/filters/user.js';
import * as os from '@/os.js'; import * as os from '@/os.js';
import { ColdDeviceStorage, defaultStore, noteViewInterruptors } from '@/store.js'; import { defaultStore, noteViewInterruptors } from '@/store.js';
import { reactionPicker } from '@/scripts/reaction-picker.js'; import { reactionPicker } from '@/scripts/reaction-picker.js';
import { extractUrlFromMfm } from '@/scripts/extract-url-from-mfm.js'; import { extractUrlFromMfm } from '@/scripts/extract-url-from-mfm.js';
import { $i } from '@/account.js'; import { $i } from '@/account.js';
@ -570,7 +570,7 @@ async function translate(): Promise<void> {
if (translation.value != null) return; if (translation.value != null) return;
translating.value = true; translating.value = true;
vibrate(ColdDeviceStorage.get('vibrateSystem') ? 5 : []); vibrate(defaultStore.state.vibrateSystem ? 5 : []);
if (props.mock) { if (props.mock) {
return; return;
@ -583,7 +583,7 @@ async function translate(): Promise<void> {
translating.value = false; translating.value = false;
translation.value = res; translation.value = res;
vibrate(ColdDeviceStorage.get('vibrateSystem') ? [5, 5, 10] : []); vibrate(defaultStore.state.vibrateSystem ? [5, 5, 10] : []);
} }
function showRenoteMenu(viaKeyboard = false): void { function showRenoteMenu(viaKeyboard = false): void {

View file

@ -145,7 +145,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</MkA> </MkA>
</div> </div>
<MkReactionsViewer ref="reactionsViewer" :note="appearNote"/> <MkReactionsViewer ref="reactionsViewer" :note="appearNote"/>
<button v-if="!note.isHidden" v-vibrate="ColdDeviceStorage.get('vibrateSystem') ? 5 : ''" v-tooltip="i18n.ts.reply" class="_button" :class="$style.noteFooterButton" @click="reply()"> <button v-if="!note.isHidden" v-vibrate="defaultStore.state.vibrateSystem ? 5 : []" v-tooltip="i18n.ts.reply" class="_button" :class="$style.noteFooterButton" @click="reply()">
<i class="ti ti-arrow-back-up"></i> <i class="ti ti-arrow-back-up"></i>
<p v-if="appearNote.repliesCount > 0" :class="$style.noteFooterButtonCount">{{ appearNote.repliesCount }}</p> <p v-if="appearNote.repliesCount > 0" :class="$style.noteFooterButtonCount">{{ appearNote.repliesCount }}</p>
</button> </button>
@ -155,7 +155,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<button <button
v-if="canRenote" v-if="canRenote"
ref="renoteButton" ref="renoteButton"
v-vibrate="ColdDeviceStorage.get('vibrateSystem') ? [30, 30, 60] : ''" v-vibrate="defaultStore.state.vibrateSystem ? [30, 30, 60] : []"
v-tooltip="i18n.ts.renote" v-tooltip="i18n.ts.renote"
class="_button" class="_button"
:class="$style.noteFooterButton" :class="$style.noteFooterButton"
@ -167,23 +167,23 @@ SPDX-License-Identifier: AGPL-3.0-only
<button v-else class="_button" :class="$style.noteFooterButton" disabled> <button v-else class="_button" :class="$style.noteFooterButton" disabled>
<i class="ti ti-ban"></i> <i class="ti ti-ban"></i>
</button> </button>
<button v-if="appearNote.myReaction == null" ref="heartReactButton" v-vibrate="ColdDeviceStorage.get('vibrateSystem') ? [30, 50, 50] : ''" v-tooltip="i18n.ts.like" :class="$style.noteFooterButton" class="_button" @mousedown="heartReact()"> <button v-if="appearNote.myReaction == null" ref="heartReactButton" v-vibrate="defaultStore.state.vibrateSystem ? [30, 50, 50] : []" v-tooltip="i18n.ts.like" :class="$style.noteFooterButton" class="_button" @mousedown="heartReact()">
<i class="ti ti-heart"></i> <i class="ti ti-heart"></i>
</button> </button>
<button v-if="appearNote.reactionAcceptance !== 'likeOnly'" ref="reactButton" v-vibrate="ColdDeviceStorage.get('vibrateSystem') ? [30, 50, 50] : ''" :class="$style.noteFooterButton" class="_button" @mousedown="react()"> <button v-if="appearNote.reactionAcceptance !== 'likeOnly'" ref="reactButton" v-vibrate="defaultStore.state.vibrateSystem ? [30, 50, 50] : []" :class="$style.noteFooterButton" class="_button" @mousedown="react()">
<i v-if="appearNote.myReaction == null" v-tooltip="i18n.ts.reaction" class="ti ti-mood-plus"></i> <i v-if="appearNote.myReaction == null" v-tooltip="i18n.ts.reaction" class="ti ti-mood-plus"></i>
<i v-else v-tooltip="i18n.ts.editReaction" class="ti ti-mood-edit"></i> <i v-else v-tooltip="i18n.ts.editReaction" class="ti ti-mood-edit"></i>
</button> </button>
<button v-if="appearNote.myReaction != null && appearNote.reactionAcceptance == 'likeOnly'" ref="reactButton" v-vibrate="ColdDeviceStorage.get('vibrateSystem') ? [30, 50, 50] : ''" v-tooltip="i18n.ts.removeReaction" :class="[$style.noteFooterButton, $style.reacted]" class="_button" @click="undoReact(appearNote)"> <button v-if="appearNote.myReaction != null && appearNote.reactionAcceptance == 'likeOnly'" ref="reactButton" v-vibrate="defaultStore.state.vibrateSystem ? [30, 50, 50] : []" v-tooltip="i18n.ts.removeReaction" :class="[$style.noteFooterButton, $style.reacted]" class="_button" @click="undoReact(appearNote)">
<i class="ti ti-heart-minus"></i> <i class="ti ti-heart-minus"></i>
</button> </button>
<button v-if="canRenote && defaultStore.state.renoteQuoteButtonSeparation" v-vibrate="ColdDeviceStorage.get('vibrateSystem') ? 5 : ''" v-tooltip="i18n.ts.quote" class="_button" :class="$style.noteFooterButton" @click="quote()"> <button v-if="canRenote && defaultStore.state.renoteQuoteButtonSeparation" v-vibrate="defaultStore.state.vibrateSystem ? 5 : []" v-tooltip="i18n.ts.quote" class="_button" :class="$style.noteFooterButton" @click="quote()">
<i class="ti ti-quote"></i> <i class="ti ti-quote"></i>
</button> </button>
<button v-if="defaultStore.state.showClipButtonInNoteFooter" ref="clipButton" v-vibrate="ColdDeviceStorage.get('vibrateSystem') ? 5 : ''" v-tooltip="i18n.ts.clip" class="_button" :class="$style.noteFooterButton" @mousedown="clip()"> <button v-if="defaultStore.state.showClipButtonInNoteFooter" ref="clipButton" v-vibrate="defaultStore.state.vibrateSystem ? 5 : []" v-tooltip="i18n.ts.clip" class="_button" :class="$style.noteFooterButton" @mousedown="clip()">
<i class="ti ti-paperclip"></i> <i class="ti ti-paperclip"></i>
</button> </button>
<button ref="menuButton" v-vibrate="ColdDeviceStorage.get('vibrateSystem') ? 5 : ''" v-tooltip="i18n.ts.more" class="_button" :class="$style.noteFooterButton" @mousedown="menu()"> <button ref="menuButton" v-vibrate="defaultStore.state.vibrateSystem ? 5 : []" v-tooltip="i18n.ts.more" class="_button" :class="$style.noteFooterButton" @mousedown="menu()">
<i class="ti ti-dots"></i> <i class="ti ti-dots"></i>
</button> </button>
</footer> </footer>
@ -292,7 +292,7 @@ import { checkWordMute } from '@/scripts/check-word-mute.js';
import { userPage } from '@/filters/user.js'; import { userPage } from '@/filters/user.js';
import { notePage } from '@/filters/note.js'; import { notePage } from '@/filters/note.js';
import * as os from '@/os.js'; import * as os from '@/os.js';
import { ColdDeviceStorage, defaultStore, noteViewInterruptors } from '@/store.js'; import { defaultStore, noteViewInterruptors } from '@/store.js';
import { reactionPicker } from '@/scripts/reaction-picker.js'; import { reactionPicker } from '@/scripts/reaction-picker.js';
import { extractUrlFromMfm } from '@/scripts/extract-url-from-mfm.js'; import { extractUrlFromMfm } from '@/scripts/extract-url-from-mfm.js';
import { $i } from '@/account.js'; import { $i } from '@/account.js';
@ -595,7 +595,7 @@ async function translate(): Promise<void> {
if (translation.value != null) return; if (translation.value != null) return;
translating.value = true; translating.value = true;
vibrate(ColdDeviceStorage.get('vibrateSystem') ? 5 : []); vibrate(defaultStore.state.vibrateSystem ? 5 : []);
const res = await os.api('notes/translate', { const res = await os.api('notes/translate', {
noteId: appearNote.id, noteId: appearNote.id,
@ -604,7 +604,7 @@ async function translate(): Promise<void> {
translating.value = false; translating.value = false;
translation.value = res; translation.value = res;
vibrate(ColdDeviceStorage.get('vibrateSystem') ? [5, 5, 10] : []); vibrate(defaultStore.state.vibrateSystem ? [5, 5, 10] : []);
} }
async function clip() { async function clip() {

View file

@ -6,7 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<template> <template>
<div ref="content" :class="[$style.content, { [$style.omitted]: omitted }]"> <div ref="content" :class="[$style.content, { [$style.omitted]: omitted }]">
<slot></slot> <slot></slot>
<button v-if="omitted" v-vibrate="ColdDeviceStorage.get('vibrateSystem') ? 5 : ''" :class="$style.fade" class="_button" @click="() => { ignoreOmit = true; omitted = false; }"> <button v-if="omitted" v-vibrate="defaultStore.state.vibrateSystem ? 5 : []" :class="$style.fade" class="_button" @click="() => { ignoreOmit = true; omitted = false; }">
<span :class="$style.fadeLabel">{{ i18n.ts.showMore }}</span> <span :class="$style.fadeLabel">{{ i18n.ts.showMore }}</span>
</button> </button>
</div> </div>
@ -15,7 +15,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<script lang="ts" setup> <script lang="ts" setup>
import { onMounted, onUnmounted } from 'vue'; import { onMounted, onUnmounted } from 'vue';
import { i18n } from '@/i18n.js'; import { i18n } from '@/i18n.js';
import { ColdDeviceStorage } from '@/store.js'; import { defaultStore } from '@/store.js';
const props = withDefaults(defineProps<{ const props = withDefaults(defineProps<{
maxHeight?: number; maxHeight?: number;

View file

@ -114,7 +114,6 @@ const props = defineProps<{
& + article { & + article {
left: 0; left: 0;
width: 100%;
} }
} }
} }
@ -124,6 +123,7 @@ const props = defineProps<{
> .thumbnail { > .thumbnail {
height: 80px; height: 80px;
overflow: clip;
} }
> article { > article {

View file

@ -119,7 +119,7 @@ import { formatTimeString } from '@/scripts/format-time-string.js';
import { Autocomplete } from '@/scripts/autocomplete.js'; import { Autocomplete } from '@/scripts/autocomplete.js';
import * as os from '@/os.js'; import * as os from '@/os.js';
import { selectFiles } from '@/scripts/select-file.js'; import { selectFiles } from '@/scripts/select-file.js';
import { ColdDeviceStorage, defaultStore, notePostInterruptors, postFormActions } from '@/store.js'; import { defaultStore, notePostInterruptors, postFormActions } from '@/store.js';
import MkInfo from '@/components/MkInfo.vue'; import MkInfo from '@/components/MkInfo.vue';
import { i18n } from '@/i18n.js'; import { i18n } from '@/i18n.js';
import { instance } from '@/instance.js'; import { instance } from '@/instance.js';
@ -897,7 +897,7 @@ async function post(ev?: MouseEvent) {
}); });
textareaEl.style.height = '140px'; textareaEl.style.height = '140px';
if (props.updateMode) sound.play('noteEdited'); if (props.updateMode) sound.play('noteEdited');
vibrate(ColdDeviceStorage.get('vibrateSystem') ? [10, 20, 10, 20, 10, 20, 60] : ''); vibrate(defaultStore.state.vibrateSystem ? [10, 20, 10, 20, 10, 20, 60] : []);
} }
function cancel() { function cancel() {

View file

@ -139,7 +139,7 @@ import { formatTimeString } from '@/scripts/format-time-string.js';
import { Autocomplete } from '@/scripts/autocomplete.js'; import { Autocomplete } from '@/scripts/autocomplete.js';
import * as os from '@/os.js'; import * as os from '@/os.js';
import { selectFiles } from '@/scripts/select-file.js'; import { selectFiles } from '@/scripts/select-file.js';
import { ColdDeviceStorage, defaultStore, notePostInterruptors, postFormActions } from '@/store.js'; import { defaultStore, notePostInterruptors, postFormActions } from '@/store.js';
import MkInfo from '@/components/MkInfo.vue'; import MkInfo from '@/components/MkInfo.vue';
import { i18n } from '@/i18n.js'; import { i18n } from '@/i18n.js';
import { instance } from '@/instance.js'; import { instance } from '@/instance.js';
@ -918,7 +918,7 @@ async function post(ev?: MouseEvent) {
}); });
textareaEl.style.height = '35px'; textareaEl.style.height = '35px';
if (props.updateMode) sound.play('noteEdited'); if (props.updateMode) sound.play('noteEdited');
vibrate(ColdDeviceStorage.get('vibrateSystem') ? [10, 20, 10, 20, 10, 20, 60] : ''); vibrate(defaultStore.state.vibrateSystem ? [10, 20, 10, 20, 10, 20, 60] : []);
} }
function cancel() { function cancel() {

View file

@ -28,7 +28,7 @@ import { deviceKind } from '@/scripts/device-kind.js';
import { i18n } from '@/i18n.js'; import { i18n } from '@/i18n.js';
import { getScrollContainer } from '@/scripts/scroll.js'; import { getScrollContainer } from '@/scripts/scroll.js';
import { vibrate } from '@/scripts/vibrate.js'; import { vibrate } from '@/scripts/vibrate.js';
import { ColdDeviceStorage } from '@/store.js'; import { defaultStore } from '@/store.js';
const SCROLL_STOP = 10; const SCROLL_STOP = 10;
const MAX_PULL_DISTANCE = Infinity; const MAX_PULL_DISTANCE = Infinity;
@ -157,7 +157,7 @@ function moving(event: TouchEvent | PointerEvent) {
if (!isPullEnd) isVibrate = false; if (!isPullEnd) isVibrate = false;
else if (isPullEnd && !isVibrate) { else if (isPullEnd && !isVibrate) {
vibrate(ColdDeviceStorage.get('vibrateSystem') ? 10 : []); vibrate(defaultStore.state.vibrateSystem ? 10 : []);
isVibrate = true; isVibrate = true;
} }
} }

View file

@ -6,7 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<template> <template>
<div <div
v-adaptive-border v-adaptive-border
v-vibrate="ColdDeviceStorage.get('vibrateSystem') ? 5 : ''" v-vibrate="defaultStore.state.vibrateSystem ? 5 : []"
:class="[$style.root, { [$style.disabled]: disabled, [$style.checked]: checked }]" :class="[$style.root, { [$style.disabled]: disabled, [$style.checked]: checked }]"
:aria-checked="checked" :aria-checked="checked"
:aria-disabled="disabled" :aria-disabled="disabled"
@ -26,7 +26,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<script lang="ts" setup> <script lang="ts" setup>
import { } from 'vue'; import { } from 'vue';
import { ColdDeviceStorage } from '@/store.js'; import { defaultStore } from '@/store.js';
const props = defineProps<{ const props = defineProps<{
modelValue: any; modelValue: any;

View file

@ -25,7 +25,7 @@ SPDX-License-Identifier: AGPL-3.0-only
import { computed, defineAsyncComponent, onMounted, onUnmounted, ref, watch, shallowRef } from 'vue'; import { computed, defineAsyncComponent, onMounted, onUnmounted, ref, watch, shallowRef } from 'vue';
import * as os from '@/os.js'; import * as os from '@/os.js';
import { vibrate } from '@/scripts/vibrate.js'; import { vibrate } from '@/scripts/vibrate.js';
import { ColdDeviceStorage } from '@/store.js'; import { defaultStore } from '@/store.js';
const props = withDefaults(defineProps<{ const props = withDefaults(defineProps<{
modelValue: number; modelValue: number;
@ -103,7 +103,7 @@ const steps = computed(() => {
}); });
const onMousedown = (ev: MouseEvent | TouchEvent) => { const onMousedown = (ev: MouseEvent | TouchEvent) => {
vibrate(ColdDeviceStorage.get('vibrateSystem') ? 10 : ''); vibrate(defaultStore.state.vibrateSystem ? 10 : []);
ev.preventDefault(); ev.preventDefault();

View file

@ -7,7 +7,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<button <button
ref="buttonEl" ref="buttonEl"
v-ripple="canToggle" v-ripple="canToggle"
v-vibrate="ColdDeviceStorage.get('vibrateSystem') ? [10, 30, 40] : ''" v-vibrate="defaultStore.state.vibrateSystem ? [10, 30, 40] : []"
class="_button" class="_button"
:class="[$style.root, { [$style.reacted]: note.myReaction == reaction, [$style.canToggle]: (canToggle || alternative), [$style.small]: defaultStore.state.reactionsDisplaySize === 'small', [$style.large]: defaultStore.state.reactionsDisplaySize === 'large' }]" :class="[$style.root, { [$style.reacted]: note.myReaction == reaction, [$style.canToggle]: (canToggle || alternative), [$style.small]: defaultStore.state.reactionsDisplaySize === 'small', [$style.large]: defaultStore.state.reactionsDisplaySize === 'large' }]"
@click="toggleReaction()" @click="toggleReaction()"
@ -27,7 +27,7 @@ import { useTooltip } from '@/scripts/use-tooltip.js';
import { $i } from '@/account.js'; import { $i } from '@/account.js';
import MkReactionEffect from '@/components/MkReactionEffect.vue'; import MkReactionEffect from '@/components/MkReactionEffect.vue';
import { claimAchievement } from '@/scripts/achievements.js'; import { claimAchievement } from '@/scripts/achievements.js';
import { ColdDeviceStorage, defaultStore } from '@/store.js'; import { defaultStore } from '@/store.js';
import { i18n } from '@/i18n.js'; import { i18n } from '@/i18n.js';
import { customEmojis } from '@/custom-emojis.js'; import { customEmojis } from '@/custom-emojis.js';

View file

@ -50,13 +50,13 @@ SPDX-License-Identifier: AGPL-3.0-only
</div> </div>
</div> </div>
</div> </div>
<button v-if="(isLong || (isMFM && defaultStore.state.collapseDefault) || note.files.length > 0 || note.poll) && collapsed" v-vibrate="ColdDeviceStorage.get('vibrateSystem') ? 5 : ''" :class="$style.fade" class="_button" @click="collapsed = false;"> <button v-if="(isLong || (isMFM && defaultStore.state.collapseDefault) || note.files.length > 0 || note.poll) && collapsed" v-vibrate="defaultStore.state.vibrateSystem ? 5 : []" :class="$style.fade" class="_button" @click="collapsed = false;">
<span :class="$style.fadeLabel"> <span :class="$style.fadeLabel">
{{ i18n.ts.showMore }} {{ i18n.ts.showMore }}
<span v-if="note.files.length > 0" :class="$style.label">({{ collapseLabel }})</span> <span v-if="note.files.length > 0" :class="$style.label">({{ collapseLabel }})</span>
</span> </span>
</button> </button>
<button v-else-if="(isLong || (isMFM && defaultStore.state.collapseDefault) || note.files.length > 0 || note.poll) && !collapsed" v-vibrate="ColdDeviceStorage.get('vibrateSystem') ? 5 : ''" :class="$style.showLess" class="_button" @click="collapsed = true;"> <button v-else-if="(isLong || (isMFM && defaultStore.state.collapseDefault) || note.files.length > 0 || note.poll) && !collapsed" v-vibrate="defaultStore.state.vibrateSystem ? 5 : []" :class="$style.showLess" class="_button" @click="collapsed = true;">
<span :class="$style.showLessLabel">{{ i18n.ts.showLess }}</span> <span :class="$style.showLessLabel">{{ i18n.ts.showLess }}</span>
</button> </button>
<div v-if="showSubNoteFooterButton"> <div v-if="showSubNoteFooterButton">
@ -66,7 +66,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</template> </template>
</MkReactionsViewer> </MkReactionsViewer>
<footer :class="$style.footer"> <footer :class="$style.footer">
<button v-if="!note.isHidden" v-vibrate="ColdDeviceStorage.get('vibrateSystem') ? 5 : ''" v-tooltip="i18n.ts.reply" :class="$style.footerButton" class="_button" @click="reply()"> <button v-if="!note.isHidden" v-vibrate="defaultStore.state.vibrateSystem ? 5 : []" v-tooltip="i18n.ts.reply" :class="$style.footerButton" class="_button" @click="reply()">
<i class="ti ti-arrow-back-up"></i> <i class="ti ti-arrow-back-up"></i>
<p v-if="note.repliesCount > 0" :class="$style.footerButtonCount">{{ note.repliesCount }}</p> <p v-if="note.repliesCount > 0" :class="$style.footerButtonCount">{{ note.repliesCount }}</p>
</button> </button>
@ -76,7 +76,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<button <button
v-if="canRenote" v-if="canRenote"
ref="renoteButton" ref="renoteButton"
v-vibrate="ColdDeviceStorage.get('vibrateSystem') ? [30, 50, 60] : ''" v-vibrate="defaultStore.state.vibrateSystem ? [30, 50, 60] : []"
v-tooltip="i18n.ts.renote" v-tooltip="i18n.ts.renote"
:class="$style.footerButton" :class="$style.footerButton"
class="_button" class="_button"
@ -88,26 +88,26 @@ SPDX-License-Identifier: AGPL-3.0-only
<button v-else :class="$style.footerButton" class="_button" disabled> <button v-else :class="$style.footerButton" class="_button" disabled>
<i class="ti ti-ban"></i> <i class="ti ti-ban"></i>
</button> </button>
<button v-if="note.myReaction == null" ref="heartReactButton" v-vibrate="ColdDeviceStorage.get('vibrateSystem') ? [30, 50, 50] : ''" v-tooltip="i18n.ts.like" :class="$style.footerButton" class="_button" @mousedown="heartReact()"> <button v-if="note.myReaction == null" ref="heartReactButton" v-vibrate="defaultStore.state.vibrateSystem ? [30, 50, 50] : []" v-tooltip="i18n.ts.like" :class="$style.footerButton" class="_button" @mousedown="heartReact()">
<i class="ti ti-heart"></i> <i class="ti ti-heart"></i>
</button> </button>
<button v-if="note.reactionAcceptance !== 'likeOnly'" ref="reactButton" v-vibrate="ColdDeviceStorage.get('vibrateSystem') ? [30, 50, 50] : ''" :class="$style.footerButton" class="_button" @mousedown="react()"> <button v-if="note.reactionAcceptance !== 'likeOnly'" ref="reactButton" v-vibrate="defaultStore.state.vibrateSystem ? [30, 50, 50] : []" :class="$style.footerButton" class="_button" @mousedown="react()">
<i v-if="note.myReaction == null" v-tooltip="i18n.ts.reaction" class="ti ti-mood-plus"></i> <i v-if="note.myReaction == null" v-tooltip="i18n.ts.reaction" class="ti ti-mood-plus"></i>
<i v-else v-tooltip="i18n.ts.editReaction" class="ti ti-mood-edit"></i> <i v-else v-tooltip="i18n.ts.editReaction" class="ti ti-mood-edit"></i>
</button> </button>
<button v-if="note.myReaction != null && note.reactionAcceptance == 'likeOnly'" ref="reactButton" v-vibrate="ColdDeviceStorage.get('vibrateSystem') ? [30, 50, 50] : ''" v-tooltip="i18n.ts.removeReaction" :class="$style.footerButton" class="_button" @click="undoReact(note)"> <button v-if="note.myReaction != null && note.reactionAcceptance == 'likeOnly'" ref="reactButton" v-vibrate="defaultStore.state.vibrateSystem ? [30, 50, 50] : []" v-tooltip="i18n.ts.removeReaction" :class="$style.footerButton" class="_button" @click="undoReact(note)">
<i class="ti ti-heart-minus"></i> <i class="ti ti-heart-minus"></i>
</button> </button>
<button v-if="canRenote && defaultStore.state.renoteQuoteButtonSeparation" v-vibrate="ColdDeviceStorage.get('vibrateSystem') ? 5 : ''" v-tooltip="i18n.ts.quote" class="_button" :class="$style.footerButton" @click="quote()"> <button v-if="canRenote && defaultStore.state.renoteQuoteButtonSeparation" v-vibrate="defaultStore.state.vibrateSystem ? 5 : []" v-tooltip="i18n.ts.quote" class="_button" :class="$style.footerButton" @click="quote()">
<i class="ti ti-quote"></i> <i class="ti ti-quote"></i>
</button> </button>
<button v-if="defaultStore.state.showClipButtonInNoteFooter" ref="clipButton" v-vibrate="ColdDeviceStorage.get('vibrateSystem') ? 5 : ''" v-tooltip="i18n.ts.clip" :class="$style.footerButton" class="_button" @mousedown="clip()"> <button v-if="defaultStore.state.showClipButtonInNoteFooter" ref="clipButton" v-vibrate="defaultStore.state.vibrateSystem ? 5 : []" v-tooltip="i18n.ts.clip" :class="$style.footerButton" class="_button" @mousedown="clip()">
<i class="ti ti-paperclip"></i> <i class="ti ti-paperclip"></i>
</button> </button>
<MkA v-if="defaultStore.state.infoButtonForNoteActionsEnabled && defaultStore.state.showNoteActionsOnlyHover" v-tooltip="i18n.ts.details" :to="notePage(note)" :class="$style.footerButton" style="text-decoration: none;" class="_button"> <MkA v-if="defaultStore.state.infoButtonForNoteActionsEnabled && defaultStore.state.showNoteActionsOnlyHover" v-tooltip="i18n.ts.details" :to="notePage(note)" :class="$style.footerButton" style="text-decoration: none;" class="_button">
<i class="ti ti-info-circle"></i> <i class="ti ti-info-circle"></i>
</MkA> </MkA>
<button ref="menuButton" v-vibrate="ColdDeviceStorage.get('vibrateSystem') ? 5 : ''" v-tooltip="i18n.ts.more" :class="$style.footerButton" class="_button" @mousedown="menu()"> <button ref="menuButton" v-vibrate="defaultStore.state.vibrateSystem ? 5 : []" v-tooltip="i18n.ts.more" :class="$style.footerButton" class="_button" @mousedown="menu()">
<i class="ti ti-dots"></i> <i class="ti ti-dots"></i>
</button> </button>
</footer> </footer>
@ -128,7 +128,7 @@ import MkReactionsViewer from '@/components/MkReactionsViewer.vue';
import { i18n } from '@/i18n.js'; import { i18n } from '@/i18n.js';
import { $i } from '@/account.js'; import { $i } from '@/account.js';
import { shouldCollapsed, shouldMfmCollapsed } from '@/scripts/collapsed.js'; import { shouldCollapsed, shouldMfmCollapsed } from '@/scripts/collapsed.js';
import { ColdDeviceStorage, defaultStore } from '@/store.js'; import { defaultStore } from '@/store.js';
import { miLocalStorage } from '@/local-storage.js'; import { miLocalStorage } from '@/local-storage.js';
import { instance } from '@/instance.js'; import { instance } from '@/instance.js';
import { notePage } from '@/filters/note.js'; import { notePage } from '@/filters/note.js';
@ -398,7 +398,7 @@ async function translate(): Promise<void> {
if (translation.value != null) return; if (translation.value != null) return;
translating.value = true; translating.value = true;
vibrate(ColdDeviceStorage.get('vibrateSystem') ? 5 : []); vibrate(defaultStore.state.vibrateSystem ? 5 : []);
if (props.mock) { if (props.mock) {
return; return;
@ -411,7 +411,7 @@ async function translate(): Promise<void> {
translating.value = false; translating.value = false;
translation.value = res; translation.value = res;
vibrate(ColdDeviceStorage.get('vibrateSystem') ? [5, 5, 10] : []); vibrate(defaultStore.state.vibrateSystem ? [5, 5, 10] : []);
} }
function focus() { function focus() {

View file

@ -5,7 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<template> <template>
<span <span
v-vibrate="ColdDeviceStorage.get('vibrateSystem') ? 5 : ''" v-vibrate="defaultStore.state.vibrateSystem ? 5 : []"
v-tooltip="checked ? i18n.ts.itsOn : i18n.ts.itsOff" v-tooltip="checked ? i18n.ts.itsOn : i18n.ts.itsOff"
:class="{ :class="{
[$style.button]: true, [$style.button]: true,
@ -22,7 +22,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<script lang="ts" setup> <script lang="ts" setup>
import { toRefs, Ref } from 'vue'; import { toRefs, Ref } from 'vue';
import { i18n } from '@/i18n.js'; import { i18n } from '@/i18n.js';
import { ColdDeviceStorage } from '@/store.js'; import { defaultStore } from '@/store.js';
const props = withDefaults(defineProps<{ const props = withDefaults(defineProps<{
checked: boolean | Ref<boolean>; checked: boolean | Ref<boolean>;

View file

@ -25,7 +25,7 @@ import { useStream } from '@/stream.js';
import * as sound from '@/scripts/sound.js'; import * as sound from '@/scripts/sound.js';
import { $i } from '@/account.js'; import { $i } from '@/account.js';
import { instance } from '@/instance.js'; import { instance } from '@/instance.js';
import { ColdDeviceStorage, defaultStore } from '@/store.js'; import { defaultStore } from '@/store.js';
import { Paging } from '@/components/MkPagination.vue'; import { Paging } from '@/components/MkPagination.vue';
import { i18n } from '@/i18n.js'; import { i18n } from '@/i18n.js';
import { vibrate } from '@/scripts/vibrate.js'; import { vibrate } from '@/scripts/vibrate.js';
@ -85,7 +85,7 @@ const prepend = note => {
if (props.sound) { if (props.sound) {
sound.play($i && (note.userId === $i.id) ? 'noteMy' : 'note'); sound.play($i && (note.userId === $i.id) ? 'noteMy' : 'note');
vibrate($i && (note.userId === $i.id) ? '' : ColdDeviceStorage.get('vibrateNote') ? [30, 20] : ''); vibrate($i && (note.userId === $i.id) ? [] : defaultStore.state.vibrateNote ? [30, 20] : []);
} }
}; };
@ -98,7 +98,7 @@ const prependFilterdMedia = note => {
if (props.sound) { if (props.sound) {
sound.play($i && (note.userId === $i.id) ? 'noteMy' : 'note'); sound.play($i && (note.userId === $i.id) ? 'noteMy' : 'note');
vibrate($i && (note.userId === $i.id) ? '' : ColdDeviceStorage.get('vibrateNote') ? [30, 20] : ''); vibrate($i && (note.userId === $i.id) ? [] : defaultStore.state.vibrateNote ? [30, 20] : []);
} }
}; };

View file

@ -31,7 +31,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<iframe <iframe
ref="tweet" ref="tweet"
allow="fullscreen;web-share" allow="fullscreen;web-share"
sandbox="allow-popups allow-scripts allow-same-origin" sandbox="allow-popups allow-popups-to-escape-sandbox allow-scripts allow-same-origin"
scrolling="no" scrolling="no"
:style="{ position: 'relative', width: '100%', height: `${tweetHeight}px`, border: 0 }" :style="{ position: 'relative', width: '100%', height: `${tweetHeight}px`, border: 0 }"
:src="`https://platform.twitter.com/embed/index.html?embedId=${embedId}&amp;hideCard=false&amp;hideThread=false&amp;lang=en&amp;theme=${defaultStore.state.darkMode ? 'dark' : 'light'}&amp;id=${tweetId}`" :src="`https://platform.twitter.com/embed/index.html?embedId=${embedId}&amp;hideCard=false&amp;hideThread=false&amp;lang=en&amp;theme=${defaultStore.state.darkMode ? 'dark' : 'light'}&amp;id=${tweetId}`"

View file

@ -6,10 +6,10 @@ SPDX-License-Identifier: AGPL-3.0-only
<template> <template>
<div v-if="show" ref="el" :class="[$style.root, {[$style.slim]: narrow, [$style.thin]: thin_, [$style.reduceBlurEffect]: !defaultStore.state.useBlurEffect }]" :style="{ background: bg }"> <div v-if="show" ref="el" :class="[$style.root, {[$style.slim]: narrow, [$style.thin]: thin_, [$style.reduceBlurEffect]: !defaultStore.state.useBlurEffect }]" :style="{ background: bg }">
<div v-if="!thin_ && !canBack" :class="$style.buttonsLeft"> <div v-if="!thin_ && !canBack" :class="$style.buttonsLeft">
<button v-vibrate="ColdDeviceStorage.get('vibrateSystem') ? 5 : ''" class="_button" :class="[$style.button, $style.goBack]" @click.stop="goBack" @touchstart="preventDrag"><i class="ti ti-arrow-left"></i></button> <button v-vibrate="defaultStore.state.vibrateSystem ? 5 : []" class="_button" :class="[$style.button, $style.goBack]" @click.stop="goBack" @touchstart="preventDrag"><i class="ti ti-arrow-left"></i></button>
</div> </div>
<div v-if="!thin_ && narrow && props.displayMyAvatar && $i && !isFriendly" class="_button" :class="$style.buttonsLeft" @click="openAccountMenu"> <div v-if="!thin_ && narrow && props.displayMyAvatar && $i && !isFriendly" class="_button" :class="$style.buttonsLeft" @click="openAccountMenu">
<MkAvatar v-vibrate="ColdDeviceStorage.get('vibrateSystem') ? 5 : ''" :class="$style.avatar" :user="$i"/> <MkAvatar v-vibrate="defaultStore.state.vibrateSystem ? 5 : []" :class="$style.avatar" :user="$i"/>
</div> </div>
<div v-else-if="!thin_ && narrow && !hideTitle && canBack" :class="$style.buttonsLeft"/> <div v-else-if="!thin_ && narrow && !hideTitle && canBack" :class="$style.buttonsLeft"/>
<div v-else-if="!thin_ && canBack && (actions && actions.length > 0)" :class="$style.buttonsLeft"/> <div v-else-if="!thin_ && canBack && (actions && actions.length > 0)" :class="$style.buttonsLeft"/>
@ -48,7 +48,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<div v-if="!thin_ && !narrow && (actions && actions.length > 0) && hideTitle && ['index'].includes(<string>mainRouter.currentRoute.value.name)" :class="$style.buttonsRight"/> <div v-if="!thin_ && !narrow && (actions && actions.length > 0) && hideTitle && ['index'].includes(<string>mainRouter.currentRoute.value.name)" :class="$style.buttonsRight"/>
<div v-if="(!thin_ && narrow && !hideTitle) || (actions && actions.length > 0)" :class="$style.buttonsRight"> <div v-if="(!thin_ && narrow && !hideTitle) || (actions && actions.length > 0)" :class="$style.buttonsRight">
<template v-for="action in actions"> <template v-for="action in actions">
<button v-vibrate="ColdDeviceStorage.get('vibrateSystem') ? 5 : ''" v-tooltip.noDelay="action.text" class="_button" :class="[$style.button, { [$style.highlighted]: action.highlighted }]" @click.stop="action.handler" @touchstart="preventDrag"><i :class="action.icon"></i></button> <button v-vibrate="defaultStore.state.vibrateSystem ? 5 : []" v-tooltip.noDelay="action.text" class="_button" :class="[$style.button, { [$style.highlighted]: action.highlighted }]" @click.stop="action.handler" @touchstart="preventDrag"><i :class="action.icon"></i></button>
</template> </template>
</div> </div>
<div v-else-if="!thin_ && !canBack && !(actions && actions.length > 0)" :class="$style.buttonsRight"/> <div v-else-if="!thin_ && !canBack && !(actions && actions.length > 0)" :class="$style.buttonsRight"/>
@ -69,7 +69,7 @@ import { miLocalStorage } from '@/local-storage.js';
import { mainRouter } from '@/router.js'; import { mainRouter } from '@/router.js';
import * as os from '@/os.js'; import * as os from '@/os.js';
import { i18n } from '@/i18n.js'; import { i18n } from '@/i18n.js';
import { ColdDeviceStorage, defaultStore } from '@/store.js'; import { defaultStore } from '@/store.js';
import MkFollowButton from '@/components/MkFollowButton.vue'; import MkFollowButton from '@/components/MkFollowButton.vue';
let showFollowButton = $ref(false); let showFollowButton = $ref(false);

View file

@ -4,7 +4,7 @@ SPDX-License-Identifier: AGPL-3.0-only
--> -->
<template> <template>
<a v-vibrate="ColdDeviceStorage.get('vibrateSystem') ? 5 : ''" :href="to" :class="active ? activeClass : null" @click.prevent="nav" @contextmenu.prevent.stop="onContextmenu"> <a v-vibrate="defaultStore.state.vibrateSystem ? 5 : []" :href="to" :class="active ? activeClass : null" @click.prevent="nav" @contextmenu.prevent.stop="onContextmenu">
<slot></slot> <slot></slot>
</a> </a>
</template> </template>
@ -16,7 +16,7 @@ import { url } from '@/config.js';
import { popout as popout_ } from '@/scripts/popout.js'; import { popout as popout_ } from '@/scripts/popout.js';
import { i18n } from '@/i18n.js'; import { i18n } from '@/i18n.js';
import { useRouter } from '@/router.js'; import { useRouter } from '@/router.js';
import { ColdDeviceStorage } from '@/store.js'; import { defaultStore } from '@/store.js';
const props = withDefaults(defineProps<{ const props = withDefaults(defineProps<{
to: string; to: string;

View file

@ -7,7 +7,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<div ref="el" :class="$style.tabs" @wheel="onTabWheel"> <div ref="el" :class="$style.tabs" @wheel="onTabWheel">
<div :class="$style.tabsInner"> <div :class="$style.tabsInner">
<button <button
v-for="t in tabs" :ref="(el) => tabRefs[t.key] = (el as HTMLElement)" v-vibrate="ColdDeviceStorage.get('vibrateSystem') ? 5 : ''" v-tooltip.noDelay="t.title" v-for="t in tabs" :ref="(el) => tabRefs[t.key] = (el as HTMLElement)" v-vibrate="defaultStore.state.vibrateSystem ? 5 : []" v-tooltip.noDelay="t.title"
class="_button" :class="[$style.tab, { [$style.active]: t.key != null && t.key === props.tab, [$style.animate]: defaultStore.reactiveState.animation.value }]" class="_button" :class="[$style.tab, { [$style.active]: t.key != null && t.key === props.tab, [$style.animate]: defaultStore.reactiveState.animation.value }]"
@mousedown="(ev) => onTabMousedown(t, ev)" @click="(ev) => onTabClick(t, ev)" @mousedown="(ev) => onTabMousedown(t, ev)" @click="(ev) => onTabClick(t, ev)"
> >
@ -54,7 +54,7 @@ export type Tab = {
<script lang="ts" setup> <script lang="ts" setup>
import { onMounted, onUnmounted, watch, nextTick, shallowRef } from 'vue'; import { onMounted, onUnmounted, watch, nextTick, shallowRef } from 'vue';
import { ColdDeviceStorage, defaultStore } from '@/store.js'; import { defaultStore } from '@/store.js';
const props = withDefaults(defineProps<{ const props = withDefaults(defineProps<{
tabs?: Tab[]; tabs?: Tab[];

View file

@ -7,10 +7,10 @@ SPDX-License-Identifier: AGPL-3.0-only
<div v-if="show" ref="el" :class="[$style.root, { [$style.reduceBlurEffect]: !defaultStore.state.useBlurEffect }]" :style="{ background: bg }"> <div v-if="show" ref="el" :class="[$style.root, { [$style.reduceBlurEffect]: !defaultStore.state.useBlurEffect }]" :style="{ background: bg }">
<div :class="[$style.upper, { [$style.slim]: narrow || isFriendly, [$style.thin]: thin_, [$style.hideTitle]: hideTitle && isFriendly }]"> <div :class="[$style.upper, { [$style.slim]: narrow || isFriendly, [$style.thin]: thin_, [$style.hideTitle]: hideTitle && isFriendly }]">
<div v-if="!thin_ && !canBack" :class="$style.buttonsLeft"> <div v-if="!thin_ && !canBack" :class="$style.buttonsLeft">
<button v-vibrate="ColdDeviceStorage.get('vibrateSystem') ? 5 : ''" class="_button" :class="[$style.button, $style.goBack]" @click.stop="goBack" @touchstart="preventDrag"><i class="ti ti-arrow-left"></i></button> <button v-vibrate="defaultStore.state.vibrateSystem ? 5 : []" class="_button" :class="[$style.button, $style.goBack]" @click.stop="goBack" @touchstart="preventDrag"><i class="ti ti-arrow-left"></i></button>
</div> </div>
<div v-if="!thin_ && narrow && props.displayMyAvatar && $i && !isFriendly" class="_button" :class="$style.buttonsLeft" @click="openAccountMenu"> <div v-if="!thin_ && narrow && props.displayMyAvatar && $i && !isFriendly" class="_button" :class="$style.buttonsLeft" @click="openAccountMenu">
<MkAvatar v-vibrate="ColdDeviceStorage.get('vibrateSystem') ? 5 : ''" :class="$style.avatar" :user="$i"/> <MkAvatar v-vibrate="defaultStore.state.vibrateSystem ? 5 : []" :class="$style.avatar" :user="$i"/>
</div> </div>
<div v-else-if="!thin_ && narrow && !hideTitle && canBack" :class="$style.buttonsLeft"/> <div v-else-if="!thin_ && narrow && !hideTitle && canBack" :class="$style.buttonsLeft"/>
<div v-if="!thin_ && (actions && actions.length > 1) && isFriendly" :class="$style.buttonsLeft" style="min-width: initial; margin-right: initial;"> <div v-if="!thin_ && (actions && actions.length > 1) && isFriendly" :class="$style.buttonsLeft" style="min-width: initial; margin-right: initial;">
@ -47,7 +47,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<div v-if="!thin_ && !narrow && (actions && actions.length > 0) && hideTitle && ['index'].includes(<string>mainRouter.currentRoute.value.name)" :class="$style.buttonsRight"/> <div v-if="!thin_ && !narrow && (actions && actions.length > 0) && hideTitle && ['index'].includes(<string>mainRouter.currentRoute.value.name)" :class="$style.buttonsRight"/>
<div v-if="(!thin_ && narrow && !hideTitle) || (actions && actions.length > 0)" :class="$style.buttonsRight"> <div v-if="(!thin_ && narrow && !hideTitle) || (actions && actions.length > 0)" :class="$style.buttonsRight">
<template v-for="action in actions"> <template v-for="action in actions">
<button v-vibrate="ColdDeviceStorage.get('vibrateSystem') ? 5 : ''" v-tooltip.noDelay="action.text" class="_button" :class="[$style.button, { [$style.highlighted]: action.highlighted }]" @click.stop="action.handler" @touchstart="preventDrag"><i :class="action.icon"></i></button> <button v-vibrate="defaultStore.state.vibrateSystem ? 5 : []" v-tooltip.noDelay="action.text" class="_button" :class="[$style.button, { [$style.highlighted]: action.highlighted }]" @click.stop="action.handler" @touchstart="preventDrag"><i :class="action.icon"></i></button>
</template> </template>
</div> </div>
<div v-else-if="!thin_ && !canBack && !(actions && actions.length > 0)" :class="$style.buttonsRight"/> <div v-else-if="!thin_ && !canBack && !(actions && actions.length > 0)" :class="$style.buttonsRight"/>
@ -73,7 +73,7 @@ import { miLocalStorage } from '@/local-storage.js';
import { mainRouter } from '@/router.js'; import { mainRouter } from '@/router.js';
import * as os from '@/os.js'; import * as os from '@/os.js';
import { i18n } from '@/i18n.js'; import { i18n } from '@/i18n.js';
import { ColdDeviceStorage, defaultStore } from '@/store.js'; import { defaultStore } from '@/store.js';
import MkFollowButton from '@/components/MkFollowButton.vue'; import MkFollowButton from '@/components/MkFollowButton.vue';
let showFollowButton = $ref(false); let showFollowButton = $ref(false);

View file

@ -122,9 +122,9 @@ SPDX-License-Identifier: AGPL-3.0-only
</span> </span>
</span> </span>
</a> </a>
<a href="https://github.com/taichanNE30" target="_blank" :class="$style.contributor"> <a href="https://github.com/tai-cha" target="_blank" :class="$style.contributor">
<img src="https://avatars.githubusercontent.com/u/40626578?v=4" :class="$style.contributorAvatar"> <img src="https://avatars.githubusercontent.com/u/40626578?v=4" :class="$style.contributorAvatar">
<span :class="$style.contributorUsername">@taichanNE30 <span :class="$style.contributorUsername">@tai-cha
<span :class="$style.contributorClient"> <span :class="$style.contributorClient">
<span :class="$style.misskey">Misskey</span> <span :class="$style.misskey">Misskey</span>
</span> </span>

View file

@ -120,6 +120,10 @@ SPDX-License-Identifier: AGPL-3.0-only
</template> </template>
</MkFolder> </MkFolder>
<div>
<MkButton v-if="iAmModerator" inline danger style="margin-right: 8px;" @click="unsetUserAvatar"><i class="ti ti-user-circle"></i> {{ i18n.ts.unsetUserAvatar }}</MkButton>
<MkButton v-if="iAmModerator" inline danger @click="unsetUserBanner"><i class="ti ti-photo"></i> {{ i18n.ts.unsetUserBanner }}</MkButton>
</div>
<MkButton v-if="$i.isAdmin" inline danger @click="deleteAccount">{{ i18n.ts.deleteAccount }}</MkButton> <MkButton v-if="$i.isAdmin" inline danger @click="deleteAccount">{{ i18n.ts.deleteAccount }}</MkButton>
</div> </div>
</FormSection> </FormSection>
@ -319,6 +323,44 @@ async function toggleSuspend(v) {
} }
} }
async function unsetUserAvatar() {
const confirm = await os.confirm({
type: 'warning',
text: i18n.ts.unsetUserAvatarConfirm,
});
if (confirm.canceled) return;
const process = async () => {
await os.api('admin/unset-user-avatar', { userId: user.id });
os.success();
};
await process().catch(err => {
os.alert({
type: 'error',
text: err.toString(),
});
});
refreshUser();
}
async function unsetUserBanner() {
const confirm = await os.confirm({
type: 'warning',
text: i18n.ts.unsetUserBannerConfirm,
});
if (confirm.canceled) return;
const process = async () => {
await os.api('admin/unset-user-banner', { userId: user.id });
os.success();
};
await process().catch(err => {
os.alert({
type: 'error',
text: err.toString(),
});
});
refreshUser();
}
async function deleteAllFiles() { async function deleteAllFiles() {
const confirm = await os.confirm({ const confirm = await os.confirm({
type: 'warning', type: 'warning',

View file

@ -6,7 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<template> <template>
<div ref="el" class="fdidabkc" :style="{ background: bg }" @click="onClick"> <div ref="el" class="fdidabkc" :style="{ background: bg }" @click="onClick">
<div class="buttons left"> <div class="buttons left">
<button v-vibrate="ColdDeviceStorage.get('vibrateSystem') ? 5 : ''" class="_button button goBack" @click.stop="goBack" @touchstart="preventDrag"><i class="ti ti-arrow-left"></i></button> <button v-vibrate="defaultStore.state.vibrateSystem ? 5 : []" class="_button button goBack" @click.stop="goBack" @touchstart="preventDrag"><i class="ti ti-arrow-left"></i></button>
</div> </div>
<template v-if="metadata"> <template v-if="metadata">
<div class="titleContainer" @click="showTabsPopup"> <div class="titleContainer" @click="showTabsPopup">
@ -28,7 +28,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<template v-if="actions"> <template v-if="actions">
<template v-for="action in actions"> <template v-for="action in actions">
<MkButton v-if="action.asFullButton" class="fullButton" primary @click.stop="action.handler"><i :class="action.icon" style="margin-right: 6px;"></i>{{ action.text }}</MkButton> <MkButton v-if="action.asFullButton" class="fullButton" primary @click.stop="action.handler"><i :class="action.icon" style="margin-right: 6px;"></i>{{ action.text }}</MkButton>
<button v-else v-vibrate="ColdDeviceStorage.get('vibrateSystem') ? 5 : ''" v-tooltip.noDelay="action.text" class="_button button" :class="{ highlighted: action.highlighted }" @click.stop="action.handler" @touchstart="preventDrag"><i :class="action.icon"></i></button> <button v-else v-vibrate="defaultStore.state.vibrateSystem ? 5 : []" v-tooltip.noDelay="action.text" class="_button button" :class="{ highlighted: action.highlighted }" @click.stop="action.handler" @touchstart="preventDrag"><i :class="action.icon"></i></button>
</template> </template>
</template> </template>
</div> </div>
@ -44,7 +44,7 @@ import MkButton from '@/components/MkButton.vue';
import { globalEvents } from '@/events.js'; import { globalEvents } from '@/events.js';
import { injectPageMetadata } from '@/scripts/page-metadata.js'; import { injectPageMetadata } from '@/scripts/page-metadata.js';
import { deviceKind } from '@/scripts/device-kind.js'; import { deviceKind } from '@/scripts/device-kind.js';
import { ColdDeviceStorage } from '@/store.js'; import { defaultStore } from '@/store.js';
const MOBILE_THRESHOLD = 500; const MOBILE_THRESHOLD = 500;

View file

@ -9,12 +9,15 @@ SPDX-License-Identifier: AGPL-3.0-only
<XHeader :actions="headerActions" :tabs="headerTabs"/> <XHeader :actions="headerActions" :tabs="headerTabs"/>
</template> </template>
<MkSpacer :contentMax="900"> <MkSpacer :contentMax="900">
<MkSwitch :modelValue="publishing" @update:modelValue="onChangePublishing"> <MkSelect v-model="type" :class="$style.input" @update:modelValue="onChangePublishing">
{{ i18n.ts.publishing }} <template #label>{{ i18n.ts.state }}</template>
</MkSwitch> <option value="null">{{ i18n.ts.all }}</option>
<option value="true">{{ i18n.ts.publishing }}</option>
<option value="false">{{ i18n.ts.expired }}</option>
</MkSelect>
<div> <div>
<div v-for="ad in ads" class="_panel _gaps_m" :class="$style.ad"> <div v-for="ad in ads" class="_panel _gaps_m" :class="$style.ad">
<MkAd v-if="ad.url" :specify="ad"/> <MkAd v-if="ad.url" :key="ad.id" :specify="ad"/>
<MkInput v-model="ad.url" type="url"> <MkInput v-model="ad.url" type="url">
<template #label>URL</template> <template #label>URL</template>
</MkInput> </MkInput>
@ -80,14 +83,14 @@ SPDX-License-Identifier: AGPL-3.0-only
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { } from 'vue'; import { ref } from 'vue';
import XHeader from './_header_.vue'; import XHeader from './_header_.vue';
import MkButton from '@/components/MkButton.vue'; import MkButton from '@/components/MkButton.vue';
import MkInput from '@/components/MkInput.vue'; import MkInput from '@/components/MkInput.vue';
import MkTextarea from '@/components/MkTextarea.vue'; import MkTextarea from '@/components/MkTextarea.vue';
import MkRadios from '@/components/MkRadios.vue'; import MkRadios from '@/components/MkRadios.vue';
import MkFolder from '@/components/MkFolder.vue'; import MkFolder from '@/components/MkFolder.vue';
import MkSwitch from '@/components/MkSwitch.vue'; import MkSelect from '@/components/MkSelect.vue';
import FormSplit from '@/components/form/split.vue'; import FormSplit from '@/components/form/split.vue';
import * as os from '@/os.js'; import * as os from '@/os.js';
import { i18n } from '@/i18n.js'; import { i18n } from '@/i18n.js';
@ -99,9 +102,11 @@ let ads: any[] = $ref([]);
const localTime = new Date(); const localTime = new Date();
const localTimeDiff = localTime.getTimezoneOffset() * 60 * 1000; const localTimeDiff = localTime.getTimezoneOffset() * 60 * 1000;
const daysOfWeek: string[] = [i18n.ts._weekday.sunday, i18n.ts._weekday.monday, i18n.ts._weekday.tuesday, i18n.ts._weekday.wednesday, i18n.ts._weekday.thursday, i18n.ts._weekday.friday, i18n.ts._weekday.saturday]; const daysOfWeek: string[] = [i18n.ts._weekday.sunday, i18n.ts._weekday.monday, i18n.ts._weekday.tuesday, i18n.ts._weekday.wednesday, i18n.ts._weekday.thursday, i18n.ts._weekday.friday, i18n.ts._weekday.saturday];
let publishing = false; let publishing: boolean | null = null;
let type = ref('null');
os.api('admin/ad/list', { publishing: publishing }).then(adsResponse => { os.api('admin/ad/list', { publishing: publishing }).then(adsResponse => {
if (adsResponse != null) {
ads = adsResponse.map(r => { ads = adsResponse.map(r => {
const exdate = new Date(r.expiresAt); const exdate = new Date(r.expiresAt);
const stdate = new Date(r.startsAt); const stdate = new Date(r.startsAt);
@ -113,10 +118,12 @@ os.api('admin/ad/list', { publishing: publishing }).then(adsResponse => {
startsAt: stdate.toISOString().slice(0, 16), startsAt: stdate.toISOString().slice(0, 16),
}; };
}); });
}
}); });
const onChangePublishing = (v) => { const onChangePublishing = (v) => {
publishing = v; console.log(v);
publishing = v === 'true' ? true : v === 'false' ? false : null;
refresh(); refresh();
}; };
@ -195,6 +202,7 @@ function save(ad) {
function more() { function more() {
os.api('admin/ad/list', { untilId: ads.reduce((acc, ad) => ad.id != null ? ad : acc).id, publishing: publishing }).then(adsResponse => { os.api('admin/ad/list', { untilId: ads.reduce((acc, ad) => ad.id != null ? ad : acc).id, publishing: publishing }).then(adsResponse => {
if (adsResponse == null) return;
ads = ads.concat(adsResponse.map(r => { ads = ads.concat(adsResponse.map(r => {
const exdate = new Date(r.expiresAt); const exdate = new Date(r.expiresAt);
const stdate = new Date(r.startsAt); const stdate = new Date(r.startsAt);
@ -211,6 +219,7 @@ function more() {
function refresh() { function refresh() {
os.api('admin/ad/list', { publishing: publishing }).then(adsResponse => { os.api('admin/ad/list', { publishing: publishing }).then(adsResponse => {
if (adsResponse == null) return;
ads = adsResponse.map(r => { ads = adsResponse.map(r => {
const exdate = new Date(r.expiresAt); const exdate = new Date(r.expiresAt);
const stdate = new Date(r.startsAt); const stdate = new Date(r.startsAt);
@ -250,4 +259,7 @@ definePageMetadata({
margin-bottom: var(--margin); margin-bottom: var(--margin);
} }
} }
.input {
margin-bottom: 32px;
}
</style> </style>

View file

@ -73,6 +73,13 @@ SPDX-License-Identifier: AGPL-3.0-only
<MkSwitch v-model="enableActiveEmailValidation" @update:modelValue="save"> <MkSwitch v-model="enableActiveEmailValidation" @update:modelValue="save">
<template #label>Enable</template> <template #label>Enable</template>
</MkSwitch> </MkSwitch>
<MkSwitch v-model="enableVerifymailApi" @update:modelValue="save">
<template #label>Use Verifymail API</template>
</MkSwitch>
<MkInput v-model="verifymailAuthKey" @update:modelValue="save">
<template #prefix><i class="ti ti-key"></i></template>
<template #label>Verifymail API Auth Key</template>
</MkInput>
</div> </div>
</MkFolder> </MkFolder>
@ -132,6 +139,8 @@ let setSensitiveFlagAutomatically: boolean = $ref(false);
let enableSensitiveMediaDetectionForVideos: boolean = $ref(false); let enableSensitiveMediaDetectionForVideos: boolean = $ref(false);
let enableIpLogging: boolean = $ref(false); let enableIpLogging: boolean = $ref(false);
let enableActiveEmailValidation: boolean = $ref(false); let enableActiveEmailValidation: boolean = $ref(false);
let enableVerifymailApi: boolean = $ref(false);
let verifymailAuthKey: string | null = $ref(null);
async function init() { async function init() {
const meta = await os.api('admin/meta'); const meta = await os.api('admin/meta');
@ -150,6 +159,8 @@ async function init() {
enableSensitiveMediaDetectionForVideos = meta.enableSensitiveMediaDetectionForVideos; enableSensitiveMediaDetectionForVideos = meta.enableSensitiveMediaDetectionForVideos;
enableIpLogging = meta.enableIpLogging; enableIpLogging = meta.enableIpLogging;
enableActiveEmailValidation = meta.enableActiveEmailValidation; enableActiveEmailValidation = meta.enableActiveEmailValidation;
enableVerifymailApi = meta.enableVerifymailApi;
verifymailAuthKey = meta.verifymailAuthKey;
} }
function save() { function save() {
@ -167,6 +178,8 @@ function save() {
enableSensitiveMediaDetectionForVideos, enableSensitiveMediaDetectionForVideos,
enableIpLogging, enableIpLogging,
enableActiveEmailValidation, enableActiveEmailValidation,
enableVerifymailApi,
verifymailAuthKey,
}).then(() => { }).then(() => {
fetchInstance(); fetchInstance();
}); });

View file

@ -69,7 +69,7 @@ import { useStream } from '@/stream.js';
import * as sound from '@/scripts/sound.js'; import * as sound from '@/scripts/sound.js';
import { i18n } from '@/i18n.js'; import { i18n } from '@/i18n.js';
import { $i } from '@/account.js'; import { $i } from '@/account.js';
import { ColdDeviceStorage, defaultStore } from '@/store.js'; import { defaultStore } from '@/store.js';
import { definePageMetadata } from '@/scripts/page-metadata.js'; import { definePageMetadata } from '@/scripts/page-metadata.js';
import { vibrate } from '@/scripts/vibrate.js'; import { vibrate } from '@/scripts/vibrate.js';
import { miLocalStorage } from '@/local-storage.js'; import { miLocalStorage } from '@/local-storage.js';
@ -210,7 +210,7 @@ function onDrop(ev: DragEvent): void {
function onMessage(message) { function onMessage(message) {
sound.play('chat'); sound.play('chat');
vibrate(ColdDeviceStorage.get('vibrateChat') ? [30, 30, 30] : ''); vibrate(defaultStore.state.vibrateChat ? [30, 30, 30] : []);
const _isBottom = isBottomVisible($$(rootEl).value, 64); const _isBottom = isBottomVisible($$(rootEl).value, 64);

View file

@ -54,22 +54,24 @@ import { miLocalStorage } from '@/local-storage.js';
const { t, ts } = i18n; const { t, ts } = i18n;
const defaultStoreSaveKeys: (keyof typeof defaultStore['state'])[] = [ const defaultStoreSaveKeys: (keyof typeof defaultStore['state'])[] = [
'collapseRenotes',
'menu', 'menu',
'visibility', 'visibility',
'localOnly', 'localOnly',
'statusbars', 'statusbars',
'widgets', 'widgets',
'tl', 'tl',
'pinnedUserLists',
'overridedDeviceKind', 'overridedDeviceKind',
'serverDisconnectedBehavior', 'serverDisconnectedBehavior',
'collapseRenotes',
'showNoteActionsOnlyHover',
'nsfw', 'nsfw',
'highlightSensitiveMedia',
'animation', 'animation',
'animatedMfm', 'animatedMfm',
'advancedMfm', 'advancedMfm',
'loadRawImages', 'loadRawImages',
'imageNewTab', 'imageNewTab',
'enableDataSaverMode',
'disableShowingAnimatedImages', 'disableShowingAnimatedImages',
'showingAnimatedImages', 'showingAnimatedImages',
'emojiStyle', 'emojiStyle',
@ -90,10 +92,23 @@ const defaultStoreSaveKeys: (keyof typeof defaultStore['state'])[] = [
'menuDisplay', 'menuDisplay',
'reportError', 'reportError',
'squareAvatars', 'squareAvatars',
'hideAvatarsInNote', 'showAvatarDecorations',
'numberOfPageCache', 'numberOfPageCache',
'showNoteActionsOnlyHover',
'showClipButtonInNoteFooter',
'reactionsDisplaySize',
'forceShowAds',
'aiChanMode', 'aiChanMode',
'devMode',
'mediaListWithOneImageAppearance', 'mediaListWithOneImageAppearance',
'notificationPosition',
'notificationStackAxis',
'enableCondensedLineForAcct',
'keepScreenOn',
'defaultWithReplies',
'disableStreamingTimeline',
'useGroupedNotifications',
'hideAvatarsInNote',
'newNoteReceivedNotificationBehavior', 'newNoteReceivedNotificationBehavior',
'collapseDefault', 'collapseDefault',
'requireRefreshBehavior', 'requireRefreshBehavior',
@ -121,12 +136,6 @@ const defaultStoreSaveKeys: (keyof typeof defaultStore['state'])[] = [
'renameTheButtonInPostFormToNya', 'renameTheButtonInPostFormToNya',
'showReplyInNotification', 'showReplyInNotification',
'renoteQuoteButtonSeparation', 'renoteQuoteButtonSeparation',
];
const coldDeviceStorageSaveKeys: (keyof typeof ColdDeviceStorage.default)[] = [
'lightTheme',
'darkTheme',
'syncDeviceDarkMode',
'plugins',
'vibrate', 'vibrate',
'vibrateNote', 'vibrateNote',
'vibrateNotification', 'vibrateNotification',
@ -143,6 +152,12 @@ const coldDeviceStorageSaveKeys: (keyof typeof ColdDeviceStorage.default)[] = [
'sound_antenna', 'sound_antenna',
'sound_channel', 'sound_channel',
]; ];
const coldDeviceStorageSaveKeys: (keyof typeof ColdDeviceStorage.default)[] = [
'lightTheme',
'darkTheme',
'syncDeviceDarkMode',
'plugins',
];
const scope = ['clientPreferencesProfiles']; const scope = ['clientPreferencesProfiles'];

View file

@ -48,7 +48,7 @@ import MkFolder from '@/components/MkFolder.vue';
import MkSwitch from '@/components/MkSwitch.vue'; import MkSwitch from '@/components/MkSwitch.vue';
import { i18n } from '@/i18n.js'; import { i18n } from '@/i18n.js';
import { definePageMetadata } from '@/scripts/page-metadata.js'; import { definePageMetadata } from '@/scripts/page-metadata.js';
import { ColdDeviceStorage, defaultStore } from '@/store.js'; import { defaultStore } from '@/store.js';
import { unisonReload } from '@/scripts/unison-reload.js'; import { unisonReload } from '@/scripts/unison-reload.js';
const masterVolume = computed(defaultStore.makeGetterSetter('sound_masterVolume')); const masterVolume = computed(defaultStore.makeGetterSetter('sound_masterVolume'));
@ -66,12 +66,12 @@ const sounds = ref<Record<typeof soundsKeys[number], Ref<any>>>({
channel: defaultStore.reactiveState.sound_channel, channel: defaultStore.reactiveState.sound_channel,
}); });
const vibrate = computed(ColdDeviceStorage.makeGetterSetter('vibrate')); const vibrate = computed(defaultStore.makeGetterSetter('vibrate'));
const vibrateNote = computed(ColdDeviceStorage.makeGetterSetter('vibrateNote')); const vibrateNote = computed(defaultStore.makeGetterSetter('vibrateNote'));
const vibrateNotification = computed(ColdDeviceStorage.makeGetterSetter('vibrateNotification')); const vibrateNotification = computed(defaultStore.makeGetterSetter('vibrateNotification'));
const vibrateChat = computed(ColdDeviceStorage.makeGetterSetter('vibrateChat')); const vibrateChat = computed(defaultStore.makeGetterSetter('vibrateChat'));
const vibrateChatBg = computed(ColdDeviceStorage.makeGetterSetter('vibrateChatBg')); const vibrateChatBg = computed(defaultStore.makeGetterSetter('vibrateChatBg'));
const vibrateSystem = computed(ColdDeviceStorage.makeGetterSetter('vibrateSystem')); const vibrateSystem = computed(defaultStore.makeGetterSetter('vibrateSystem'));
async function reloadAsk() { async function reloadAsk() {
const { canceled } = await os.confirm({ const { canceled } = await os.confirm({

View file

@ -183,7 +183,7 @@ import { confetti } from '@/scripts/confetti.js';
import MkNotes from '@/components/MkNotes.vue'; import MkNotes from '@/components/MkNotes.vue';
import { api } from '@/os.js'; import { api } from '@/os.js';
import { isFfVisibleForMe } from '@/scripts/isFfVisibleForMe.js'; import { isFfVisibleForMe } from '@/scripts/isFfVisibleForMe.js';
import { ColdDeviceStorage, defaultStore } from '@/store.js'; import { defaultStore } from '@/store.js';
import { miLocalStorage } from '@/local-storage.js'; import { miLocalStorage } from '@/local-storage.js';
import { editNickname } from '@/scripts/edit-nickname.js'; import { editNickname } from '@/scripts/edit-nickname.js';
import { vibrate } from '@/scripts/vibrate.js'; import { vibrate } from '@/scripts/vibrate.js';
@ -294,7 +294,7 @@ async function translate(): Promise<void> {
if (translation.value != null) return; if (translation.value != null) return;
translating.value = true; translating.value = true;
vibrate(ColdDeviceStorage.get('vibrateSystem') ? 5 : []); vibrate(defaultStore.state.vibrateSystem ? 5 : []);
const res = await os.api('users/translate', { const res = await os.api('users/translate', {
userId: props.user.id, userId: props.user.id,
@ -303,7 +303,7 @@ async function translate(): Promise<void> {
translating.value = false; translating.value = false;
translation.value = res; translation.value = res;
vibrate(ColdDeviceStorage.get('vibrateSystem') ? [5, 5, 10] : []); vibrate(defaultStore.state.vibrateSystem ? [5, 5, 10] : []);
} }
watch([props.user], () => { watch([props.user], () => {

View file

@ -61,7 +61,7 @@ export const soundsTypes = [
'noizenecio/kick_gaba7', 'noizenecio/kick_gaba7',
] as const; ] as const;
export async function getAudio(file: string, useCache = true) { export async function loadAudio(file: string, useCache = true) {
if (useCache && cache.has(file)) { if (useCache && cache.has(file)) {
return cache.get(file)!; return cache.get(file)!;
} }
@ -77,12 +77,6 @@ export async function getAudio(file: string, useCache = true) {
return audioBuffer; return audioBuffer;
} }
export function setVolume(audio: HTMLAudioElement, volume: number): HTMLAudioElement {
const masterVolume = defaultStore.state.sound_masterVolume;
audio.volume = masterVolume - ((1 - volume) * masterVolume);
return audio;
}
export function play(type: 'noteMy' | 'note' | 'noteEdited' | 'chat' | 'chatBg' | 'antenna' | 'channel' | 'notification') { export function play(type: 'noteMy' | 'note' | 'noteEdited' | 'chat' | 'chatBg' | 'antenna' | 'channel' | 'notification') {
const sound = defaultStore.state[`sound_${type}`]; const sound = defaultStore.state[`sound_${type}`];
if (_DEV_) console.log('play', type, sound); if (_DEV_) console.log('play', type, sound);
@ -91,16 +85,22 @@ export function play(type: 'noteMy' | 'note' | 'noteEdited' | 'chat' | 'chatBg'
} }
export async function playFile(file: string, volume: number) { export async function playFile(file: string, volume: number) {
const buffer = await loadAudio(file);
createSourceNode(buffer, volume)?.start();
}
export function createSourceNode(buffer: AudioBuffer, volume: number) : AudioBufferSourceNode | null {
const masterVolume = defaultStore.state.sound_masterVolume; const masterVolume = defaultStore.state.sound_masterVolume;
if (masterVolume === 0 || volume === 0) { if (masterVolume === 0 || volume === 0) {
return; return null;
} }
const gainNode = ctx.createGain(); const gainNode = ctx.createGain();
gainNode.gain.value = masterVolume * volume; gainNode.gain.value = masterVolume * volume;
const soundSource = ctx.createBufferSource(); const soundSource = ctx.createBufferSource();
soundSource.buffer = await getAudio(file); soundSource.buffer = buffer;
soundSource.connect(gainNode).connect(ctx.destination); soundSource.connect(gainNode).connect(ctx.destination);
soundSource.start();
return soundSource;
} }

View file

@ -3,10 +3,10 @@
* SPDX-License-Identifier: AGPL-3.0-only * SPDX-License-Identifier: AGPL-3.0-only
*/ */
import { ColdDeviceStorage } from '@/store.js'; import { defaultStore } from '@/store.js';
export function vibrate(pattern: VibratePattern) { export function vibrate(pattern: VibratePattern) {
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
if (!ColdDeviceStorage.get('vibrate') || !window.navigator.vibrate) return; if (!defaultStore.state.vibrate || !window.navigator.vibrate) return;
window.navigator.vibrate(pattern); window.navigator.vibrate(pattern);
} }

View file

@ -538,6 +538,32 @@ export const defaultStore = markRaw(new Storage('base', {
default: true, default: true,
}, },
// - Settings/Sounds & Vibrations
vibrate: {
where: 'device',
default: true,
},
vibrateNote: {
where: 'device',
default: true,
},
vibrateNotification: {
where: 'device',
default: true,
},
vibrateChat: {
where: 'device',
default: true,
},
vibrateChatBg: {
where: 'device',
default: true,
},
vibrateSystem: {
where: 'device',
default: true,
},
// - Settings/CherryPick // - Settings/CherryPick
nicknameEnabled: { nicknameEnabled: {
where: 'account', where: 'account',
@ -640,22 +666,6 @@ export class ColdDeviceStorage {
darkTheme, darkTheme,
syncDeviceDarkMode: true, syncDeviceDarkMode: true,
plugins: [] as Plugin[], plugins: [] as Plugin[],
mediaVolume: 0.5,
vibrate: true,
vibrateNote: true,
vibrateNotification: true,
vibrateChat: true,
vibrateChatBg: true,
vibrateSystem: true,
sound_masterVolume: 0.5,
sound_note: { type: 'syuilo/n-aec', volume: 0.5 },
sound_noteMy: { type: 'syuilo/n-cea-4va', volume: 0.5 },
sound_noteEdited: { type: 'syuilo/n-eca', volume: 0.5 },
sound_notification: { type: 'syuilo/n-ea', volume: 0.5 },
sound_chat: { type: 'syuilo/pope1', volume: 0.5 },
sound_chatBg: { type: 'syuilo/waon', volume: 0.5 },
sound_antenna: { type: 'syuilo/triple', volume: 0.5 },
sound_channel: { type: 'syuilo/square-pico', volume: 0.5 },
}; };
public static watchers: Watcher[] = []; public static watchers: Watcher[] = [];

View file

@ -59,7 +59,7 @@ import * as sound from '@/scripts/sound.js';
import { $i } from '@/account.js'; import { $i } from '@/account.js';
import { useStream } from '@/stream.js'; import { useStream } from '@/stream.js';
import { i18n } from '@/i18n.js'; import { i18n } from '@/i18n.js';
import { ColdDeviceStorage, defaultStore } from '@/store.js'; import { defaultStore } from '@/store.js';
import { globalEvents } from '@/events.js'; import { globalEvents } from '@/events.js';
import { vibrate } from '@/scripts/vibrate.js'; import { vibrate } from '@/scripts/vibrate.js';
@ -88,7 +88,7 @@ function onNotification(notification: Misskey.entities.Notification, isClient =
} }
sound.play('notification'); sound.play('notification');
vibrate(ColdDeviceStorage.get('vibrateNotification') ? [20, 30, 30, 30] : ''); vibrate(defaultStore.state.vibrateNotification ? [20, 30, 30, 30] : []);
} }
if ($i) { if ($i) {

View file

@ -8,7 +8,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<div v-if="['all', 'bg'].includes(<string>defaultStore.state.bannerDisplay)" :class="[$style.banner, $style.topBanner]" :style="{ backgroundImage: `url(${ instance.bannerUrl })` }"></div> <div v-if="['all', 'bg'].includes(<string>defaultStore.state.bannerDisplay)" :class="[$style.banner, $style.topBanner]" :style="{ backgroundImage: `url(${ instance.bannerUrl })` }"></div>
<div :class="$style.top"> <div :class="$style.top">
<div v-if="['all', 'topBottom', 'top'].includes(<string>defaultStore.state.bannerDisplay)" :class="[$style.banner, $style.topBanner]" :style="{ backgroundImage: `url(${ instance.bannerUrl })` }"></div> <div v-if="['all', 'topBottom', 'top'].includes(<string>defaultStore.state.bannerDisplay)" :class="[$style.banner, $style.topBanner]" :style="{ backgroundImage: `url(${ instance.bannerUrl })` }"></div>
<button v-vibrate="ColdDeviceStorage.get('vibrateSystem') ? 5 : ''" class="_button" :class="$style.instance" @click="openInstanceMenu"> <button v-vibrate="defaultStore.state.vibrateSystem ? 5 : []" class="_button" :class="$style.instance" @click="openInstanceMenu">
<img :src="instance.iconUrl || instance.faviconUrl || '/favicon.ico'" alt="" :class="$style.instanceIcon"/> <img :src="instance.iconUrl || instance.faviconUrl || '/favicon.ico'" alt="" :class="$style.instanceIcon"/>
</button> </button>
</div> </div>
@ -18,7 +18,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</MkA> </MkA>
<template v-for="item in menu"> <template v-for="item in menu">
<div v-if="item === '-'" :class="$style.divider"></div> <div v-if="item === '-'" :class="$style.divider"></div>
<component :is="navbarItemDef[item].to ? 'MkA' : 'button'" v-else-if="navbarItemDef[item] && (navbarItemDef[item].show !== false)" v-vibrate="ColdDeviceStorage.get('vibrateSystem') ? 5 : ''" class="_button" :class="[$style.item, { [$style.active]: navbarItemDef[item].active }]" :activeClass="$style.active" :to="navbarItemDef[item].to" v-on="navbarItemDef[item].action ? { click: navbarItemDef[item].action } : {}"> <component :is="navbarItemDef[item].to ? 'MkA' : 'button'" v-else-if="navbarItemDef[item] && (navbarItemDef[item].show !== false)" v-vibrate="defaultStore.state.vibrateSystem ? 5 : []" class="_button" :class="[$style.item, { [$style.active]: navbarItemDef[item].active }]" :activeClass="$style.active" :to="navbarItemDef[item].to" v-on="navbarItemDef[item].action ? { click: navbarItemDef[item].action } : {}">
<i class="ti-fw" :class="[$style.itemIcon, navbarItemDef[item].icon]"></i><span :class="$style.itemText">{{ navbarItemDef[item].title }}</span> <i class="ti-fw" :class="[$style.itemIcon, navbarItemDef[item].icon]"></i><span :class="$style.itemText">{{ navbarItemDef[item].title }}</span>
<span v-if="navbarItemDef[item].indicated" :class="$style.itemIndicator"> <span v-if="navbarItemDef[item].indicated" :class="$style.itemIndicator">
<span v-if="navbarItemDef[item].indicateValue && defaultStore.state.showUnreadNotificationsCount" class="_indicateCounter" :class="$style.itemIndicateValueIcon">{{ navbarItemDef[item].indicateValue }}</span> <span v-if="navbarItemDef[item].indicateValue && defaultStore.state.showUnreadNotificationsCount" class="_indicateCounter" :class="$style.itemIndicateValueIcon">{{ navbarItemDef[item].indicateValue }}</span>
@ -31,7 +31,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<i :class="$style.itemIcon" class="ti ti-dashboard ti-fw"></i><span :class="$style.itemText">{{ i18n.ts.controlPanel }}</span> <i :class="$style.itemIcon" class="ti ti-dashboard ti-fw"></i><span :class="$style.itemText">{{ i18n.ts.controlPanel }}</span>
<span v-if="controlPanelIndicated" :class="$style.itemIndicator"><i class="_indicatorCircle"></i></span> <span v-if="controlPanelIndicated" :class="$style.itemIndicator"><i class="_indicatorCircle"></i></span>
</MkA> </MkA>
<button v-vibrate="ColdDeviceStorage.get('vibrateSystem') ? 5 : ''" :class="$style.item" class="_button" @click="more"> <button v-vibrate="defaultStore.state.vibrateSystem ? 5 : []" :class="$style.item" class="_button" @click="more">
<i :class="$style.itemIcon" class="ti ti-dots ti-fw"></i><span :class="$style.itemText">{{ i18n.ts.more }}</span> <i :class="$style.itemIcon" class="ti ti-dots ti-fw"></i><span :class="$style.itemText">{{ i18n.ts.more }}</span>
<span v-if="otherMenuItemIndicated" :class="$style.itemIndicator"><i class="_indicatorCircle"></i></span> <span v-if="otherMenuItemIndicated" :class="$style.itemIndicator"><i class="_indicatorCircle"></i></span>
</button> </button>
@ -41,11 +41,11 @@ SPDX-License-Identifier: AGPL-3.0-only
</div> </div>
<div :class="$style.bottom"> <div :class="$style.bottom">
<div v-if="['all', 'topBottom', 'bottom'].includes(<string>defaultStore.state.bannerDisplay)" :class="[$style.banner, $style.bottomBanner]" :style="{ backgroundImage: `url(${ $i.bannerUrl })` }"></div> <div v-if="['all', 'topBottom', 'bottom'].includes(<string>defaultStore.state.bannerDisplay)" :class="[$style.banner, $style.bottomBanner]" :style="{ backgroundImage: `url(${ $i.bannerUrl })` }"></div>
<button v-vibrate="ColdDeviceStorage.get('vibrateSystem') ? 5 : ''" class="_button" :class="$style.post" data-cy-open-post-form @click="os.post"> <button v-vibrate="defaultStore.state.vibrateSystem ? 5 : []" class="_button" :class="$style.post" data-cy-open-post-form @click="os.post">
<i :class="[$style.postIcon, defaultStore.state.renameTheButtonInPostFormToNya ? 'ti-paw-filled' : 'ti-pencil']" class="ti ti-fw"></i><span style="position: relative;">{{ defaultStore.state.renameTheButtonInPostFormToNya ? i18n.ts.nya : i18n.ts.note }}</span> <i :class="[$style.postIcon, defaultStore.state.renameTheButtonInPostFormToNya ? 'ti-paw-filled' : 'ti-pencil']" class="ti ti-fw"></i><span style="position: relative;">{{ defaultStore.state.renameTheButtonInPostFormToNya ? i18n.ts.nya : i18n.ts.note }}</span>
</button> </button>
<div :class="$style.profile"> <div :class="$style.profile">
<button v-vibrate="ColdDeviceStorage.get('vibrateSystem') ? 5 : ''" class="_button" :class="$style.account" @click="openAccountMenu"> <button v-vibrate="defaultStore.state.vibrateSystem ? 5 : []" class="_button" :class="$style.account" @click="openAccountMenu">
<MkAvatar :user="$i" :class="$style.avatar"/><MkAcct :class="$style.acct" class="_nowrap" :user="$i"/> <MkAvatar :user="$i" :class="$style.avatar"/><MkAcct :class="$style.acct" class="_nowrap" :user="$i"/>
</button> </button>
</div> </div>
@ -59,7 +59,7 @@ import { openInstanceMenu } from './common';
import * as os from '@/os.js'; import * as os from '@/os.js';
import { navbarItemDef } from '@/navbar.js'; import { navbarItemDef } from '@/navbar.js';
import { $i, openAccountMenu as openAccountMenu_ } from '@/account.js'; import { $i, openAccountMenu as openAccountMenu_ } from '@/account.js';
import { ColdDeviceStorage, defaultStore } from '@/store.js'; import { defaultStore } from '@/store.js';
import { i18n } from '@/i18n.js'; import { i18n } from '@/i18n.js';
import { instance } from '@/instance.js'; import { instance } from '@/instance.js';
import { version } from '@/config.js'; import { version } from '@/config.js';

View file

@ -9,7 +9,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<div v-if="['all', 'bg'].includes(<string>defaultStore.state.bannerDisplay)" :class="[$style.banner, $style.topBanner]" :style="{ backgroundImage: `url(${ instance.bannerUrl })` }"></div> <div v-if="['all', 'bg'].includes(<string>defaultStore.state.bannerDisplay)" :class="[$style.banner, $style.topBanner]" :style="{ backgroundImage: `url(${ instance.bannerUrl })` }"></div>
<div :class="$style.top"> <div :class="$style.top">
<div v-if="['all', 'topBottom', 'top'].includes(<string>defaultStore.state.bannerDisplay)" :class="[$style.banner, $style.topBanner]" :style="{ backgroundImage: `url(${ instance.bannerUrl })` }"></div> <div v-if="['all', 'topBottom', 'top'].includes(<string>defaultStore.state.bannerDisplay)" :class="[$style.banner, $style.topBanner]" :style="{ backgroundImage: `url(${ instance.bannerUrl })` }"></div>
<button v-vibrate="ColdDeviceStorage.get('vibrateSystem') ? 5 : ''" v-tooltip.noDelay.right="instance.name ?? i18n.ts.instance" class="_button" :class="$style.instance" @click="openInstanceMenu"> <button v-vibrate="defaultStore.state.vibrateSystem ? 5 : []" v-tooltip.noDelay.right="instance.name ?? i18n.ts.instance" class="_button" :class="$style.instance" @click="openInstanceMenu">
<img :src="instance.iconUrl || instance.faviconUrl || '/favicon.ico'" alt="" :class="$style.instanceIcon"/> <img :src="instance.iconUrl || instance.faviconUrl || '/favicon.ico'" alt="" :class="$style.instanceIcon"/>
</button> </button>
</div> </div>
@ -22,7 +22,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<component <component
:is="navbarItemDef[item].to ? 'MkA' : 'button'" :is="navbarItemDef[item].to ? 'MkA' : 'button'"
v-else-if="navbarItemDef[item] && (navbarItemDef[item].show !== false)" v-else-if="navbarItemDef[item] && (navbarItemDef[item].show !== false)"
v-vibrate="ColdDeviceStorage.get('vibrateSystem') ? 5 : ''" v-vibrate="defaultStore.state.vibrateSystem ? 5 : []"
v-tooltip.noDelay.right="navbarItemDef[item].title" v-tooltip.noDelay.right="navbarItemDef[item].title"
class="_button" class="_button"
:class="[$style.item, { [$style.active]: navbarItemDef[item].active }]" :class="[$style.item, { [$style.active]: navbarItemDef[item].active }]"
@ -42,7 +42,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<i :class="$style.itemIcon" class="ti ti-dashboard ti-fw"></i><span :class="$style.itemText">{{ i18n.ts.controlPanel }}</span> <i :class="$style.itemIcon" class="ti ti-dashboard ti-fw"></i><span :class="$style.itemText">{{ i18n.ts.controlPanel }}</span>
<span v-if="controlPanelIndicated" :class="$style.itemIndicator"><i class="_indicatorCircle"></i></span> <span v-if="controlPanelIndicated" :class="$style.itemIndicator"><i class="_indicatorCircle"></i></span>
</MkA> </MkA>
<button v-vibrate="ColdDeviceStorage.get('vibrateSystem') ? 5 : ''" class="_button" :class="$style.item" @click="more"> <button v-vibrate="defaultStore.state.vibrateSystem ? 5 : []" class="_button" :class="$style.item" @click="more">
<i :class="$style.itemIcon" class="ti ti-dots ti-fw"></i><span :class="$style.itemText">{{ i18n.ts.more }}</span> <i :class="$style.itemIcon" class="ti ti-dots ti-fw"></i><span :class="$style.itemText">{{ i18n.ts.more }}</span>
<span v-if="otherMenuItemIndicated" :class="$style.itemIndicator"><i class="_indicatorCircle"></i></span> <span v-if="otherMenuItemIndicated" :class="$style.itemIndicator"><i class="_indicatorCircle"></i></span>
</button> </button>
@ -52,10 +52,10 @@ SPDX-License-Identifier: AGPL-3.0-only
</div> </div>
<div :class="$style.bottom"> <div :class="$style.bottom">
<div v-if="['all', 'topBottom', 'bottom'].includes(<string>defaultStore.state.bannerDisplay)" :class="[$style.banner, $style.bottomBanner]" :style="{ backgroundImage: `url(${ $i.bannerUrl })` }"></div> <div v-if="['all', 'topBottom', 'bottom'].includes(<string>defaultStore.state.bannerDisplay)" :class="[$style.banner, $style.bottomBanner]" :style="{ backgroundImage: `url(${ $i.bannerUrl })` }"></div>
<button v-vibrate="ColdDeviceStorage.get('vibrateSystem') ? 5 : ''" v-tooltip.noDelay.right="defaultStore.state.renameTheButtonInPostFormToNya ? i18n.ts.nya : i18n.ts.note" class="_button" :class="[$style.post]" data-cy-open-post-form @click="os.post"> <button v-vibrate="defaultStore.state.vibrateSystem ? 5 : []" v-tooltip.noDelay.right="defaultStore.state.renameTheButtonInPostFormToNya ? i18n.ts.nya : i18n.ts.note" class="_button" :class="[$style.post]" data-cy-open-post-form @click="os.post">
<i class="ti ti-fw" :class="[$style.postIcon, defaultStore.state.renameTheButtonInPostFormToNya ? 'ti-paw-filled' : 'ti-pencil']"></i><span :class="$style.postText">{{ defaultStore.state.renameTheButtonInPostFormToNya ? i18n.ts.nya : i18n.ts.note }}</span> <i class="ti ti-fw" :class="[$style.postIcon, defaultStore.state.renameTheButtonInPostFormToNya ? 'ti-paw-filled' : 'ti-pencil']"></i><span :class="$style.postText">{{ defaultStore.state.renameTheButtonInPostFormToNya ? i18n.ts.nya : i18n.ts.note }}</span>
</button> </button>
<button v-vibrate="ColdDeviceStorage.get('vibrateSystem') ? 5 : ''" v-tooltip.noDelay.right="`${i18n.ts.account}: @${$i.username}`" class="_button" :class="[$style.account]" @click="openAccountMenu"> <button v-vibrate="defaultStore.state.vibrateSystem ? 5 : []" v-tooltip.noDelay.right="`${i18n.ts.account}: @${$i.username}`" class="_button" :class="[$style.account]" @click="openAccountMenu">
<MkAvatar :user="$i" :class="$style.avatar"/><MkAcct class="_nowrap" :class="$style.acct" :user="$i"/> <MkAvatar :user="$i" :class="$style.avatar"/><MkAcct class="_nowrap" :class="$style.acct" :user="$i"/>
</button> </button>
</div> </div>
@ -69,7 +69,7 @@ import { openInstanceMenu } from './common.js';
import * as os from '@/os.js'; import * as os from '@/os.js';
import { navbarItemDef } from '@/navbar.js'; import { navbarItemDef } from '@/navbar.js';
import { $i, openAccountMenu as openAccountMenu_ } from '@/account.js'; import { $i, openAccountMenu as openAccountMenu_ } from '@/account.js';
import { ColdDeviceStorage, defaultStore } from '@/store.js'; import { defaultStore } from '@/store.js';
import { i18n } from '@/i18n.js'; import { i18n } from '@/i18n.js';
import { instance } from '@/instance.js'; import { instance } from '@/instance.js';
import { version } from '@/config.js'; import { version } from '@/config.js';

View file

@ -7,7 +7,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<div class="azykntjl"> <div class="azykntjl">
<div class="body"> <div class="body">
<div class="left"> <div class="left">
<button v-click-anime v-vibrate="ColdDeviceStorage.get('vibrateSystem') ? 5 : ''" class="item _button instance" @click="openInstanceMenu"> <button v-click-anime v-vibrate="defaultStore.state.vibrateSystem ? 5 : []" class="item _button instance" @click="openInstanceMenu">
<img :src="instance.iconUrl ?? instance.faviconUrl ?? '/favicon.ico'" class="_ghost"/> <img :src="instance.iconUrl ?? instance.faviconUrl ?? '/favicon.ico'" class="_ghost"/>
</button> </button>
<MkA v-click-anime v-tooltip="i18n.ts.timeline" class="item index" activeClass="active" to="/" exact> <MkA v-click-anime v-tooltip="i18n.ts.timeline" class="item index" activeClass="active" to="/" exact>
@ -15,7 +15,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</MkA> </MkA>
<template v-for="item in menu"> <template v-for="item in menu">
<div v-if="item === '-'" class="divider"></div> <div v-if="item === '-'" class="divider"></div>
<component :is="navbarItemDef[item].to ? 'MkA' : 'button'" v-else-if="navbarItemDef[item] && (navbarItemDef[item].show !== false)" v-click-anime v-vibrate="ColdDeviceStorage.get('vibrateSystem') ? 5 : ''" v-tooltip="navbarItemDef[item].title" class="item _button" :class="item" activeClass="active" :to="navbarItemDef[item].to" v-on="navbarItemDef[item].action ? { click: navbarItemDef[item].action } : {}"> <component :is="navbarItemDef[item].to ? 'MkA' : 'button'" v-else-if="navbarItemDef[item] && (navbarItemDef[item].show !== false)" v-click-anime v-vibrate="defaultStore.state.vibrateSystem ? 5 : []" v-tooltip="navbarItemDef[item].title" class="item _button" :class="item" activeClass="active" :to="navbarItemDef[item].to" v-on="navbarItemDef[item].action ? { click: navbarItemDef[item].action } : {}">
<i class="ti-fw" :class="navbarItemDef[item].icon"></i> <i class="ti-fw" :class="navbarItemDef[item].icon"></i>
<span v-if="navbarItemDef[item].indicated" class="indicator"><i class="_indicatorCircle"></i></span> <span v-if="navbarItemDef[item].indicated" class="indicator"><i class="_indicatorCircle"></i></span>
</component> </component>
@ -25,7 +25,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<i class="ti ti-dashboard ti-fw"></i> <i class="ti ti-dashboard ti-fw"></i>
<span v-if="controlPanelIndicated" class="indicator"><i class="_indicatorCircle"></i></span> <span v-if="controlPanelIndicated" class="indicator"><i class="_indicatorCircle"></i></span>
</MkA> </MkA>
<button v-click-anime v-vibrate="ColdDeviceStorage.get('vibrateSystem') ? 5 : ''" class="item _button" @click="more"> <button v-click-anime v-vibrate="defaultStore.state.vibrateSystem ? 5 : []" class="item _button" @click="more">
<i class="ti ti-dots ti-fw"></i> <i class="ti ti-dots ti-fw"></i>
<span v-if="otherNavItemIndicated" class="indicator"><i class="_indicatorCircle"></i></span> <span v-if="otherNavItemIndicated" class="indicator"><i class="_indicatorCircle"></i></span>
</button> </button>
@ -34,7 +34,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<MkA v-click-anime v-tooltip="i18n.ts.settings" class="item" activeClass="active" to="/settings" :behavior="settingsWindowed ? 'window' : null"> <MkA v-click-anime v-tooltip="i18n.ts.settings" class="item" activeClass="active" to="/settings" :behavior="settingsWindowed ? 'window' : null">
<i class="ti ti-settings ti-fw"></i> <i class="ti ti-settings ti-fw"></i>
</MkA> </MkA>
<button v-click-anime v-vibrate="ColdDeviceStorage.get('vibrateSystem') ? 5 : ''" class="item _button account" @click="openAccountMenu"> <button v-click-anime v-vibrate="defaultStore.state.vibrateSystem ? 5 : []" class="item _button account" @click="openAccountMenu">
<MkAvatar :user="$i" class="avatar"/><MkAcct class="acct" :user="$i"/> <MkAvatar :user="$i" class="avatar"/><MkAcct class="acct" :user="$i"/>
</button> </button>
<div class="post" @click="os.post()"> <div class="post" @click="os.post()">
@ -54,7 +54,7 @@ import * as os from '@/os.js';
import { navbarItemDef } from '@/navbar'; import { navbarItemDef } from '@/navbar';
import { openAccountMenu as openAccountMenu_, $i } from '@/account.js'; import { openAccountMenu as openAccountMenu_, $i } from '@/account.js';
import MkButton from '@/components/MkButton.vue'; import MkButton from '@/components/MkButton.vue';
import { ColdDeviceStorage, defaultStore } from '@/store.js'; import { defaultStore } from '@/store.js';
import { instance } from '@/instance.js'; import { instance } from '@/instance.js';
import { i18n } from '@/i18n.js'; import { i18n } from '@/i18n.js';
import { version } from '@/config.js'; import { version } from '@/config.js';

View file

@ -5,7 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<template> <template>
<div class="npcljfve" :class="{ iconOnly }"> <div class="npcljfve" :class="{ iconOnly }">
<button v-click-anime v-vibrate="ColdDeviceStorage.get('vibrateSystem') ? 5 : ''" class="item _button account" @click="openAccountMenu"> <button v-click-anime v-vibrate="defaultStore.state.vibrateSystem ? 5 : []" class="item _button account" @click="openAccountMenu">
<MkAvatar :user="$i" class="avatar"/><MkAcct class="text" :user="$i"/> <MkAvatar :user="$i" class="avatar"/><MkAcct class="text" :user="$i"/>
</button> </button>
<div class="post" data-cy-open-post-form @click="os.post"> <div class="post" data-cy-open-post-form @click="os.post">
@ -19,7 +19,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</MkA> </MkA>
<template v-for="item in menu"> <template v-for="item in menu">
<div v-if="item === '-'" class="divider"></div> <div v-if="item === '-'" class="divider"></div>
<component :is="navbarItemDef[item].to ? 'MkA' : 'button'" v-else-if="navbarItemDef[item] && (navbarItemDef[item].show !== false)" v-click-anime v-vibrate="ColdDeviceStorage.get('vibrateSystem') ? 5 : ''" class="item _button" :class="item" activeClass="active" :to="navbarItemDef[item].to" v-on="navbarItemDef[item].action ? { click: navbarItemDef[item].action } : {}"> <component :is="navbarItemDef[item].to ? 'MkA' : 'button'" v-else-if="navbarItemDef[item] && (navbarItemDef[item].show !== false)" v-click-anime v-vibrate="defaultStore.state.vibrateSystem ? 5 : []" class="item _button" :class="item" activeClass="active" :to="navbarItemDef[item].to" v-on="navbarItemDef[item].action ? { click: navbarItemDef[item].action } : {}">
<i class="ti-fw" :class="navbarItemDef[item].icon"></i><span class="text">{{ navbarItemDef[item].title }}</span> <i class="ti-fw" :class="navbarItemDef[item].icon"></i><span class="text">{{ navbarItemDef[item].title }}</span>
<span v-if="navbarItemDef[item].indicated" class="indicator"> <span v-if="navbarItemDef[item].indicated" class="indicator">
<span v-if="navbarItemDef[item].indicateValue && defaultStore.state.showUnreadNotificationsCount" class="_indicateCounter itemIndicateValueIcon">{{ navbarItemDef[item].indicateValue }}</span> <span v-if="navbarItemDef[item].indicateValue && defaultStore.state.showUnreadNotificationsCount" class="_indicateCounter itemIndicateValueIcon">{{ navbarItemDef[item].indicateValue }}</span>
@ -32,7 +32,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<i class="ti ti-dashboard ti-fw"></i><span class="text">{{ i18n.ts.controlPanel }}</span> <i class="ti ti-dashboard ti-fw"></i><span class="text">{{ i18n.ts.controlPanel }}</span>
<span v-if="controlPanelIndicated" class="indicator"><i class="_indicatorCircle"></i></span> <span v-if="controlPanelIndicated" class="indicator"><i class="_indicatorCircle"></i></span>
</MkA> </MkA>
<button v-click-anime v-vibrate="ColdDeviceStorage.get('vibrateSystem') ? 5 : ''" class="item _button" @click="more"> <button v-click-anime v-vibrate="defaultStore.state.vibrateSystem ? 5 : []" class="item _button" @click="more">
<i class="ti ti-dots ti-fw"></i><span class="text">{{ i18n.ts.more }}</span> <i class="ti ti-dots ti-fw"></i><span class="text">{{ i18n.ts.more }}</span>
<span v-if="otherNavItemIndicated" class="indicator"><i class="_indicatorCircle"></i></span> <span v-if="otherNavItemIndicated" class="indicator"><i class="_indicatorCircle"></i></span>
</button> </button>
@ -41,7 +41,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</MkA> </MkA>
<div class="divider"></div> <div class="divider"></div>
<div class="about"> <div class="about">
<button v-click-anime v-vibrate="ColdDeviceStorage.get('vibrateSystem') ? 5 : ''" class="item _button" @click="openInstanceMenu"> <button v-click-anime v-vibrate="defaultStore.state.vibrateSystem ? 5 : []" class="item _button" @click="openInstanceMenu">
<img :src="instance.iconUrl ?? instance.faviconUrl ?? '/favicon.ico'" class="_ghost"/> <img :src="instance.iconUrl ?? instance.faviconUrl ?? '/favicon.ico'" class="_ghost"/>
</button> </button>
</div> </div>
@ -60,7 +60,7 @@ import MkButton from '@/components/MkButton.vue';
// import { StickySidebar } from '@/scripts/sticky-sidebar.js'; // import { StickySidebar } from '@/scripts/sticky-sidebar.js';
// import { mainRouter } from '@/router.js'; // import { mainRouter } from '@/router.js';
//import CherryPickLogo from '@assets/client/cherrypick.svg'; //import CherryPickLogo from '@assets/client/cherrypick.svg';
import { ColdDeviceStorage, defaultStore } from '@/store.js'; import { defaultStore } from '@/store.js';
import { instance } from '@/instance.js'; import { instance } from '@/instance.js';
import { i18n } from '@/i18n.js'; import { i18n } from '@/i18n.js';
import { version } from '@/config.js'; import { version } from '@/config.js';

View file

@ -36,30 +36,30 @@ SPDX-License-Identifier: AGPL-3.0-only
</div> </div>
<div :class="$style.sideMenu"> <div :class="$style.sideMenu">
<div :class="$style.sideMenuTop"> <div :class="$style.sideMenuTop">
<button v-vibrate="ColdDeviceStorage.get('vibrateSystem') ? 5 : ''" v-tooltip.noDelay.left="`${i18n.ts._deck.profile}: ${deckStore.state.profile}`" :class="$style.sideMenuButton" class="_button" @click="changeProfile"><i class="ti ti-caret-down"></i></button> <button v-vibrate="defaultStore.state.vibrateSystem ? 5 : []" v-tooltip.noDelay.left="`${i18n.ts._deck.profile}: ${deckStore.state.profile}`" :class="$style.sideMenuButton" class="_button" @click="changeProfile"><i class="ti ti-caret-down"></i></button>
<button v-vibrate="ColdDeviceStorage.get('vibrateSystem') ? 5 : ''" v-tooltip.noDelay.left="i18n.ts._deck.deleteProfile" :class="$style.sideMenuButton" class="_button" @click="deleteProfile"><i class="ti ti-trash"></i></button> <button v-vibrate="defaultStore.state.vibrateSystem ? 5 : []" v-tooltip.noDelay.left="i18n.ts._deck.deleteProfile" :class="$style.sideMenuButton" class="_button" @click="deleteProfile"><i class="ti ti-trash"></i></button>
</div> </div>
<div :class="$style.sideMenuMiddle"> <div :class="$style.sideMenuMiddle">
<button v-vibrate="ColdDeviceStorage.get('vibrateSystem') ? 5 : ''" v-tooltip.noDelay.left="i18n.ts._deck.addColumn" :class="$style.sideMenuButton" class="_button" @click="addColumn"><i class="ti ti-plus"></i></button> <button v-vibrate="defaultStore.state.vibrateSystem ? 5 : []" v-tooltip.noDelay.left="i18n.ts._deck.addColumn" :class="$style.sideMenuButton" class="_button" @click="addColumn"><i class="ti ti-plus"></i></button>
</div> </div>
<div :class="$style.sideMenuBottom"> <div :class="$style.sideMenuBottom">
<button v-vibrate="ColdDeviceStorage.get('vibrateSystem') ? 5 : ''" v-tooltip.noDelay.left="i18n.ts.settings" :class="$style.sideMenuButton" class="_button" @click="showSettings"><i class="ti ti-settings"></i></button> <button v-vibrate="defaultStore.state.vibrateSystem ? 5 : []" v-tooltip.noDelay.left="i18n.ts.settings" :class="$style.sideMenuButton" class="_button" @click="showSettings"><i class="ti ti-settings"></i></button>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div v-if="isMobile" :class="$style.nav"> <div v-if="isMobile" :class="$style.nav">
<button v-vibrate="ColdDeviceStorage.get('vibrateSystem') ? 5 : ''" :class="$style.navButton" class="_button" @click="drawerMenuShowing = true"><i :class="$style.navButtonIcon" class="ti ti-menu-2"></i><span v-if="menuIndicated" :class="$style.navButtonIndicator"><i class="_indicatorCircle"></i></span></button> <button v-vibrate="defaultStore.state.vibrateSystem ? 5 : []" :class="$style.navButton" class="_button" @click="drawerMenuShowing = true"><i :class="$style.navButtonIcon" class="ti ti-menu-2"></i><span v-if="menuIndicated" :class="$style.navButtonIndicator"><i class="_indicatorCircle"></i></span></button>
<button v-vibrate="ColdDeviceStorage.get('vibrateSystem') ? 5 : ''" :class="$style.navButton" class="_button" @click="mainRouter.push('/')"><i :class="$style.navButtonIcon" class="ti ti-home"></i></button> <button v-vibrate="defaultStore.state.vibrateSystem ? 5 : []" :class="$style.navButton" class="_button" @click="mainRouter.push('/')"><i :class="$style.navButtonIcon" class="ti ti-home"></i></button>
<button v-vibrate="ColdDeviceStorage.get('vibrateSystem') ? 5 : ''" :class="$style.navButton" class="_button" @click="mainRouter.push('/my/notifications')"> <button v-vibrate="defaultStore.state.vibrateSystem ? 5 : []" :class="$style.navButton" class="_button" @click="mainRouter.push('/my/notifications')">
<i :class="$style.navButtonIcon" class="ti ti-bell"></i> <i :class="$style.navButtonIcon" class="ti ti-bell"></i>
<span v-if="$i?.hasUnreadNotification" :class="$style.navButtonIndicator"> <span v-if="$i?.hasUnreadNotification" :class="$style.navButtonIndicator">
<span v-if="defaultStore.state.showUnreadNotificationsCount" class="_indicateCounter" :class="$style.itemIndicateValueIcon">{{ $i.unreadNotificationsCount > 99 ? '99+' : $i.unreadNotificationsCount }}</span> <span v-if="defaultStore.state.showUnreadNotificationsCount" class="_indicateCounter" :class="$style.itemIndicateValueIcon">{{ $i.unreadNotificationsCount > 99 ? '99+' : $i.unreadNotificationsCount }}</span>
<i v-else class="_indicatorCircle"></i> <i v-else class="_indicatorCircle"></i>
</span> </span>
</button> </button>
<button v-vibrate="ColdDeviceStorage.get('vibrateSystem') ? 5 : ''" :class="$style.postButton" class="_button" @click="os.post()"><i :class="$style.navButtonIcon" class="ti ti-pencil"></i></button> <button v-vibrate="defaultStore.state.vibrateSystem ? 5 : []" :class="$style.postButton" class="_button" @click="os.post()"><i :class="$style.navButtonIcon" class="ti ti-pencil"></i></button>
</div> </div>
<Transition <Transition
@ -108,7 +108,7 @@ import { i18n } from '@/i18n.js';
import { mainRouter } from '@/router.js'; import { mainRouter } from '@/router.js';
import { unisonReload } from '@/scripts/unison-reload.js'; import { unisonReload } from '@/scripts/unison-reload.js';
import { deviceKind } from '@/scripts/device-kind.js'; import { deviceKind } from '@/scripts/device-kind.js';
import { ColdDeviceStorage, defaultStore } from '@/store.js'; import { defaultStore } from '@/store.js';
import XMainColumn from '@/ui/deck/main-column.vue'; import XMainColumn from '@/ui/deck/main-column.vue';
import XTlColumn from '@/ui/deck/tl-column.vue'; import XTlColumn from '@/ui/deck/tl-column.vue';
import XAntennaColumn from '@/ui/deck/antenna-column.vue'; import XAntennaColumn from '@/ui/deck/antenna-column.vue';

View file

@ -26,26 +26,26 @@ SPDX-License-Identifier: AGPL-3.0-only
<XWidgets/> <XWidgets/>
</div> </div>
<button v-if="isMobile && enableNavButton.includes(<string>mainRouter.currentRoute.value.name)" v-vibrate="ColdDeviceStorage.get('vibrateSystem') ? 5 : ''" :class="[$style.floatNavButton, { [$style.reduceBlurEffect]: !defaultStore.state.useBlurEffect, [$style.reduceAnimation]: !defaultStore.state.animation, [$style.showEl]: (showEl && ['hideHeaderFloatBtn', 'hideFloatBtnOnly', 'hideFloatBtnNavBar', 'hide'].includes(<string>defaultStore.state.displayHeaderNavBarWhenScroll)) }]" class="_button" @click="drawerMenuShowing = true"><CPAvatar :class="$style.floatNavButtonAvatar" :user="$i"/></button> <button v-if="isMobile && enableNavButton.includes(<string>mainRouter.currentRoute.value.name)" v-vibrate="defaultStore.state.vibrateSystem ? 5 : []" :class="[$style.floatNavButton, { [$style.reduceBlurEffect]: !defaultStore.state.useBlurEffect, [$style.reduceAnimation]: !defaultStore.state.animation, [$style.showEl]: (showEl && ['hideHeaderFloatBtn', 'hideFloatBtnOnly', 'hideFloatBtnNavBar', 'hide'].includes(<string>defaultStore.state.displayHeaderNavBarWhenScroll)) }]" class="_button" @click="drawerMenuShowing = true"><CPAvatar :class="$style.floatNavButtonAvatar" :user="$i"/></button>
<button v-if="isMobile && enablePostButton.includes(<string>mainRouter.currentRoute.value.name)" v-vibrate="ColdDeviceStorage.get('vibrateSystem') ? 5 : ''" :class="[$style.floatPostButton, { [$style.reduceBlurEffect]: !defaultStore.state.useBlurEffect, [$style.reduceAnimation]: !defaultStore.state.animation, [$style.showEl]: (showEl && ['hideHeaderFloatBtn', 'hideFloatBtnOnly', 'hideFloatBtnNavBar', 'hide'].includes(<string>defaultStore.state.displayHeaderNavBarWhenScroll)) }]" :style="{ background: PostBg }" class="_button" @click="openMessage"><span :class="[$style.floatPostButtonBg, { [$style.reduceBlurEffect]: !defaultStore.state.useBlurEffect }]"></span><i v-if="mainRouter.currentRoute.value.name === 'messaging' && !(['messaging-room', 'messaging-room-group'].includes(<string>mainRouter.currentRoute.value.name))" class="ti ti-plus"></i><i v-else-if="enablePostButton.includes(<string>mainRouter.currentRoute.value.name)" class="ti ti-pencil"></i></button> <button v-if="isMobile && enablePostButton.includes(<string>mainRouter.currentRoute.value.name)" v-vibrate="defaultStore.state.vibrateSystem ? 5 : []" :class="[$style.floatPostButton, { [$style.reduceBlurEffect]: !defaultStore.state.useBlurEffect, [$style.reduceAnimation]: !defaultStore.state.animation, [$style.showEl]: (showEl && ['hideHeaderFloatBtn', 'hideFloatBtnOnly', 'hideFloatBtnNavBar', 'hide'].includes(<string>defaultStore.state.displayHeaderNavBarWhenScroll)) }]" :style="{ background: PostBg }" class="_button" @click="openMessage"><span :class="[$style.floatPostButtonBg, { [$style.reduceBlurEffect]: !defaultStore.state.useBlurEffect }]"></span><i v-if="mainRouter.currentRoute.value.name === 'messaging' && !(['messaging-room', 'messaging-room-group'].includes(<string>mainRouter.currentRoute.value.name))" class="ti ti-plus"></i><i v-else-if="enablePostButton.includes(<string>mainRouter.currentRoute.value.name)" class="ti ti-pencil"></i></button>
<button v-if="!isDesktop && !isMobile" v-vibrate="ColdDeviceStorage.get('vibrateSystem') ? 5 : ''" :class="[$style.widgetButton, { [$style.reduceAnimation]: !defaultStore.state.animation, [$style.showEl]: (showEl && ['hideHeaderFloatBtn', 'hideFloatBtnOnly', 'hideFloatBtnNavBar', 'hide'].includes(<string>defaultStore.state.displayHeaderNavBarWhenScroll)) }]" class="_button" @click="widgetsShowing = true"><i class="ti ti-apps"></i></button> <button v-if="!isDesktop && !isMobile" v-vibrate="defaultStore.state.vibrateSystem ? 5 : []" :class="[$style.widgetButton, { [$style.reduceAnimation]: !defaultStore.state.animation, [$style.showEl]: (showEl && ['hideHeaderFloatBtn', 'hideFloatBtnOnly', 'hideFloatBtnNavBar', 'hide'].includes(<string>defaultStore.state.displayHeaderNavBarWhenScroll)) }]" class="_button" @click="widgetsShowing = true"><i class="ti ti-apps"></i></button>
<div v-if="isMobile" ref="navFooter" :class="[$style.nav, { [$style.reduceBlurEffect]: !defaultStore.state.useBlurEffect, [$style.reduceAnimation]: !defaultStore.state.animation, [$style.showEl]: (showEl && ['hideFloatBtnNavBar', 'hide'].includes(<string>defaultStore.state.displayHeaderNavBarWhenScroll)) }]" :style="{ background: bg }"> <div v-if="isMobile" ref="navFooter" :class="[$style.nav, { [$style.reduceBlurEffect]: !defaultStore.state.useBlurEffect, [$style.reduceAnimation]: !defaultStore.state.animation, [$style.showEl]: (showEl && ['hideFloatBtnNavBar', 'hide'].includes(<string>defaultStore.state.displayHeaderNavBarWhenScroll)) }]" :style="{ background: bg }">
<!-- v-vibrate="ColdDeviceStorage.get('vibrateSystem') ? 5 : ''" <button :class="$style.navButton" class="_button" @click="drawerMenuShowing = true"><i :class="$style.navButtonIcon" class="ti ti-menu-2"></i><span v-if="menuIndicated" :class="$style.navButtonIndicator"><i class="_indicatorCircle"></i></span></button> --> <!-- v-vibrate="defaultStore.state.vibrateSystem ? 5 : []" <button :class="$style.navButton" class="_button" @click="drawerMenuShowing = true"><i :class="$style.navButtonIcon" class="ti ti-menu-2"></i><span v-if="menuIndicated" :class="$style.navButtonIndicator"><i class="_indicatorCircle"></i></span></button> -->
<button v-vibrate="ColdDeviceStorage.get('vibrateSystem') ? 5 : ''" :class="[$style.navButton, { [$style.active]: mainRouter.currentRoute.value.name === 'index' }]" class="_button" @click="mainRouter.currentRoute.value.name === 'index' ? top() : mainRouter.push('/')" @touchstart="openAccountMenu" @touchend="closeAccountMenu"><i :class="$style.navButtonIcon" class="ti ti-home"></i><span v-if="queue > 0" :class="$style.navButtonIndicatorHome"><i class="_indicatorCircle"></i></span></button> <button v-vibrate="defaultStore.state.vibrateSystem ? 5 : []" :class="[$style.navButton, { [$style.active]: mainRouter.currentRoute.value.name === 'index' }]" class="_button" @click="mainRouter.currentRoute.value.name === 'index' ? top() : mainRouter.push('/')" @touchstart="openAccountMenu" @touchend="closeAccountMenu"><i :class="$style.navButtonIcon" class="ti ti-home"></i><span v-if="queue > 0" :class="$style.navButtonIndicatorHome"><i class="_indicatorCircle"></i></span></button>
<button v-vibrate="ColdDeviceStorage.get('vibrateSystem') ? 5 : ''" :class="[$style.navButton, { [$style.active]: mainRouter.currentRoute.value.name === 'explore' }]" class="_button" @click="mainRouter.currentRoute.value.name === 'explore' ? top() : mainRouter.push('/explore')"><i :class="$style.navButtonIcon" class="ti ti-hash"></i></button> <button v-vibrate="defaultStore.state.vibrateSystem ? 5 : []" :class="[$style.navButton, { [$style.active]: mainRouter.currentRoute.value.name === 'explore' }]" class="_button" @click="mainRouter.currentRoute.value.name === 'explore' ? top() : mainRouter.push('/explore')"><i :class="$style.navButtonIcon" class="ti ti-hash"></i></button>
<button v-vibrate="ColdDeviceStorage.get('vibrateSystem') ? 5 : ''" :class="[$style.navButton, { [$style.active]: mainRouter.currentRoute.value.name === 'my-notifications' }]" class="_button" @click="mainRouter.currentRoute.value.name === 'my-notifications' ? top() : mainRouter.push('/my/notifications')"> <button v-vibrate="defaultStore.state.vibrateSystem ? 5 : []" :class="[$style.navButton, { [$style.active]: mainRouter.currentRoute.value.name === 'my-notifications' }]" class="_button" @click="mainRouter.currentRoute.value.name === 'my-notifications' ? top() : mainRouter.push('/my/notifications')">
<i :class="$style.navButtonIcon" class="ti ti-bell"></i> <i :class="$style.navButtonIcon" class="ti ti-bell"></i>
<span v-if="$i?.hasUnreadNotification" :class="$style.navButtonIndicator"> <span v-if="$i?.hasUnreadNotification" :class="$style.navButtonIndicator">
<span v-if="defaultStore.state.showUnreadNotificationsCount" class="_indicateCounter" :class="$style.itemIndicateValueIcon">{{ $i.unreadNotificationsCount > 99 ? '99+' : $i.unreadNotificationsCount }}</span> <span v-if="defaultStore.state.showUnreadNotificationsCount" class="_indicateCounter" :class="$style.itemIndicateValueIcon">{{ $i.unreadNotificationsCount > 99 ? '99+' : $i.unreadNotificationsCount }}</span>
<i v-else class="_indicatorCircle"></i> <i v-else class="_indicatorCircle"></i>
</span> </span>
</button> </button>
<button v-vibrate="ColdDeviceStorage.get('vibrateSystem') ? 5 : ''" :class="[$style.navButton, { [$style.active]: ['messaging', 'messaging-room', 'messaging-room-group'].includes(<string>mainRouter.currentRoute.value.name) }]" class="_button" @click="mainRouter.currentRoute.value.name === 'messaging' ? top() : mainRouter.push('/my/messaging')"><i :class="$style.navButtonIcon" class="ti ti-messages"></i><span v-if="$i?.hasUnreadMessagingMessage" :class="$style.navButtonIndicator"><i class="_indicatorCircle"></i></span></button> <button v-vibrate="defaultStore.state.vibrateSystem ? 5 : []" :class="[$style.navButton, { [$style.active]: ['messaging', 'messaging-room', 'messaging-room-group'].includes(<string>mainRouter.currentRoute.value.name) }]" class="_button" @click="mainRouter.currentRoute.value.name === 'messaging' ? top() : mainRouter.push('/my/messaging')"><i :class="$style.navButtonIcon" class="ti ti-messages"></i><span v-if="$i?.hasUnreadMessagingMessage" :class="$style.navButtonIndicator"><i class="_indicatorCircle"></i></span></button>
<button v-vibrate="ColdDeviceStorage.get('vibrateSystem') ? 5 : ''" :class="$style.navButton" class="_button" @click="widgetsShowing = true"><i :class="$style.navButtonIcon" class="ti ti-apps"></i></button> <button v-vibrate="defaultStore.state.vibrateSystem ? 5 : []" :class="$style.navButton" class="_button" @click="widgetsShowing = true"><i :class="$style.navButtonIcon" class="ti ti-apps"></i></button>
<!-- <button v-vibrate="ColdDeviceStorage.get('vibrateSystem') ? 5 : ''" :class="$style.postButton" class="_button" @click="os.post()"><i :class="$style.navButtonIcon" class="ti ti-pencil"></i></button> --> <!-- <button v-vibrate="defaultStore.state.vibrateSystem ? 5 : []" :class="$style.postButton" class="_button" @click="os.post()"><i :class="$style.navButtonIcon" class="ti ti-pencil"></i></button> -->
</div> </div>
<Transition <Transition
@ -113,7 +113,7 @@ import XCommon from '@/ui/_common_/common.vue';
import { instanceName } from '@/config.js'; import { instanceName } from '@/config.js';
import XDrawerMenu from '@/ui/friendly/navbar-for-mobile.vue'; import XDrawerMenu from '@/ui/friendly/navbar-for-mobile.vue';
import * as os from '@/os.js'; import * as os from '@/os.js';
import { ColdDeviceStorage, defaultStore } from '@/store.js'; import { defaultStore } from '@/store.js';
import { i18n } from '@/i18n.js'; import { i18n } from '@/i18n.js';
import { $i, openAccountMenu as openAccountMenu_ } from '@/account.js'; import { $i, openAccountMenu as openAccountMenu_ } from '@/account.js';
import { mainRouter } from '@/router.js'; import { mainRouter } from '@/router.js';

View file

@ -8,7 +8,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<div v-if="['all', 'bg'].includes(<string>defaultStore.state.bannerDisplay)" :class="[$style.banner, $style.topBanner]" :style="{ backgroundImage: `url(${ instance.bannerUrl })` }"></div> <div v-if="['all', 'bg'].includes(<string>defaultStore.state.bannerDisplay)" :class="[$style.banner, $style.topBanner]" :style="{ backgroundImage: `url(${ instance.bannerUrl })` }"></div>
<div :class="$style.top"> <div :class="$style.top">
<div v-if="['all', 'topBottom', 'top'].includes(<string>defaultStore.state.bannerDisplay)" :class="[$style.banner, $style.topBanner]" :style="{ backgroundImage: `url(${ instance.bannerUrl })` }"></div> <div v-if="['all', 'topBottom', 'top'].includes(<string>defaultStore.state.bannerDisplay)" :class="[$style.banner, $style.topBanner]" :style="{ backgroundImage: `url(${ instance.bannerUrl })` }"></div>
<button v-vibrate="ColdDeviceStorage.get('vibrateSystem') ? 5 : ''" class="_button" :class="$style.instance" @click="openInstanceMenu"> <button v-vibrate="defaultStore.state.vibrateSystem ? 5 : []" class="_button" :class="$style.instance" @click="openInstanceMenu">
<img :src="instance.iconUrl || instance.faviconUrl || '/favicon.ico'" alt="" :class="$style.instanceIcon"/> <img :src="instance.iconUrl || instance.faviconUrl || '/favicon.ico'" alt="" :class="$style.instanceIcon"/>
</button> </button>
</div> </div>
@ -18,7 +18,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</MkA> </MkA>
<template v-for="item in menu"> <template v-for="item in menu">
<div v-if="item === '-'" :class="$style.divider"></div> <div v-if="item === '-'" :class="$style.divider"></div>
<component :is="navbarItemDef[item].to ? 'MkA' : 'button'" v-else-if="navbarItemDef[item] && (navbarItemDef[item].show !== false)" v-vibrate="ColdDeviceStorage.get('vibrateSystem') ? 5 : ''" class="_button" :class="[$style.item, { [$style.active]: navbarItemDef[item].active }]" :activeClass="$style.active" :to="navbarItemDef[item].to" v-on="navbarItemDef[item].action ? { click: navbarItemDef[item].action } : {}"> <component :is="navbarItemDef[item].to ? 'MkA' : 'button'" v-else-if="navbarItemDef[item] && (navbarItemDef[item].show !== false)" v-vibrate="defaultStore.state.vibrateSystem ? 5 : []" class="_button" :class="[$style.item, { [$style.active]: navbarItemDef[item].active }]" :activeClass="$style.active" :to="navbarItemDef[item].to" v-on="navbarItemDef[item].action ? { click: navbarItemDef[item].action } : {}">
<i class="ti-fw" :class="[$style.itemIcon, navbarItemDef[item].icon]"></i><span :class="$style.itemText">{{ navbarItemDef[item].title }}</span> <i class="ti-fw" :class="[$style.itemIcon, navbarItemDef[item].icon]"></i><span :class="$style.itemText">{{ navbarItemDef[item].title }}</span>
<span v-if="navbarItemDef[item].indicated" :class="$style.itemIndicator"> <span v-if="navbarItemDef[item].indicated" :class="$style.itemIndicator">
<span v-if="navbarItemDef[item].indicateValue && defaultStore.state.showUnreadNotificationsCount" class="_indicateCounter" :class="$style.itemIndicateValueIcon">{{ navbarItemDef[item].indicateValue }}</span> <span v-if="navbarItemDef[item].indicateValue && defaultStore.state.showUnreadNotificationsCount" class="_indicateCounter" :class="$style.itemIndicateValueIcon">{{ navbarItemDef[item].indicateValue }}</span>
@ -31,7 +31,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<i :class="$style.itemIcon" class="ti ti-dashboard ti-fw"></i><span :class="$style.itemText">{{ i18n.ts.controlPanel }}</span> <i :class="$style.itemIcon" class="ti ti-dashboard ti-fw"></i><span :class="$style.itemText">{{ i18n.ts.controlPanel }}</span>
<span v-if="controlPanelIndicated" :class="$style.itemIndicator"><i class="_indicatorCircle"></i></span> <span v-if="controlPanelIndicated" :class="$style.itemIndicator"><i class="_indicatorCircle"></i></span>
</MkA> </MkA>
<button v-vibrate="ColdDeviceStorage.get('vibrateSystem') ? 5 : ''" :class="$style.item" class="_button" @click="more"> <button v-vibrate="defaultStore.state.vibrateSystem ? 5 : []" :class="$style.item" class="_button" @click="more">
<i :class="$style.itemIcon" class="ti ti-dots ti-fw"></i><span :class="$style.itemText">{{ i18n.ts.more }}</span> <i :class="$style.itemIcon" class="ti ti-dots ti-fw"></i><span :class="$style.itemText">{{ i18n.ts.more }}</span>
<span v-if="otherMenuItemIndicated" :class="$style.itemIndicator"><i class="_indicatorCircle"></i></span> <span v-if="otherMenuItemIndicated" :class="$style.itemIndicator"><i class="_indicatorCircle"></i></span>
</button> </button>
@ -41,14 +41,14 @@ SPDX-License-Identifier: AGPL-3.0-only
</div> </div>
<div :class="$style.bottom"> <div :class="$style.bottom">
<div v-if="['all', 'topBottom', 'bottom'].includes(<string>defaultStore.state.bannerDisplay)" :class="[$style.banner, $style.bottomBanner]" :style="{ backgroundImage: `url(${ $i.bannerUrl })` }"></div> <div v-if="['all', 'topBottom', 'bottom'].includes(<string>defaultStore.state.bannerDisplay)" :class="[$style.banner, $style.bottomBanner]" :style="{ backgroundImage: `url(${ $i.bannerUrl })` }"></div>
<button v-vibrate="ColdDeviceStorage.get('vibrateSystem') ? 5 : ''" class="_button" :class="$style.post" data-cy-open-post-form @click="os.post"> <button v-vibrate="defaultStore.state.vibrateSystem ? 5 : []" class="_button" :class="$style.post" data-cy-open-post-form @click="os.post">
<i :class="[$style.postIcon, defaultStore.state.renameTheButtonInPostFormToNya ? 'ti-paw-filled' : 'ti-pencil']" class="ti ti-fw"></i><span style="position: relative;">{{ defaultStore.state.renameTheButtonInPostFormToNya ? i18n.ts.nya : i18n.ts.note }}</span> <i :class="[$style.postIcon, defaultStore.state.renameTheButtonInPostFormToNya ? 'ti-paw-filled' : 'ti-pencil']" class="ti ti-fw"></i><span style="position: relative;">{{ defaultStore.state.renameTheButtonInPostFormToNya ? i18n.ts.nya : i18n.ts.note }}</span>
</button> </button>
<div :class="$style.profile"> <div :class="$style.profile">
<button v-vibrate="ColdDeviceStorage.get('vibrateSystem') ? 5 : ''" class="_button" :class="$style.account" @click="openProfile"> <button v-vibrate="defaultStore.state.vibrateSystem ? 5 : []" class="_button" :class="$style.account" @click="openProfile">
<MkAvatar :user="$i" :class="$style.avatar"/><MkUserName :class="$style.acct" class="_nowrap" :user="$i"/> <MkAvatar :user="$i" :class="$style.avatar"/><MkUserName :class="$style.acct" class="_nowrap" :user="$i"/>
</button> </button>
<button v-vibrate="ColdDeviceStorage.get('vibrateSystem') ? 5 : ''" class="_button" :class="$style.drawer" @click="openAccountMenu"><i class="ti ti-chevron-up"/></button> <button v-vibrate="defaultStore.state.vibrateSystem ? 5 : []" class="_button" :class="$style.drawer" @click="openAccountMenu"><i class="ti ti-chevron-up"/></button>
</div> </div>
</div> </div>
</div> </div>
@ -60,7 +60,7 @@ import { openInstanceMenu } from '@/ui/_common_/common.js';
import * as os from '@/os.js'; import * as os from '@/os.js';
import { navbarItemDef } from '@/navbar.js'; import { navbarItemDef } from '@/navbar.js';
import { $i, openAccountMenu as openAccountMenu_ } from '@/account.js'; import { $i, openAccountMenu as openAccountMenu_ } from '@/account.js';
import { ColdDeviceStorage, defaultStore } from '@/store.js'; import { defaultStore } from '@/store.js';
import { i18n } from '@/i18n.js'; import { i18n } from '@/i18n.js';
import { instance } from '@/instance.js'; import { instance } from '@/instance.js';
import { mainRouter } from '@/router.js'; import { mainRouter } from '@/router.js';

View file

@ -9,7 +9,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<div v-if="['all', 'bg'].includes(<string>defaultStore.state.bannerDisplay)" :class="[$style.banner, $style.topBanner]" :style="{ backgroundImage: `url(${ instance.bannerUrl })` }"></div> <div v-if="['all', 'bg'].includes(<string>defaultStore.state.bannerDisplay)" :class="[$style.banner, $style.topBanner]" :style="{ backgroundImage: `url(${ instance.bannerUrl })` }"></div>
<div :class="$style.top"> <div :class="$style.top">
<div v-if="['all', 'topBottom', 'top'].includes(<string>defaultStore.state.bannerDisplay)" :class="[$style.banner, $style.topBanner]" :style="{ backgroundImage: `url(${ instance.bannerUrl })` }"></div> <div v-if="['all', 'topBottom', 'top'].includes(<string>defaultStore.state.bannerDisplay)" :class="[$style.banner, $style.topBanner]" :style="{ backgroundImage: `url(${ instance.bannerUrl })` }"></div>
<button v-vibrate="ColdDeviceStorage.get('vibrateSystem') ? 5 : ''" v-tooltip.noDelay.right="instance.name ?? i18n.ts.instance" class="_button" :class="$style.instance" @click="openInstanceMenu"> <button v-vibrate="defaultStore.state.vibrateSystem ? 5 : []" v-tooltip.noDelay.right="instance.name ?? i18n.ts.instance" class="_button" :class="$style.instance" @click="openInstanceMenu">
<img :src="instance.iconUrl || instance.faviconUrl || '/favicon.ico'" alt="" :class="$style.instanceIcon"/> <img :src="instance.iconUrl || instance.faviconUrl || '/favicon.ico'" alt="" :class="$style.instanceIcon"/>
</button> </button>
</div> </div>
@ -22,7 +22,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<component <component
:is="navbarItemDef[item].to ? 'MkA' : 'button'" :is="navbarItemDef[item].to ? 'MkA' : 'button'"
v-else-if="navbarItemDef[item] && (navbarItemDef[item].show !== false)" v-else-if="navbarItemDef[item] && (navbarItemDef[item].show !== false)"
v-vibrate="ColdDeviceStorage.get('vibrateSystem') ? 5 : ''" v-vibrate="defaultStore.state.vibrateSystem ? 5 : []"
v-tooltip.noDelay.right="navbarItemDef[item].title" v-tooltip.noDelay.right="navbarItemDef[item].title"
class="_button" class="_button"
:class="[$style.item, { [$style.active]: navbarItemDef[item].active }]" :class="[$style.item, { [$style.active]: navbarItemDef[item].active }]"
@ -42,7 +42,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<i :class="$style.itemIcon" class="ti ti-dashboard ti-fw"></i><span :class="$style.itemText">{{ i18n.ts.controlPanel }}</span> <i :class="$style.itemIcon" class="ti ti-dashboard ti-fw"></i><span :class="$style.itemText">{{ i18n.ts.controlPanel }}</span>
<span v-if="controlPanelIndicated" :class="$style.itemIndicator"><i class="_indicatorCircle"></i></span> <span v-if="controlPanelIndicated" :class="$style.itemIndicator"><i class="_indicatorCircle"></i></span>
</MkA> </MkA>
<button v-vibrate="ColdDeviceStorage.get('vibrateSystem') ? 5 : ''" class="_button" :class="$style.item" @click="more"> <button v-vibrate="defaultStore.state.vibrateSystem ? 5 : []" class="_button" :class="$style.item" @click="more">
<i :class="$style.itemIcon" class="ti ti-dots ti-fw"></i><span :class="$style.itemText">{{ i18n.ts.more }}</span> <i :class="$style.itemIcon" class="ti ti-dots ti-fw"></i><span :class="$style.itemText">{{ i18n.ts.more }}</span>
<span v-if="otherMenuItemIndicated" :class="$style.itemIndicator"><i class="_indicatorCircle"></i></span> <span v-if="otherMenuItemIndicated" :class="$style.itemIndicator"><i class="_indicatorCircle"></i></span>
</button> </button>
@ -52,17 +52,17 @@ SPDX-License-Identifier: AGPL-3.0-only
</div> </div>
<div :class="$style.bottom"> <div :class="$style.bottom">
<div v-if="['all', 'topBottom', 'bottom'].includes(<string>defaultStore.state.bannerDisplay)" :class="[$style.banner, $style.bottomBanner]" :style="{ backgroundImage: `url(${ $i.bannerUrl })` }"></div> <div v-if="['all', 'topBottom', 'bottom'].includes(<string>defaultStore.state.bannerDisplay)" :class="[$style.banner, $style.bottomBanner]" :style="{ backgroundImage: `url(${ $i.bannerUrl })` }"></div>
<button v-vibrate="ColdDeviceStorage.get('vibrateSystem') ? 5 : ''" v-tooltip.noDelay.right="defaultStore.state.renameTheButtonInPostFormToNya ? i18n.ts.nya : i18n.ts.note" class="_button" :class="[$style.post]" data-cy-open-post-form @click="os.post"> <button v-vibrate="defaultStore.state.vibrateSystem ? 5 : []" v-tooltip.noDelay.right="defaultStore.state.renameTheButtonInPostFormToNya ? i18n.ts.nya : i18n.ts.note" class="_button" :class="[$style.post]" data-cy-open-post-form @click="os.post">
<i class="ti ti-fw" :class="[$style.postIcon, defaultStore.state.renameTheButtonInPostFormToNya ? 'ti-paw-filled' : 'ti-pencil']"></i><span :class="$style.postText">{{ defaultStore.state.renameTheButtonInPostFormToNya ? i18n.ts.nya : i18n.ts.note }}</span> <i class="ti ti-fw" :class="[$style.postIcon, defaultStore.state.renameTheButtonInPostFormToNya ? 'ti-paw-filled' : 'ti-pencil']"></i><span :class="$style.postText">{{ defaultStore.state.renameTheButtonInPostFormToNya ? i18n.ts.nya : i18n.ts.note }}</span>
</button> </button>
<div :class="$style.profile"> <div :class="$style.profile">
<button v-if="iconOnly" v-vibrate="ColdDeviceStorage.get('vibrateSystem') ? 5 : ''" v-tooltip.noDelay.right="`${i18n.ts.account}: @${$i.username}`" class="_button" :class="[$style.account]" @click="openAccountMenu"> <button v-if="iconOnly" v-vibrate="defaultStore.state.vibrateSystem ? 5 : []" v-tooltip.noDelay.right="`${i18n.ts.account}: @${$i.username}`" class="_button" :class="[$style.account]" @click="openAccountMenu">
<MkAvatar :user="$i" :class="$style.avatar"/> <MkAvatar :user="$i" :class="$style.avatar"/>
</button> </button>
<button v-else v-vibrate="ColdDeviceStorage.get('vibrateSystem') ? 5 : ''" v-tooltip.noDelay.right="`${i18n.ts.account}: @${$i.username}`" class="_button" :class="[$style.account]" @click="openProfile"> <button v-else v-vibrate="defaultStore.state.vibrateSystem ? 5 : []" v-tooltip.noDelay.right="`${i18n.ts.account}: @${$i.username}`" class="_button" :class="[$style.account]" @click="openProfile">
<MkAvatar :user="$i" :class="$style.avatar"/><MkUserName class="_nowrap" :class="$style.acct" :user="$i"/> <MkAvatar :user="$i" :class="$style.avatar"/><MkUserName class="_nowrap" :class="$style.acct" :user="$i"/>
</button> </button>
<button v-if="!iconOnly" v-vibrate="ColdDeviceStorage.get('vibrateSystem') ? 5 : ''" class="_button" :class="[$style.drawer]" @click="openAccountMenu"><i class="ti ti-chevron-up"/></button> <button v-if="!iconOnly" v-vibrate="defaultStore.state.vibrateSystem ? 5 : []" class="_button" :class="[$style.drawer]" @click="openAccountMenu"><i class="ti ti-chevron-up"/></button>
</div> </div>
</div> </div>
</div> </div>
@ -75,7 +75,7 @@ import { openInstanceMenu } from '@/ui/_common_/common.js';
import * as os from '@/os.js'; import * as os from '@/os.js';
import { navbarItemDef } from '@/navbar.js'; import { navbarItemDef } from '@/navbar.js';
import { $i, openAccountMenu as openAccountMenu_ } from '@/account.js'; import { $i, openAccountMenu as openAccountMenu_ } from '@/account.js';
import { ColdDeviceStorage, defaultStore } from '@/store.js'; import { defaultStore } from '@/store.js';
import { i18n } from '@/i18n.js'; import { i18n } from '@/i18n.js';
import { instance } from '@/instance.js'; import { instance } from '@/instance.js';
import { mainRouter } from '@/router.js'; import { mainRouter } from '@/router.js';

View file

@ -22,20 +22,20 @@ SPDX-License-Identifier: AGPL-3.0-only
<XWidgets/> <XWidgets/>
</div> </div>
<button v-if="!isDesktop && !isMobile" v-vibrate="ColdDeviceStorage.get('vibrateSystem') ? 5 : ''" :class="[$style.widgetButton, { [$style.reduceAnimation]: !defaultStore.state.animation, [$style.showEl]: (showEl && ['hideHeaderFloatBtn', 'hideFloatBtnOnly', 'hideFloatBtnNavBar', 'hide'].includes(<string>defaultStore.state.displayHeaderNavBarWhenScroll)) }]" class="_button" @click="widgetsShowing = true"><i class="ti ti-apps"></i></button> <button v-if="!isDesktop && !isMobile" v-vibrate="defaultStore.state.vibrateSystem ? 5 : []" :class="[$style.widgetButton, { [$style.reduceAnimation]: !defaultStore.state.animation, [$style.showEl]: (showEl && ['hideHeaderFloatBtn', 'hideFloatBtnOnly', 'hideFloatBtnNavBar', 'hide'].includes(<string>defaultStore.state.displayHeaderNavBarWhenScroll)) }]" class="_button" @click="widgetsShowing = true"><i class="ti ti-apps"></i></button>
<div v-if="isMobile" ref="navFooter" :class="[$style.nav, { [$style.reduceAnimation]: !defaultStore.state.animation, [$style.showEl]: (showEl && ['hideFloatBtnNavBar', 'hide'].includes(<string>defaultStore.state.displayHeaderNavBarWhenScroll)) }]"> <div v-if="isMobile" ref="navFooter" :class="[$style.nav, { [$style.reduceAnimation]: !defaultStore.state.animation, [$style.showEl]: (showEl && ['hideFloatBtnNavBar', 'hide'].includes(<string>defaultStore.state.displayHeaderNavBarWhenScroll)) }]">
<button v-vibrate="ColdDeviceStorage.get('vibrateSystem') ? 5 : ''" :class="$style.navButton" class="_button" @click="drawerMenuShowing = true"><i :class="$style.navButtonIcon" class="ti ti-menu-2"></i><span v-if="menuIndicated" :class="$style.navButtonIndicator"><i class="_indicatorCircle"></i></span></button> <button v-vibrate="defaultStore.state.vibrateSystem ? 5 : []" :class="$style.navButton" class="_button" @click="drawerMenuShowing = true"><i :class="$style.navButtonIcon" class="ti ti-menu-2"></i><span v-if="menuIndicated" :class="$style.navButtonIndicator"><i class="_indicatorCircle"></i></span></button>
<button v-vibrate="ColdDeviceStorage.get('vibrateSystem') ? 5 : ''" :class="$style.navButton" class="_button" @click="mainRouter.currentRoute.value.name === 'index' ? top() : mainRouter.push('/')"><i :class="$style.navButtonIcon" class="ti ti-home"></i></button> <button v-vibrate="defaultStore.state.vibrateSystem ? 5 : []" :class="$style.navButton" class="_button" @click="mainRouter.currentRoute.value.name === 'index' ? top() : mainRouter.push('/')"><i :class="$style.navButtonIcon" class="ti ti-home"></i></button>
<button v-vibrate="ColdDeviceStorage.get('vibrateSystem') ? 5 : ''" :class="$style.navButton" class="_button" @click="mainRouter.push('/my/notifications')"> <button v-vibrate="defaultStore.state.vibrateSystem ? 5 : []" :class="$style.navButton" class="_button" @click="mainRouter.push('/my/notifications')">
<i :class="$style.navButtonIcon" class="ti ti-bell"></i> <i :class="$style.navButtonIcon" class="ti ti-bell"></i>
<span v-if="$i?.hasUnreadNotification" :class="$style.navButtonIndicator"> <span v-if="$i?.hasUnreadNotification" :class="$style.navButtonIndicator">
<span v-if="defaultStore.state.showUnreadNotificationsCount" class="_indicateCounter" :class="$style.itemIndicateValueIcon">{{ $i.unreadNotificationsCount > 99 ? '99+' : $i.unreadNotificationsCount }}</span> <span v-if="defaultStore.state.showUnreadNotificationsCount" class="_indicateCounter" :class="$style.itemIndicateValueIcon">{{ $i.unreadNotificationsCount > 99 ? '99+' : $i.unreadNotificationsCount }}</span>
<i v-else class="_indicatorCircle"></i> <i v-else class="_indicatorCircle"></i>
</span> </span>
</button> </button>
<button v-vibrate="ColdDeviceStorage.get('vibrateSystem') ? 5 : ''" :class="$style.navButton" class="_button" @click="widgetsShowing = true"><i :class="$style.navButtonIcon" class="ti ti-apps"></i></button> <button v-vibrate="defaultStore.state.vibrateSystem ? 5 : []" :class="$style.navButton" class="_button" @click="widgetsShowing = true"><i :class="$style.navButtonIcon" class="ti ti-apps"></i></button>
<button v-vibrate="ColdDeviceStorage.get('vibrateSystem') ? 5 : ''" :class="$style.postButton" class="_button" @click="os.post()"><i :class="$style.navButtonIcon" class="ti ti-pencil"></i></button> <button v-vibrate="defaultStore.state.vibrateSystem ? 5 : []" :class="$style.postButton" class="_button" @click="os.post()"><i :class="$style.navButtonIcon" class="ti ti-pencil"></i></button>
</div> </div>
<Transition <Transition
@ -102,7 +102,7 @@ import type MkStickyContainer from '@/components/global/MkStickyContainer.vue';
import { instanceName } from '@/config.js'; import { instanceName } from '@/config.js';
import XDrawerMenu from '@/ui/_common_/navbar-for-mobile.vue'; import XDrawerMenu from '@/ui/_common_/navbar-for-mobile.vue';
import * as os from '@/os.js'; import * as os from '@/os.js';
import { ColdDeviceStorage, defaultStore } from '@/store.js'; import { defaultStore } from '@/store.js';
import { navbarItemDef } from '@/navbar.js'; import { navbarItemDef } from '@/navbar.js';
import { i18n } from '@/i18n.js'; import { i18n } from '@/i18n.js';
import { $i } from '@/account.js'; import { $i } from '@/account.js';

View file

@ -7,8 +7,8 @@ SPDX-License-Identifier: AGPL-3.0-only
<div> <div>
<XWidgets :edit="editMode" :widgets="widgets" @addWidget="addWidget" @removeWidget="removeWidget" @updateWidget="updateWidget" @updateWidgets="updateWidgets" @exit="editMode = false"/> <XWidgets :edit="editMode" :widgets="widgets" @addWidget="addWidget" @removeWidget="removeWidget" @updateWidget="updateWidget" @updateWidgets="updateWidgets" @exit="editMode = false"/>
<button v-if="editMode" v-vibrate="ColdDeviceStorage.get('vibrateSystem') ? 5 : ''" class="_textButton" style="font-size: 0.9em;" @click="editMode = false"><i class="ti ti-check"></i> {{ i18n.ts.editWidgetsExit }}</button> <button v-if="editMode" v-vibrate="defaultStore.state.vibrateSystem ? 5 : []" class="_textButton" style="font-size: 0.9em;" @click="editMode = false"><i class="ti ti-check"></i> {{ i18n.ts.editWidgetsExit }}</button>
<button v-else v-vibrate="ColdDeviceStorage.get('vibrateSystem') ? 5 : ''" class="_textButton" data-cy-widget-edit :class="$style.edit" style="font-size: 0.9em;" @click="editMode = true"><i class="ti ti-pencil"></i> {{ i18n.ts.editWidgets }}</button> <button v-else v-vibrate="defaultStore.state.vibrateSystem ? 5 : []" class="_textButton" data-cy-widget-edit :class="$style.edit" style="font-size: 0.9em;" @click="editMode = true"><i class="ti ti-pencil"></i> {{ i18n.ts.editWidgets }}</button>
</div> </div>
</template> </template>
@ -19,7 +19,7 @@ let editMode = $ref(false);
import { } from 'vue'; import { } from 'vue';
import XWidgets from '@/components/MkWidgets.vue'; import XWidgets from '@/components/MkWidgets.vue';
import { i18n } from '@/i18n.js'; import { i18n } from '@/i18n.js';
import { ColdDeviceStorage, defaultStore } from '@/store.js'; import { defaultStore } from '@/store.js';
const props = withDefaults(defineProps<{ const props = withDefaults(defineProps<{
// null = // null =

View file

@ -23,7 +23,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<MkA to="/channels" class="link" activeClass="active"><i class="ti ti-device-tv icon"></i> {{ i18n.ts.channel }}</MkA> <MkA to="/channels" class="link" activeClass="active"><i class="ti ti-device-tv icon"></i> {{ i18n.ts.channel }}</MkA>
</div> </div>
<div v-else-if="narrow === true" class="narrow"> <div v-else-if="narrow === true" class="narrow">
<button v-vibrate="ColdDeviceStorage.get('vibrateSystem') ? 5 : ''" class="menu _button" @click="showMenu = true"> <button v-vibrate="defaultStore.state.vibrateSystem ? 5 : []" class="menu _button" @click="showMenu = true">
<i class="ti ti-menu-2 icon"></i> <i class="ti ti-menu-2 icon"></i>
</button> </button>
</div> </div>
@ -59,8 +59,8 @@ SPDX-License-Identifier: AGPL-3.0-only
<MkA to="/play" class="link" activeClass="active"><i class="ti ti-player-play icon"></i>Play</MkA> <MkA to="/play" class="link" activeClass="active"><i class="ti ti-player-play icon"></i>Play</MkA>
<MkA to="/gallery" class="link" activeClass="active"><i class="ti ti-icons icon"></i>{{ i18n.ts.gallery }}</MkA> <MkA to="/gallery" class="link" activeClass="active"><i class="ti ti-icons icon"></i>{{ i18n.ts.gallery }}</MkA>
<div class="action"> <div class="action">
<button v-vibrate="ColdDeviceStorage.get('vibrateSystem') ? 5 : ''" class="_buttonPrimary" @click="signup()">{{ i18n.ts.signup }}</button> <button v-vibrate="defaultStore.state.vibrateSystem ? 5 : []" class="_buttonPrimary" @click="signup()">{{ i18n.ts.signup }}</button>
<button v-vibrate="ColdDeviceStorage.get('vibrateSystem') ? 5 : ''" class="_button" @click="signin()">{{ i18n.ts.login }}</button> <button v-vibrate="defaultStore.state.vibrateSystem ? 5 : []" class="_button" @click="signin()">{{ i18n.ts.login }}</button>
</div> </div>
</div> </div>
</Transition> </Transition>

View file

@ -17,7 +17,7 @@ SPDX-License-Identifier: AGPL-3.0-only
See https://github.com/misskey-dev/misskey/issues/10905 See https://github.com/misskey-dev/misskey/issues/10905
--> -->
<div v-if="showBottom" :class="$style.bottom"> <div v-if="showBottom" :class="$style.bottom">
<button v-vibrate="ColdDeviceStorage.get('vibrateSystem') ? 5 : ''" v-tooltip="i18n.ts.goToMisskey" :class="['_button', '_shadow', $style.button]" @click="goToMisskey"><i class="ti ti-home"></i></button> <button v-vibrate="defaultStore.state.vibrateSystem ? 5 : []" v-tooltip="i18n.ts.goToMisskey" :class="['_button', '_shadow', $style.button]" @click="goToMisskey"><i class="ti ti-home"></i></button>
</div> </div>
</template> </template>
@ -28,7 +28,7 @@ import { mainRouter } from '@/router.js';
import { PageMetadata, provideMetadataReceiver } from '@/scripts/page-metadata.js'; import { PageMetadata, provideMetadataReceiver } from '@/scripts/page-metadata.js';
import { instanceName, ui } from '@/config.js'; import { instanceName, ui } from '@/config.js';
import { i18n } from '@/i18n.js'; import { i18n } from '@/i18n.js';
import { ColdDeviceStorage } from '@/store.js'; import { defaultStore } from '@/store.js';
let pageMetadata = $ref<null | ComputedRef<PageMetadata>>(); let pageMetadata = $ref<null | ComputedRef<PageMetadata>>();

View file

@ -99,7 +99,10 @@ const current = reactive({
}, },
}); });
const prev = reactive({} as typeof current); const prev = reactive({} as typeof current);
const jammedSound = sound.setVolume(sound.getAudio('syuilo/queue-jammed'), 1); let jammedAudioBuffer: AudioBuffer | null = $ref(null);
let jammedSoundNodePlaying: boolean = $ref(false);
sound.loadAudio('syuilo/queue-jammed').then(buf => jammedAudioBuffer = buf);
for (const domain of ['inbox', 'deliver']) { for (const domain of ['inbox', 'deliver']) {
prev[domain] = deepClone(current[domain]); prev[domain] = deepClone(current[domain]);
@ -113,8 +116,13 @@ const onStats = (stats) => {
current[domain].waiting = stats[domain].waiting; current[domain].waiting = stats[domain].waiting;
current[domain].delayed = stats[domain].delayed; current[domain].delayed = stats[domain].delayed;
if (current[domain].waiting > 0 && widgetProps.sound && jammedSound.paused) { if (current[domain].waiting > 0 && widgetProps.sound && jammedAudioBuffer && !jammedSoundNodePlaying) {
jammedSound.play(); const soundNode = sound.createSourceNode(jammedAudioBuffer, 1);
if (soundNode) {
jammedSoundNodePlaying = true;
soundNode.onended = () => jammedSoundNodePlaying = false;
soundNode.start();
}
} }
} }
}; };

View file

@ -150,7 +150,7 @@ describe('MkUrlPreview', () => {
}); });
assert.exists(iframe, 'iframe should exist'); assert.exists(iframe, 'iframe should exist');
assert.strictEqual(iframe?.getAttribute('allow'), 'fullscreen;web-share'); assert.strictEqual(iframe?.getAttribute('allow'), 'fullscreen;web-share');
assert.strictEqual(iframe?.getAttribute('sandbox'), 'allow-popups allow-scripts allow-same-origin'); assert.strictEqual(iframe?.getAttribute('sandbox'), 'allow-popups allow-popups-to-escape-sandbox allow-scripts allow-same-origin');
}); });
test('Loading a post in iframe', async () => { test('Loading a post in iframe', async () => {
@ -159,6 +159,6 @@ describe('MkUrlPreview', () => {
}); });
assert.exists(iframe, 'iframe should exist'); assert.exists(iframe, 'iframe should exist');
assert.strictEqual(iframe?.getAttribute('allow'), 'fullscreen;web-share'); assert.strictEqual(iframe?.getAttribute('allow'), 'fullscreen;web-share');
assert.strictEqual(iframe?.getAttribute('sandbox'), 'allow-popups allow-scripts allow-same-origin'); assert.strictEqual(iframe?.getAttribute('sandbox'), 'allow-popups allow-popups-to-escape-sandbox allow-scripts allow-same-origin');
}); });
}); });

View file

@ -18,7 +18,7 @@
"@typescript/lib-webworker": "npm:@types/serviceworker@0.0.67", "@typescript/lib-webworker": "npm:@types/serviceworker@0.0.67",
"eslint": "8.53.0", "eslint": "8.53.0",
"eslint-plugin-import": "2.29.0", "eslint-plugin-import": "2.29.0",
"typescript": "5.2.2" "typescript": "5.3.2"
}, },
"type": "module" "type": "module"
} }

View file

@ -28,8 +28,8 @@ importers:
specifier: 5.24.0 specifier: 5.24.0
version: 5.24.0 version: 5.24.0
typescript: typescript:
specifier: 5.2.2 specifier: 5.3.2
version: 5.2.2 version: 5.3.2
optionalDependencies: optionalDependencies:
'@tensorflow/tfjs-core': '@tensorflow/tfjs-core':
specifier: 4.4.0 specifier: 4.4.0
@ -37,10 +37,10 @@ importers:
devDependencies: devDependencies:
'@typescript-eslint/eslint-plugin': '@typescript-eslint/eslint-plugin':
specifier: 6.11.0 specifier: 6.11.0
version: 6.11.0(@typescript-eslint/parser@6.11.0)(eslint@8.53.0)(typescript@5.2.2) version: 6.11.0(@typescript-eslint/parser@6.11.0)(eslint@8.53.0)(typescript@5.3.2)
'@typescript-eslint/parser': '@typescript-eslint/parser':
specifier: 6.11.0 specifier: 6.11.0
version: 6.11.0(eslint@8.53.0)(typescript@5.2.2) version: 6.11.0(eslint@8.53.0)(typescript@5.3.2)
cross-env: cross-env:
specifier: 7.0.3 specifier: 7.0.3
version: 7.0.3 version: 7.0.3
@ -393,8 +393,8 @@ importers:
specifier: 0.3.17 specifier: 0.3.17
version: 0.3.17(ioredis@5.3.2)(pg@8.11.3) version: 0.3.17(ioredis@5.3.2)(pg@8.11.3)
typescript: typescript:
specifier: 5.2.2 specifier: 5.3.2
version: 5.2.2 version: 5.3.2
ulid: ulid:
specifier: 2.3.0 specifier: 2.3.0
version: 2.3.0 version: 2.3.0
@ -627,10 +627,10 @@ importers:
version: 8.5.9 version: 8.5.9
'@typescript-eslint/eslint-plugin': '@typescript-eslint/eslint-plugin':
specifier: 6.11.0 specifier: 6.11.0
version: 6.11.0(@typescript-eslint/parser@6.11.0)(eslint@8.53.0)(typescript@5.2.2) version: 6.11.0(@typescript-eslint/parser@6.11.0)(eslint@8.53.0)(typescript@5.3.2)
'@typescript-eslint/parser': '@typescript-eslint/parser':
specifier: 6.11.0 specifier: 6.11.0
version: 6.11.0(eslint@8.53.0)(typescript@5.2.2) version: 6.11.0(eslint@8.53.0)(typescript@5.3.2)
aws-sdk-client-mock: aws-sdk-client-mock:
specifier: 3.0.0 specifier: 3.0.0
version: 3.0.0 version: 3.0.0
@ -685,10 +685,10 @@ importers:
version: 20.9.1 version: 20.9.1
'@typescript-eslint/eslint-plugin': '@typescript-eslint/eslint-plugin':
specifier: 6.11.0 specifier: 6.11.0
version: 6.11.0(@typescript-eslint/parser@6.11.0)(eslint@8.53.0)(typescript@5.2.2) version: 6.11.0(@typescript-eslint/parser@6.11.0)(eslint@8.53.0)(typescript@5.3.2)
'@typescript-eslint/parser': '@typescript-eslint/parser':
specifier: 6.11.0 specifier: 6.11.0
version: 6.11.0(eslint@8.53.0)(typescript@5.2.2) version: 6.11.0(eslint@8.53.0)(typescript@5.3.2)
eslint: eslint:
specifier: 8.53.0 specifier: 8.53.0
version: 8.53.0 version: 8.53.0
@ -708,8 +708,8 @@ importers:
specifier: 0.29.0 specifier: 0.29.0
version: 0.29.0 version: 0.29.0
typescript: typescript:
specifier: 5.2.2 specifier: 5.3.2
version: 5.2.2 version: 5.3.2
packages/frontend: packages/frontend:
dependencies: dependencies:
@ -888,8 +888,8 @@ importers:
specifier: 14.0.0 specifier: 14.0.0
version: 14.0.0 version: 14.0.0
typescript: typescript:
specifier: 5.2.2 specifier: 5.3.2
version: 5.2.2 version: 5.3.2
uuid: uuid:
specifier: 9.0.1 specifier: 9.0.1
version: 9.0.1 version: 9.0.1
@ -904,7 +904,7 @@ importers:
version: 4.5.0(@types/node@20.9.1)(sass@1.69.5)(terser@5.24.0) version: 4.5.0(@types/node@20.9.1)(sass@1.69.5)(terser@5.24.0)
vue: vue:
specifier: 3.3.8 specifier: 3.3.8
version: 3.3.8(typescript@5.2.2) version: 3.3.8(typescript@5.3.2)
vue-prism-editor: vue-prism-editor:
specifier: 2.0.0-alpha.2 specifier: 2.0.0-alpha.2
version: 2.0.0-alpha.2(vue@3.3.8) version: 2.0.0-alpha.2(vue@3.3.8)
@ -947,10 +947,10 @@ importers:
version: 7.5.3 version: 7.5.3
'@storybook/react': '@storybook/react':
specifier: 7.5.3 specifier: 7.5.3
version: 7.5.3(react-dom@18.2.0)(react@18.2.0)(typescript@5.2.2) version: 7.5.3(react-dom@18.2.0)(react@18.2.0)(typescript@5.3.2)
'@storybook/react-vite': '@storybook/react-vite':
specifier: 7.5.3 specifier: 7.5.3
version: 7.5.3(react-dom@18.2.0)(react@18.2.0)(rollup@4.4.1)(typescript@5.2.2)(vite@4.5.0) version: 7.5.3(react-dom@18.2.0)(react@18.2.0)(rollup@4.4.1)(typescript@5.3.2)(vite@4.5.0)
'@storybook/testing-library': '@storybook/testing-library':
specifier: 0.2.2 specifier: 0.2.2
version: 0.2.2 version: 0.2.2
@ -962,10 +962,10 @@ importers:
version: 7.5.3 version: 7.5.3
'@storybook/vue3': '@storybook/vue3':
specifier: 7.5.3 specifier: 7.5.3
version: 7.5.3(@vue/compiler-core@3.3.7)(vue@3.3.8) version: 7.5.3(@vue/compiler-core@3.3.8)(vue@3.3.8)
'@storybook/vue3-vite': '@storybook/vue3-vite':
specifier: 7.5.3 specifier: 7.5.3
version: 7.5.3(@vue/compiler-core@3.3.7)(react-dom@18.2.0)(react@18.2.0)(typescript@5.2.2)(vite@4.5.0)(vue@3.3.8) version: 7.5.3(@vue/compiler-core@3.3.8)(react-dom@18.2.0)(react@18.2.0)(typescript@5.3.2)(vite@4.5.0)(vue@3.3.8)
'@testing-library/vue': '@testing-library/vue':
specifier: 8.0.0 specifier: 8.0.0
version: 8.0.0(@vue/compiler-sfc@3.3.8)(vue@3.3.8) version: 8.0.0(@vue/compiler-sfc@3.3.8)(vue@3.3.8)
@ -1013,10 +1013,10 @@ importers:
version: 8.5.9 version: 8.5.9
'@typescript-eslint/eslint-plugin': '@typescript-eslint/eslint-plugin':
specifier: 6.11.0 specifier: 6.11.0
version: 6.11.0(@typescript-eslint/parser@6.11.0)(eslint@8.53.0)(typescript@5.2.2) version: 6.11.0(@typescript-eslint/parser@6.11.0)(eslint@8.53.0)(typescript@5.3.2)
'@typescript-eslint/parser': '@typescript-eslint/parser':
specifier: 6.11.0 specifier: 6.11.0
version: 6.11.0(eslint@8.53.0)(typescript@5.2.2) version: 6.11.0(eslint@8.53.0)(typescript@5.3.2)
'@vitest/coverage-v8': '@vitest/coverage-v8':
specifier: 0.34.6 specifier: 0.34.6
version: 0.34.6(vitest@0.34.6) version: 0.34.6(vitest@0.34.6)
@ -1040,7 +1040,7 @@ importers:
version: 2.29.0(@typescript-eslint/parser@6.11.0)(eslint@8.53.0) version: 2.29.0(@typescript-eslint/parser@6.11.0)(eslint@8.53.0)
eslint-plugin-storybook: eslint-plugin-storybook:
specifier: ^0.6.13 specifier: ^0.6.13
version: 0.6.13(eslint@8.53.0)(typescript@5.2.2) version: 0.6.13(eslint@8.53.0)(typescript@5.3.2)
eslint-plugin-vue: eslint-plugin-vue:
specifier: 9.18.1 specifier: 9.18.1
version: 9.18.1(eslint@8.53.0) version: 9.18.1(eslint@8.53.0)
@ -1055,7 +1055,7 @@ importers:
version: 4.0.5 version: 4.0.5
msw: msw:
specifier: 1.3.2 specifier: 1.3.2
version: 1.3.2(typescript@5.2.2) version: 1.3.2(typescript@5.3.2)
msw-storybook-addon: msw-storybook-addon:
specifier: 1.10.0 specifier: 1.10.0
version: 1.10.0(msw@1.3.2) version: 1.10.0(msw@1.3.2)
@ -1079,7 +1079,7 @@ importers:
version: 7.5.3 version: 7.5.3
storybook-addon-misskey-theme: storybook-addon-misskey-theme:
specifier: github:misskey-dev/storybook-addon-misskey-theme specifier: github:misskey-dev/storybook-addon-misskey-theme
version: github.com/misskey-dev/storybook-addon-misskey-theme/cf583db098365b2ccc81a82f63ca9c93bc32b640(@storybook/blocks@7.5.3)(@storybook/components@7.5.2)(@storybook/core-events@7.5.3)(@storybook/manager-api@7.5.3)(@storybook/preview-api@7.5.3)(@storybook/theming@7.5.3)(@storybook/types@7.5.3)(react-dom@18.2.0)(react@18.2.0) version: github.com/misskey-dev/storybook-addon-misskey-theme/cf583db098365b2ccc81a82f63ca9c93bc32b640(@storybook/blocks@7.5.3)(@storybook/components@7.5.3)(@storybook/core-events@7.5.3)(@storybook/manager-api@7.5.3)(@storybook/preview-api@7.5.3)(@storybook/theming@7.5.3)(@storybook/types@7.5.3)(react-dom@18.2.0)(react@18.2.0)
summaly: summaly:
specifier: github:misskey-dev/summaly specifier: github:misskey-dev/summaly
version: github.com/misskey-dev/summaly/d2d8db49943ccb201c1b1b283e9d0a630519fac7 version: github.com/misskey-dev/summaly/d2d8db49943ccb201c1b1b283e9d0a630519fac7
@ -1097,7 +1097,7 @@ importers:
version: 9.3.2(eslint@8.53.0) version: 9.3.2(eslint@8.53.0)
vue-tsc: vue-tsc:
specifier: 1.8.22 specifier: 1.8.22
version: 1.8.22(typescript@5.2.2) version: 1.8.22(typescript@5.3.2)
packages/sw: packages/sw:
dependencies: dependencies:
@ -1113,7 +1113,7 @@ importers:
devDependencies: devDependencies:
'@typescript-eslint/parser': '@typescript-eslint/parser':
specifier: 6.11.0 specifier: 6.11.0
version: 6.11.0(eslint@8.53.0)(typescript@5.2.2) version: 6.11.0(eslint@8.53.0)(typescript@5.3.2)
'@typescript/lib-webworker': '@typescript/lib-webworker':
specifier: npm:@types/serviceworker@0.0.67 specifier: npm:@types/serviceworker@0.0.67
version: /@types/serviceworker@0.0.67 version: /@types/serviceworker@0.0.67
@ -1124,8 +1124,8 @@ importers:
specifier: 2.29.0 specifier: 2.29.0
version: 2.29.0(@typescript-eslint/parser@6.11.0)(eslint@8.53.0) version: 2.29.0(@typescript-eslint/parser@6.11.0)(eslint@8.53.0)
typescript: typescript:
specifier: 5.2.2 specifier: 5.3.2
version: 5.2.2 version: 5.3.2
packages: packages:
@ -4384,7 +4384,7 @@ packages:
chalk: 4.1.2 chalk: 4.1.2
dev: true dev: true
/@joshwooding/vite-plugin-react-docgen-typescript@0.3.0(typescript@5.2.2)(vite@4.5.0): /@joshwooding/vite-plugin-react-docgen-typescript@0.3.0(typescript@5.3.2)(vite@4.5.0):
resolution: {integrity: sha512-2D6y7fNvFmsLmRt6UCOFJPvFoPMJGT0Uh1Wg0RaigUp7kdQPs6yYn8Dmx6GZkOH/NW0yMTwRz/p0SRMMRo50vA==} resolution: {integrity: sha512-2D6y7fNvFmsLmRt6UCOFJPvFoPMJGT0Uh1Wg0RaigUp7kdQPs6yYn8Dmx6GZkOH/NW0yMTwRz/p0SRMMRo50vA==}
peerDependencies: peerDependencies:
typescript: '>= 4.3.x' typescript: '>= 4.3.x'
@ -4396,8 +4396,8 @@ packages:
glob: 7.2.3 glob: 7.2.3
glob-promise: 4.2.2(glob@7.2.3) glob-promise: 4.2.2(glob@7.2.3)
magic-string: 0.27.0 magic-string: 0.27.0
react-docgen-typescript: 2.2.2(typescript@5.2.2) react-docgen-typescript: 2.2.2(typescript@5.3.2)
typescript: 5.2.2 typescript: 5.3.2
vite: 4.5.0(@types/node@20.9.1)(sass@1.69.5)(terser@5.24.0) vite: 4.5.0(@types/node@20.9.1)(sass@1.69.5)(terser@5.24.0)
dev: true dev: true
@ -6599,7 +6599,7 @@ packages:
- supports-color - supports-color
dev: true dev: true
/@storybook/builder-vite@7.5.3(typescript@5.2.2)(vite@4.5.0): /@storybook/builder-vite@7.5.3(typescript@5.3.2)(vite@4.5.0):
resolution: {integrity: sha512-c104V3O75OCVnfZj0Jr70V09g0KSbPGvQK2Zh31omXGvakG8XrhWolYxkmjOcForJmAqsXnKs/nw3F75Gp853g==} resolution: {integrity: sha512-c104V3O75OCVnfZj0Jr70V09g0KSbPGvQK2Zh31omXGvakG8XrhWolYxkmjOcForJmAqsXnKs/nw3F75Gp853g==}
peerDependencies: peerDependencies:
'@preact/preset-vite': '*' '@preact/preset-vite': '*'
@ -6630,24 +6630,13 @@ packages:
fs-extra: 11.1.1 fs-extra: 11.1.1
magic-string: 0.30.5 magic-string: 0.30.5
rollup: 3.29.4 rollup: 3.29.4
typescript: 5.2.2 typescript: 5.3.2
vite: 4.5.0(@types/node@20.9.1)(sass@1.69.5)(terser@5.24.0) vite: 4.5.0(@types/node@20.9.1)(sass@1.69.5)(terser@5.24.0)
transitivePeerDependencies: transitivePeerDependencies:
- encoding - encoding
- supports-color - supports-color
dev: true dev: true
/@storybook/channels@7.5.2:
resolution: {integrity: sha512-3SgqWq9NS0XX1QxK3riuaOLrReHWwVhI63u6q1ryDD3SttpmAezZETibOAtzDuk2FKgsyHTmAlmcGQf4ZxhOJA==}
dependencies:
'@storybook/client-logger': 7.5.2
'@storybook/core-events': 7.5.2
'@storybook/global': 5.0.0
qs: 6.11.1
telejson: 7.2.0
tiny-invariant: 1.3.1
dev: true
/@storybook/channels@7.5.3: /@storybook/channels@7.5.3:
resolution: {integrity: sha512-dhWuV2o2lmxH0RKuzND8jxYzvSQTSmpE13P0IT/k8+I1up/rSNYOBQJT6SalakcNWXFAMXguo/8E7ApmnKKcEw==} resolution: {integrity: sha512-dhWuV2o2lmxH0RKuzND8jxYzvSQTSmpE13P0IT/k8+I1up/rSNYOBQJT6SalakcNWXFAMXguo/8E7ApmnKKcEw==}
dependencies: dependencies:
@ -6711,12 +6700,6 @@ packages:
- utf-8-validate - utf-8-validate
dev: true dev: true
/@storybook/client-logger@7.5.2:
resolution: {integrity: sha512-7YgLItlmiYDzWYexTaRNuHhtFarh9krsI+8l7Yjn9ryoHSTJUcTWx+yPJm1II+PQR8v/x5UgsxzultjgEurfRQ==}
dependencies:
'@storybook/global': 5.0.0
dev: true
/@storybook/client-logger@7.5.3: /@storybook/client-logger@7.5.3:
resolution: {integrity: sha512-vUFYALypjix5FoJ5M/XUP6KmyTnQJNW1poHdW7WXUVSg+lBM6E5eAtjTm0hdxNNDH8KSrdy24nCLra5h0X0BWg==} resolution: {integrity: sha512-vUFYALypjix5FoJ5M/XUP6KmyTnQJNW1poHdW7WXUVSg+lBM6E5eAtjTm0hdxNNDH8KSrdy24nCLra5h0X0BWg==}
dependencies: dependencies:
@ -6744,29 +6727,6 @@ packages:
- supports-color - supports-color
dev: true dev: true
/@storybook/components@7.5.2(react-dom@18.2.0)(react@18.2.0):
resolution: {integrity: sha512-OP+o6AoxoQDbqjk/jdQ1arlc1T8601eCL+rS1dJY9EtAFq7Z0LEFtafhEW/Lx8FotfVGjfCNptH9ODhHU6e5Jw==}
peerDependencies:
react: ^16.8.0 || ^17.0.0 || ^18.0.0
react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0
dependencies:
'@radix-ui/react-select': 1.2.2(react-dom@18.2.0)(react@18.2.0)
'@radix-ui/react-toolbar': 1.0.4(react-dom@18.2.0)(react@18.2.0)
'@storybook/client-logger': 7.5.2
'@storybook/csf': 0.1.0
'@storybook/global': 5.0.0
'@storybook/theming': 7.5.2(react-dom@18.2.0)(react@18.2.0)
'@storybook/types': 7.5.2
memoizerific: 1.11.3
react: 18.2.0
react-dom: 18.2.0(react@18.2.0)
use-resize-observer: 9.1.0(react-dom@18.2.0)(react@18.2.0)
util-deprecate: 1.0.2
transitivePeerDependencies:
- '@types/react'
- '@types/react-dom'
dev: true
/@storybook/components@7.5.3(react-dom@18.2.0)(react@18.2.0): /@storybook/components@7.5.3(react-dom@18.2.0)(react@18.2.0):
resolution: {integrity: sha512-M3+cjvEsDGLUx8RvK5wyF6/13LNlUnKbMgiDE8Sxk/v/WPpyhOAIh/B8VmrU1psahS61Jd4MTkFmLf1cWau1vw==} resolution: {integrity: sha512-M3+cjvEsDGLUx8RvK5wyF6/13LNlUnKbMgiDE8Sxk/v/WPpyhOAIh/B8VmrU1psahS61Jd4MTkFmLf1cWau1vw==}
peerDependencies: peerDependencies:
@ -6828,12 +6788,6 @@ packages:
- supports-color - supports-color
dev: true dev: true
/@storybook/core-events@7.5.2:
resolution: {integrity: sha512-DV8bFEFVKDEvaH87KYPXDE0YEV+Y9yjFv2xxmC9pF8l+MWCtVW72RBLhB+gU5NM1bkHrRDNb0lOJfVGKlhxOog==}
dependencies:
ts-dedent: 2.2.0
dev: true
/@storybook/core-events@7.5.3: /@storybook/core-events@7.5.3:
resolution: {integrity: sha512-DFOpyQ22JD5C1oeOFzL8wlqSWZzrqgDfDbUGP8xdO4wJu+FVTxnnWN6ZYLdTPB1u27DOhd7TzjQMfLDHLu7kbQ==} resolution: {integrity: sha512-DFOpyQ22JD5C1oeOFzL8wlqSWZzrqgDfDbUGP8xdO4wJu+FVTxnnWN6ZYLdTPB1u27DOhd7TzjQMfLDHLu7kbQ==}
dependencies: dependencies:
@ -7053,7 +7007,7 @@ packages:
react-dom: 18.2.0(react@18.2.0) react-dom: 18.2.0(react@18.2.0)
dev: true dev: true
/@storybook/react-vite@7.5.3(react-dom@18.2.0)(react@18.2.0)(rollup@4.4.1)(typescript@5.2.2)(vite@4.5.0): /@storybook/react-vite@7.5.3(react-dom@18.2.0)(react@18.2.0)(rollup@4.4.1)(typescript@5.3.2)(vite@4.5.0):
resolution: {integrity: sha512-ArPyHgiPbT5YvcyK4xK/DfqBOpn4R4/EP3kfIGhx8QKJyOtxPEYFdkLIZ5xu3KnPX7/z7GT+4a6Rb+8sk9gliA==} resolution: {integrity: sha512-ArPyHgiPbT5YvcyK4xK/DfqBOpn4R4/EP3kfIGhx8QKJyOtxPEYFdkLIZ5xu3KnPX7/z7GT+4a6Rb+8sk9gliA==}
engines: {node: '>=16'} engines: {node: '>=16'}
peerDependencies: peerDependencies:
@ -7061,10 +7015,10 @@ packages:
react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0
vite: ^3.0.0 || ^4.0.0 || ^5.0.0 vite: ^3.0.0 || ^4.0.0 || ^5.0.0
dependencies: dependencies:
'@joshwooding/vite-plugin-react-docgen-typescript': 0.3.0(typescript@5.2.2)(vite@4.5.0) '@joshwooding/vite-plugin-react-docgen-typescript': 0.3.0(typescript@5.3.2)(vite@4.5.0)
'@rollup/pluginutils': 5.0.5(rollup@4.4.1) '@rollup/pluginutils': 5.0.5(rollup@4.4.1)
'@storybook/builder-vite': 7.5.3(typescript@5.2.2)(vite@4.5.0) '@storybook/builder-vite': 7.5.3(typescript@5.3.2)(vite@4.5.0)
'@storybook/react': 7.5.3(react-dom@18.2.0)(react@18.2.0)(typescript@5.2.2) '@storybook/react': 7.5.3(react-dom@18.2.0)(react@18.2.0)(typescript@5.3.2)
'@vitejs/plugin-react': 3.1.0(vite@4.5.0) '@vitejs/plugin-react': 3.1.0(vite@4.5.0)
magic-string: 0.30.5 magic-string: 0.30.5
react: 18.2.0 react: 18.2.0
@ -7080,7 +7034,7 @@ packages:
- vite-plugin-glimmerx - vite-plugin-glimmerx
dev: true dev: true
/@storybook/react@7.5.3(react-dom@18.2.0)(react@18.2.0)(typescript@5.2.2): /@storybook/react@7.5.3(react-dom@18.2.0)(react@18.2.0)(typescript@5.3.2):
resolution: {integrity: sha512-dZILdM36xMFDjdmmy421G5X+sOIncB2qF3IPTooniG1i1Z6v/dVNo57ovdID9lDTNa+AWr2fLB9hANiISMqmjQ==} resolution: {integrity: sha512-dZILdM36xMFDjdmmy421G5X+sOIncB2qF3IPTooniG1i1Z6v/dVNo57ovdID9lDTNa+AWr2fLB9hANiISMqmjQ==}
engines: {node: '>=16.0.0'} engines: {node: '>=16.0.0'}
peerDependencies: peerDependencies:
@ -7113,7 +7067,7 @@ packages:
react-element-to-jsx-string: 15.0.0(react-dom@18.2.0)(react@18.2.0) react-element-to-jsx-string: 15.0.0(react-dom@18.2.0)(react@18.2.0)
ts-dedent: 2.2.0 ts-dedent: 2.2.0
type-fest: 2.19.0 type-fest: 2.19.0
typescript: 5.2.2 typescript: 5.3.2
util-deprecate: 1.0.2 util-deprecate: 1.0.2
transitivePeerDependencies: transitivePeerDependencies:
- encoding - encoding
@ -7172,20 +7126,6 @@ packages:
ts-dedent: 2.2.0 ts-dedent: 2.2.0
dev: true dev: true
/@storybook/theming@7.5.2(react-dom@18.2.0)(react@18.2.0):
resolution: {integrity: sha512-DZBTcYErSYvmTYsGz7lKtiIcBe8flBw5Ojp52r3O4GcRYG4AbuUwwVvehz+O1cWaS+UW3HavrcgapERH7ZHd1A==}
peerDependencies:
react: ^16.8.0 || ^17.0.0 || ^18.0.0
react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0
dependencies:
'@emotion/use-insertion-effect-with-fallbacks': 1.0.0(react@18.2.0)
'@storybook/client-logger': 7.5.2
'@storybook/global': 5.0.0
memoizerific: 1.11.3
react: 18.2.0
react-dom: 18.2.0(react@18.2.0)
dev: true
/@storybook/theming@7.5.3(react-dom@18.2.0)(react@18.2.0): /@storybook/theming@7.5.3(react-dom@18.2.0)(react@18.2.0):
resolution: {integrity: sha512-Cjmthe1MAk0z4RKCZ7m72gAD8YD0zTAH97z5ryM1Qv84QXjiCQ143fGOmYz1xEQdNFpOThPcwW6FEccLHTkVcg==} resolution: {integrity: sha512-Cjmthe1MAk0z4RKCZ7m72gAD8YD0zTAH97z5ryM1Qv84QXjiCQ143fGOmYz1xEQdNFpOThPcwW6FEccLHTkVcg==}
peerDependencies: peerDependencies:
@ -7200,15 +7140,6 @@ packages:
react-dom: 18.2.0(react@18.2.0) react-dom: 18.2.0(react@18.2.0)
dev: true dev: true
/@storybook/types@7.5.2:
resolution: {integrity: sha512-RDKHo6WUES+4nt7uZMfankjxdpYX2EI2GpJ2n2RPcnhzmb/ub1huNTjbzDEYMqY24SppljZeIN57m3Ar6L6f9A==}
dependencies:
'@storybook/channels': 7.5.2
'@types/babel__core': 7.20.0
'@types/express': 4.17.17
file-system-cache: 2.3.0
dev: true
/@storybook/types@7.5.3: /@storybook/types@7.5.3:
resolution: {integrity: sha512-iu5W0Kdd6nysN5CPkY4GRl+0BpxRTdSfBIJak7mb6xCIHSB5t1tw4BOuqMQ5EgpikRY3MWJ4gY647QkWBX3MNQ==} resolution: {integrity: sha512-iu5W0Kdd6nysN5CPkY4GRl+0BpxRTdSfBIJak7mb6xCIHSB5t1tw4BOuqMQ5EgpikRY3MWJ4gY647QkWBX3MNQ==}
dependencies: dependencies:
@ -7218,7 +7149,7 @@ packages:
file-system-cache: 2.3.0 file-system-cache: 2.3.0
dev: true dev: true
/@storybook/vue3-vite@7.5.3(@vue/compiler-core@3.3.7)(react-dom@18.2.0)(react@18.2.0)(typescript@5.2.2)(vite@4.5.0)(vue@3.3.8): /@storybook/vue3-vite@7.5.3(@vue/compiler-core@3.3.8)(react-dom@18.2.0)(react@18.2.0)(typescript@5.3.2)(vite@4.5.0)(vue@3.3.8):
resolution: {integrity: sha512-gkNwDDn2AKthAtaoPrHb0+2gi33UluxpfSq/M5COoMEVFphj6y/jyDa+OEYlceXgnD8g2xvX4/yv2TbTNDzmcQ==} resolution: {integrity: sha512-gkNwDDn2AKthAtaoPrHb0+2gi33UluxpfSq/M5COoMEVFphj6y/jyDa+OEYlceXgnD8g2xvX4/yv2TbTNDzmcQ==}
engines: {node: ^14.18 || >=16} engines: {node: ^14.18 || >=16}
peerDependencies: peerDependencies:
@ -7226,9 +7157,9 @@ packages:
react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0
vite: ^3.0.0 || ^4.0.0 || ^5.0.0 vite: ^3.0.0 || ^4.0.0 || ^5.0.0
dependencies: dependencies:
'@storybook/builder-vite': 7.5.3(typescript@5.2.2)(vite@4.5.0) '@storybook/builder-vite': 7.5.3(typescript@5.3.2)(vite@4.5.0)
'@storybook/core-server': 7.5.3 '@storybook/core-server': 7.5.3
'@storybook/vue3': 7.5.3(@vue/compiler-core@3.3.7)(vue@3.3.8) '@storybook/vue3': 7.5.3(@vue/compiler-core@3.3.8)(vue@3.3.8)
'@vitejs/plugin-vue': 4.5.0(vite@4.5.0)(vue@3.3.8) '@vitejs/plugin-vue': 4.5.0(vite@4.5.0)(vue@3.3.8)
magic-string: 0.30.5 magic-string: 0.30.5
react: 18.2.0 react: 18.2.0
@ -7247,7 +7178,7 @@ packages:
- vue - vue
dev: true dev: true
/@storybook/vue3@7.5.3(@vue/compiler-core@3.3.7)(vue@3.3.8): /@storybook/vue3@7.5.3(@vue/compiler-core@3.3.8)(vue@3.3.8):
resolution: {integrity: sha512-JaxtOl3UD9YhPrOqHuKtpqHMnFril3sBUxx/no2yM/mZYmNpAVd/C6PFM839WCay1mAywPuUoebJvmwWxWijkw==} resolution: {integrity: sha512-JaxtOl3UD9YhPrOqHuKtpqHMnFril3sBUxx/no2yM/mZYmNpAVd/C6PFM839WCay1mAywPuUoebJvmwWxWijkw==}
engines: {node: '>=16.0.0'} engines: {node: '>=16.0.0'}
peerDependencies: peerDependencies:
@ -7259,11 +7190,11 @@ packages:
'@storybook/global': 5.0.0 '@storybook/global': 5.0.0
'@storybook/preview-api': 7.5.3 '@storybook/preview-api': 7.5.3
'@storybook/types': 7.5.3 '@storybook/types': 7.5.3
'@vue/compiler-core': 3.3.7 '@vue/compiler-core': 3.3.8
lodash: 4.17.21 lodash: 4.17.21
ts-dedent: 2.2.0 ts-dedent: 2.2.0
type-fest: 2.19.0 type-fest: 2.19.0
vue: 3.3.8(typescript@5.2.2) vue: 3.3.8(typescript@5.3.2)
vue-component-type-helpers: 1.8.22 vue-component-type-helpers: 1.8.22
transitivePeerDependencies: transitivePeerDependencies:
- encoding - encoding
@ -7758,7 +7689,7 @@ packages:
'@testing-library/dom': 9.3.3 '@testing-library/dom': 9.3.3
'@vue/compiler-sfc': 3.3.8 '@vue/compiler-sfc': 3.3.8
'@vue/test-utils': 2.4.1(vue@3.3.8) '@vue/test-utils': 2.4.1(vue@3.3.8)
vue: 3.3.8(typescript@5.2.2) vue: 3.3.8(typescript@5.3.2)
transitivePeerDependencies: transitivePeerDependencies:
- '@vue/server-renderer' - '@vue/server-renderer'
dev: true dev: true
@ -8447,7 +8378,7 @@ packages:
dev: true dev: true
optional: true optional: true
/@typescript-eslint/eslint-plugin@6.11.0(@typescript-eslint/parser@6.11.0)(eslint@8.53.0)(typescript@5.2.2): /@typescript-eslint/eslint-plugin@6.11.0(@typescript-eslint/parser@6.11.0)(eslint@8.53.0)(typescript@5.3.2):
resolution: {integrity: sha512-uXnpZDc4VRjY4iuypDBKzW1rz9T5YBBK0snMn8MaTSNd2kMlj50LnLBABELjJiOL5YHk7ZD8hbSpI9ubzqYI0w==} resolution: {integrity: sha512-uXnpZDc4VRjY4iuypDBKzW1rz9T5YBBK0snMn8MaTSNd2kMlj50LnLBABELjJiOL5YHk7ZD8hbSpI9ubzqYI0w==}
engines: {node: ^16.0.0 || >=18.0.0} engines: {node: ^16.0.0 || >=18.0.0}
peerDependencies: peerDependencies:
@ -8459,10 +8390,10 @@ packages:
optional: true optional: true
dependencies: dependencies:
'@eslint-community/regexpp': 4.6.2 '@eslint-community/regexpp': 4.6.2
'@typescript-eslint/parser': 6.11.0(eslint@8.53.0)(typescript@5.2.2) '@typescript-eslint/parser': 6.11.0(eslint@8.53.0)(typescript@5.3.2)
'@typescript-eslint/scope-manager': 6.11.0 '@typescript-eslint/scope-manager': 6.11.0
'@typescript-eslint/type-utils': 6.11.0(eslint@8.53.0)(typescript@5.2.2) '@typescript-eslint/type-utils': 6.11.0(eslint@8.53.0)(typescript@5.3.2)
'@typescript-eslint/utils': 6.11.0(eslint@8.53.0)(typescript@5.2.2) '@typescript-eslint/utils': 6.11.0(eslint@8.53.0)(typescript@5.3.2)
'@typescript-eslint/visitor-keys': 6.11.0 '@typescript-eslint/visitor-keys': 6.11.0
debug: 4.3.4(supports-color@8.1.1) debug: 4.3.4(supports-color@8.1.1)
eslint: 8.53.0 eslint: 8.53.0
@ -8470,13 +8401,13 @@ packages:
ignore: 5.2.4 ignore: 5.2.4
natural-compare: 1.4.0 natural-compare: 1.4.0
semver: 7.5.4 semver: 7.5.4
ts-api-utils: 1.0.1(typescript@5.2.2) ts-api-utils: 1.0.1(typescript@5.3.2)
typescript: 5.2.2 typescript: 5.3.2
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
dev: true dev: true
/@typescript-eslint/parser@6.11.0(eslint@8.53.0)(typescript@5.2.2): /@typescript-eslint/parser@6.11.0(eslint@8.53.0)(typescript@5.3.2):
resolution: {integrity: sha512-+whEdjk+d5do5nxfxx73oanLL9ghKO3EwM9kBCkUtWMRwWuPaFv9ScuqlYfQ6pAD6ZiJhky7TZ2ZYhrMsfMxVQ==} resolution: {integrity: sha512-+whEdjk+d5do5nxfxx73oanLL9ghKO3EwM9kBCkUtWMRwWuPaFv9ScuqlYfQ6pAD6ZiJhky7TZ2ZYhrMsfMxVQ==}
engines: {node: ^16.0.0 || >=18.0.0} engines: {node: ^16.0.0 || >=18.0.0}
peerDependencies: peerDependencies:
@ -8488,11 +8419,11 @@ packages:
dependencies: dependencies:
'@typescript-eslint/scope-manager': 6.11.0 '@typescript-eslint/scope-manager': 6.11.0
'@typescript-eslint/types': 6.11.0 '@typescript-eslint/types': 6.11.0
'@typescript-eslint/typescript-estree': 6.11.0(typescript@5.2.2) '@typescript-eslint/typescript-estree': 6.11.0(typescript@5.3.2)
'@typescript-eslint/visitor-keys': 6.11.0 '@typescript-eslint/visitor-keys': 6.11.0
debug: 4.3.4(supports-color@8.1.1) debug: 4.3.4(supports-color@8.1.1)
eslint: 8.53.0 eslint: 8.53.0
typescript: 5.2.2 typescript: 5.3.2
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
dev: true dev: true
@ -8513,7 +8444,7 @@ packages:
'@typescript-eslint/visitor-keys': 6.11.0 '@typescript-eslint/visitor-keys': 6.11.0
dev: true dev: true
/@typescript-eslint/type-utils@6.11.0(eslint@8.53.0)(typescript@5.2.2): /@typescript-eslint/type-utils@6.11.0(eslint@8.53.0)(typescript@5.3.2):
resolution: {integrity: sha512-nA4IOXwZtqBjIoYrJcYxLRO+F9ri+leVGoJcMW1uqr4r1Hq7vW5cyWrA43lFbpRvQ9XgNrnfLpIkO3i1emDBIA==} resolution: {integrity: sha512-nA4IOXwZtqBjIoYrJcYxLRO+F9ri+leVGoJcMW1uqr4r1Hq7vW5cyWrA43lFbpRvQ9XgNrnfLpIkO3i1emDBIA==}
engines: {node: ^16.0.0 || >=18.0.0} engines: {node: ^16.0.0 || >=18.0.0}
peerDependencies: peerDependencies:
@ -8523,12 +8454,12 @@ packages:
typescript: typescript:
optional: true optional: true
dependencies: dependencies:
'@typescript-eslint/typescript-estree': 6.11.0(typescript@5.2.2) '@typescript-eslint/typescript-estree': 6.11.0(typescript@5.3.2)
'@typescript-eslint/utils': 6.11.0(eslint@8.53.0)(typescript@5.2.2) '@typescript-eslint/utils': 6.11.0(eslint@8.53.0)(typescript@5.3.2)
debug: 4.3.4(supports-color@8.1.1) debug: 4.3.4(supports-color@8.1.1)
eslint: 8.53.0 eslint: 8.53.0
ts-api-utils: 1.0.1(typescript@5.2.2) ts-api-utils: 1.0.1(typescript@5.3.2)
typescript: 5.2.2 typescript: 5.3.2
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
dev: true dev: true
@ -8543,7 +8474,7 @@ packages:
engines: {node: ^16.0.0 || >=18.0.0} engines: {node: ^16.0.0 || >=18.0.0}
dev: true dev: true
/@typescript-eslint/typescript-estree@5.62.0(typescript@5.2.2): /@typescript-eslint/typescript-estree@5.62.0(typescript@5.3.2):
resolution: {integrity: sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==} resolution: {integrity: sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
peerDependencies: peerDependencies:
@ -8558,13 +8489,13 @@ packages:
globby: 11.1.0 globby: 11.1.0
is-glob: 4.0.3 is-glob: 4.0.3
semver: 7.5.4 semver: 7.5.4
tsutils: 3.21.0(typescript@5.2.2) tsutils: 3.21.0(typescript@5.3.2)
typescript: 5.2.2 typescript: 5.3.2
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
dev: true dev: true
/@typescript-eslint/typescript-estree@6.11.0(typescript@5.2.2): /@typescript-eslint/typescript-estree@6.11.0(typescript@5.3.2):
resolution: {integrity: sha512-Aezzv1o2tWJwvZhedzvD5Yv7+Lpu1by/U1LZ5gLc4tCx8jUmuSCMioPFRjliN/6SJIvY6HpTtJIWubKuYYYesQ==} resolution: {integrity: sha512-Aezzv1o2tWJwvZhedzvD5Yv7+Lpu1by/U1LZ5gLc4tCx8jUmuSCMioPFRjliN/6SJIvY6HpTtJIWubKuYYYesQ==}
engines: {node: ^16.0.0 || >=18.0.0} engines: {node: ^16.0.0 || >=18.0.0}
peerDependencies: peerDependencies:
@ -8579,13 +8510,13 @@ packages:
globby: 11.1.0 globby: 11.1.0
is-glob: 4.0.3 is-glob: 4.0.3
semver: 7.5.4 semver: 7.5.4
ts-api-utils: 1.0.1(typescript@5.2.2) ts-api-utils: 1.0.1(typescript@5.3.2)
typescript: 5.2.2 typescript: 5.3.2
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
dev: true dev: true
/@typescript-eslint/utils@5.62.0(eslint@8.53.0)(typescript@5.2.2): /@typescript-eslint/utils@5.62.0(eslint@8.53.0)(typescript@5.3.2):
resolution: {integrity: sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==} resolution: {integrity: sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
peerDependencies: peerDependencies:
@ -8596,7 +8527,7 @@ packages:
'@types/semver': 7.5.5 '@types/semver': 7.5.5
'@typescript-eslint/scope-manager': 5.62.0 '@typescript-eslint/scope-manager': 5.62.0
'@typescript-eslint/types': 5.62.0 '@typescript-eslint/types': 5.62.0
'@typescript-eslint/typescript-estree': 5.62.0(typescript@5.2.2) '@typescript-eslint/typescript-estree': 5.62.0(typescript@5.3.2)
eslint: 8.53.0 eslint: 8.53.0
eslint-scope: 5.1.1 eslint-scope: 5.1.1
semver: 7.5.4 semver: 7.5.4
@ -8605,7 +8536,7 @@ packages:
- typescript - typescript
dev: true dev: true
/@typescript-eslint/utils@6.11.0(eslint@8.53.0)(typescript@5.2.2): /@typescript-eslint/utils@6.11.0(eslint@8.53.0)(typescript@5.3.2):
resolution: {integrity: sha512-p23ibf68fxoZy605dc0dQAEoUsoiNoP3MD9WQGiHLDuTSOuqoTsa4oAy+h3KDkTcxbbfOtUjb9h3Ta0gT4ug2g==} resolution: {integrity: sha512-p23ibf68fxoZy605dc0dQAEoUsoiNoP3MD9WQGiHLDuTSOuqoTsa4oAy+h3KDkTcxbbfOtUjb9h3Ta0gT4ug2g==}
engines: {node: ^16.0.0 || >=18.0.0} engines: {node: ^16.0.0 || >=18.0.0}
peerDependencies: peerDependencies:
@ -8616,7 +8547,7 @@ packages:
'@types/semver': 7.5.5 '@types/semver': 7.5.5
'@typescript-eslint/scope-manager': 6.11.0 '@typescript-eslint/scope-manager': 6.11.0
'@typescript-eslint/types': 6.11.0 '@typescript-eslint/types': 6.11.0
'@typescript-eslint/typescript-estree': 6.11.0(typescript@5.2.2) '@typescript-eslint/typescript-estree': 6.11.0(typescript@5.3.2)
eslint: 8.53.0 eslint: 8.53.0
semver: 7.5.4 semver: 7.5.4
transitivePeerDependencies: transitivePeerDependencies:
@ -8679,7 +8610,7 @@ packages:
vue: ^3.2.25 vue: ^3.2.25
dependencies: dependencies:
vite: 4.5.0(@types/node@20.9.1)(sass@1.69.5)(terser@5.24.0) vite: 4.5.0(@types/node@20.9.1)(sass@1.69.5)(terser@5.24.0)
vue: 3.3.8(typescript@5.2.2) vue: 3.3.8(typescript@5.3.2)
/@vitest/coverage-v8@0.34.6(vitest@0.34.6): /@vitest/coverage-v8@0.34.6(vitest@0.34.6):
resolution: {integrity: sha512-fivy/OK2d/EsJFoEoxHFEnNGTg+MmdZBAVK9Ka4qhXR2K3J0DS08vcGVwzDtXSuUMabLv4KtPcpSKkcMXFDViw==} resolution: {integrity: sha512-fivy/OK2d/EsJFoEoxHFEnNGTg+MmdZBAVK9Ka4qhXR2K3J0DS08vcGVwzDtXSuUMabLv4KtPcpSKkcMXFDViw==}
@ -8774,7 +8705,7 @@ packages:
ast-kit: 0.11.2(rollup@4.4.1) ast-kit: 0.11.2(rollup@4.4.1)
local-pkg: 0.5.0 local-pkg: 0.5.0
magic-string-ast: 0.3.0 magic-string-ast: 0.3.0
vue: 3.3.8(typescript@5.2.2) vue: 3.3.8(typescript@5.3.2)
transitivePeerDependencies: transitivePeerDependencies:
- rollup - rollup
dev: false dev: false
@ -8791,7 +8722,7 @@ packages:
'@vue/shared': 3.3.8 '@vue/shared': 3.3.8
magic-string: 0.30.5 magic-string: 0.30.5
unplugin: 1.5.1 unplugin: 1.5.1
vue: 3.3.8(typescript@5.2.2) vue: 3.3.8(typescript@5.3.2)
transitivePeerDependencies: transitivePeerDependencies:
- rollup - rollup
dev: false dev: false
@ -8862,7 +8793,7 @@ packages:
'@vue/compiler-dom': 3.3.8 '@vue/compiler-dom': 3.3.8
'@vue/shared': 3.3.8 '@vue/shared': 3.3.8
/@vue/language-core@1.8.22(typescript@5.2.2): /@vue/language-core@1.8.22(typescript@5.3.2):
resolution: {integrity: sha512-bsMoJzCrXZqGsxawtUea1cLjUT9dZnDsy5TuZ+l1fxRMzUGQUG9+Ypq4w//CqpWmrx7nIAJpw2JVF/t258miRw==} resolution: {integrity: sha512-bsMoJzCrXZqGsxawtUea1cLjUT9dZnDsy5TuZ+l1fxRMzUGQUG9+Ypq4w//CqpWmrx7nIAJpw2JVF/t258miRw==}
peerDependencies: peerDependencies:
typescript: '*' typescript: '*'
@ -8877,7 +8808,7 @@ packages:
computeds: 0.0.1 computeds: 0.0.1
minimatch: 9.0.3 minimatch: 9.0.3
muggle-string: 0.3.1 muggle-string: 0.3.1
typescript: 5.2.2 typescript: 5.3.2
vue-template-compiler: 2.7.14 vue-template-compiler: 2.7.14
dev: true dev: true
@ -8915,7 +8846,7 @@ packages:
dependencies: dependencies:
'@vue/compiler-ssr': 3.3.8 '@vue/compiler-ssr': 3.3.8
'@vue/shared': 3.3.8 '@vue/shared': 3.3.8
vue: 3.3.8(typescript@5.2.2) vue: 3.3.8(typescript@5.3.2)
/@vue/shared@3.3.6: /@vue/shared@3.3.6:
resolution: {integrity: sha512-Xno5pEqg8SVhomD0kTSmfh30ZEmV/+jZtyh39q6QflrjdJCXah5lrnOLi9KB6a5k5aAHXMXjoMnxlzUkCNfWLQ==} resolution: {integrity: sha512-Xno5pEqg8SVhomD0kTSmfh30ZEmV/+jZtyh39q6QflrjdJCXah5lrnOLi9KB6a5k5aAHXMXjoMnxlzUkCNfWLQ==}
@ -8938,7 +8869,7 @@ packages:
optional: true optional: true
dependencies: dependencies:
js-beautify: 1.14.9 js-beautify: 1.14.9
vue: 3.3.8(typescript@5.2.2) vue: 3.3.8(typescript@5.3.2)
vue-component-type-helpers: 1.8.4 vue-component-type-helpers: 1.8.4
dev: true dev: true
@ -11660,7 +11591,7 @@ packages:
eslint-import-resolver-webpack: eslint-import-resolver-webpack:
optional: true optional: true
dependencies: dependencies:
'@typescript-eslint/parser': 6.11.0(eslint@8.53.0)(typescript@5.2.2) '@typescript-eslint/parser': 6.11.0(eslint@8.53.0)(typescript@5.3.2)
debug: 3.2.7(supports-color@5.5.0) debug: 3.2.7(supports-color@5.5.0)
eslint: 8.53.0 eslint: 8.53.0
eslint-import-resolver-node: 0.3.9 eslint-import-resolver-node: 0.3.9
@ -11678,7 +11609,7 @@ packages:
'@typescript-eslint/parser': '@typescript-eslint/parser':
optional: true optional: true
dependencies: dependencies:
'@typescript-eslint/parser': 6.11.0(eslint@8.53.0)(typescript@5.2.2) '@typescript-eslint/parser': 6.11.0(eslint@8.53.0)(typescript@5.3.2)
array-includes: 3.1.7 array-includes: 3.1.7
array.prototype.findlastindex: 1.2.3 array.prototype.findlastindex: 1.2.3
array.prototype.flat: 1.3.2 array.prototype.flat: 1.3.2
@ -11703,14 +11634,14 @@ packages:
- supports-color - supports-color
dev: true dev: true
/eslint-plugin-storybook@0.6.13(eslint@8.53.0)(typescript@5.2.2): /eslint-plugin-storybook@0.6.13(eslint@8.53.0)(typescript@5.3.2):
resolution: {integrity: sha512-smd+CS0WH1jBqUEJ3znGS7DU4ayBE9z6lkQAK2yrSUv1+rq8BT/tiI5C/rKE7rmiqiAfojtNYZRhzo5HrulccQ==} resolution: {integrity: sha512-smd+CS0WH1jBqUEJ3znGS7DU4ayBE9z6lkQAK2yrSUv1+rq8BT/tiI5C/rKE7rmiqiAfojtNYZRhzo5HrulccQ==}
engines: {node: 12.x || 14.x || >= 16} engines: {node: 12.x || 14.x || >= 16}
peerDependencies: peerDependencies:
eslint: '>=6' eslint: '>=6'
dependencies: dependencies:
'@storybook/csf': 0.0.1 '@storybook/csf': 0.0.1
'@typescript-eslint/utils': 5.62.0(eslint@8.53.0)(typescript@5.2.2) '@typescript-eslint/utils': 5.62.0(eslint@8.53.0)(typescript@5.3.2)
eslint: 8.53.0 eslint: 8.53.0
requireindex: 1.2.0 requireindex: 1.2.0
ts-dedent: 2.2.0 ts-dedent: 2.2.0
@ -15594,10 +15525,10 @@ packages:
msw: '>=0.35.0 <2.0.0' msw: '>=0.35.0 <2.0.0'
dependencies: dependencies:
is-node-process: 1.2.0 is-node-process: 1.2.0
msw: 1.3.2(typescript@5.2.2) msw: 1.3.2(typescript@5.3.2)
dev: true dev: true
/msw@1.3.2(typescript@5.2.2): /msw@1.3.2(typescript@5.3.2):
resolution: {integrity: sha512-wKLhFPR+NitYTkQl5047pia0reNGgf0P6a1eTnA5aNlripmiz0sabMvvHcicE8kQ3/gZcI0YiPFWmYfowfm3lA==} resolution: {integrity: sha512-wKLhFPR+NitYTkQl5047pia0reNGgf0P6a1eTnA5aNlripmiz0sabMvvHcicE8kQ3/gZcI0YiPFWmYfowfm3lA==}
engines: {node: '>=14'} engines: {node: '>=14'}
hasBin: true hasBin: true
@ -15626,7 +15557,7 @@ packages:
path-to-regexp: 6.2.1 path-to-regexp: 6.2.1
strict-event-emitter: 0.4.6 strict-event-emitter: 0.4.6
type-fest: 2.19.0 type-fest: 2.19.0
typescript: 5.2.2 typescript: 5.3.2
yargs: 17.7.2 yargs: 17.7.2
transitivePeerDependencies: transitivePeerDependencies:
- encoding - encoding
@ -17609,12 +17540,12 @@ packages:
react-dom: 18.2.0(react@18.2.0) react-dom: 18.2.0(react@18.2.0)
dev: true dev: true
/react-docgen-typescript@2.2.2(typescript@5.2.2): /react-docgen-typescript@2.2.2(typescript@5.3.2):
resolution: {integrity: sha512-tvg2ZtOpOi6QDwsb3GZhOjDkkX0h8Z2gipvTg6OVMUyoYoURhEiRNePT8NZItTVCDh39JJHnLdfCOkzoLbFnTg==} resolution: {integrity: sha512-tvg2ZtOpOi6QDwsb3GZhOjDkkX0h8Z2gipvTg6OVMUyoYoURhEiRNePT8NZItTVCDh39JJHnLdfCOkzoLbFnTg==}
peerDependencies: peerDependencies:
typescript: '>= 4.3.x' typescript: '>= 4.3.x'
dependencies: dependencies:
typescript: 5.2.2 typescript: 5.3.2
dev: true dev: true
/react-docgen@6.0.4: /react-docgen@6.0.4:
@ -19502,13 +19433,13 @@ packages:
escape-string-regexp: 5.0.0 escape-string-regexp: 5.0.0
dev: false dev: false
/ts-api-utils@1.0.1(typescript@5.2.2): /ts-api-utils@1.0.1(typescript@5.3.2):
resolution: {integrity: sha512-lC/RGlPmwdrIBFTX59wwNzqh7aR2otPNPR/5brHZm/XKFYKsfqxihXUe9pU3JI+3vGkl+vyCoNNnPhJn3aLK1A==} resolution: {integrity: sha512-lC/RGlPmwdrIBFTX59wwNzqh7aR2otPNPR/5brHZm/XKFYKsfqxihXUe9pU3JI+3vGkl+vyCoNNnPhJn3aLK1A==}
engines: {node: '>=16.13.0'} engines: {node: '>=16.13.0'}
peerDependencies: peerDependencies:
typescript: '>=4.2.0' typescript: '>=4.2.0'
dependencies: dependencies:
typescript: 5.2.2 typescript: 5.3.2
dev: true dev: true
/ts-dedent@2.2.0: /ts-dedent@2.2.0:
@ -19580,14 +19511,14 @@ packages:
/tslib@2.6.2: /tslib@2.6.2:
resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==} resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==}
/tsutils@3.21.0(typescript@5.2.2): /tsutils@3.21.0(typescript@5.3.2):
resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==} resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==}
engines: {node: '>= 6'} engines: {node: '>= 6'}
peerDependencies: peerDependencies:
typescript: '>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta' typescript: '>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta'
dependencies: dependencies:
tslib: 1.14.1 tslib: 1.14.1
typescript: 5.2.2 typescript: 5.3.2
dev: true dev: true
/tunnel-agent@0.6.0: /tunnel-agent@0.6.0:
@ -19789,8 +19720,8 @@ packages:
hasBin: true hasBin: true
dev: true dev: true
/typescript@5.2.2: /typescript@5.3.2:
resolution: {integrity: sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==} resolution: {integrity: sha512-6l+RyNy7oAHDfxC4FzSJcz9vnjTKxrLpDG5M2Vu4SHRVNg6xzqZp6LYSR9zjqQTu8DU/f5xwxUdADOkbrIX2gQ==}
engines: {node: '>=14.17'} engines: {node: '>=14.17'}
hasBin: true hasBin: true
@ -20084,7 +20015,7 @@ packages:
diff: 5.1.0 diff: 5.1.0
diff-match-patch: 1.0.5 diff-match-patch: 1.0.5
highlight.js: 11.8.0 highlight.js: 11.8.0
vue: 3.3.8(typescript@5.2.2) vue: 3.3.8(typescript@5.3.2)
vue-demi: 0.13.11(vue@3.3.8) vue-demi: 0.13.11(vue@3.3.8)
dev: false dev: false
@ -20298,7 +20229,7 @@ packages:
'@vue/composition-api': '@vue/composition-api':
optional: true optional: true
dependencies: dependencies:
vue: 3.3.8(typescript@5.2.2) vue: 3.3.8(typescript@5.3.2)
dev: false dev: false
/vue-docgen-api@4.64.1(vue@3.3.8): /vue-docgen-api@4.64.1(vue@3.3.8):
@ -20342,7 +20273,7 @@ packages:
peerDependencies: peerDependencies:
vue: '>=2' vue: '>=2'
dependencies: dependencies:
vue: 3.3.8(typescript@5.2.2) vue: 3.3.8(typescript@5.3.2)
dev: true dev: true
/vue-prism-editor@2.0.0-alpha.2(vue@3.3.8): /vue-prism-editor@2.0.0-alpha.2(vue@3.3.8):
@ -20351,7 +20282,7 @@ packages:
peerDependencies: peerDependencies:
vue: ^3.0.0 vue: ^3.0.0
dependencies: dependencies:
vue: 3.3.8(typescript@5.2.2) vue: 3.3.8(typescript@5.3.2)
dev: false dev: false
/vue-template-compiler@2.7.14: /vue-template-compiler@2.7.14:
@ -20361,19 +20292,19 @@ packages:
he: 1.2.0 he: 1.2.0
dev: true dev: true
/vue-tsc@1.8.22(typescript@5.2.2): /vue-tsc@1.8.22(typescript@5.3.2):
resolution: {integrity: sha512-j9P4kHtW6eEE08aS5McFZE/ivmipXy0JzrnTgbomfABMaVKx37kNBw//irL3+LlE3kOo63XpnRigyPC3w7+z+A==} resolution: {integrity: sha512-j9P4kHtW6eEE08aS5McFZE/ivmipXy0JzrnTgbomfABMaVKx37kNBw//irL3+LlE3kOo63XpnRigyPC3w7+z+A==}
hasBin: true hasBin: true
peerDependencies: peerDependencies:
typescript: '*' typescript: '*'
dependencies: dependencies:
'@volar/typescript': 1.10.9 '@volar/typescript': 1.10.9
'@vue/language-core': 1.8.22(typescript@5.2.2) '@vue/language-core': 1.8.22(typescript@5.3.2)
semver: 7.5.4 semver: 7.5.4
typescript: 5.2.2 typescript: 5.3.2
dev: true dev: true
/vue@3.3.8(typescript@5.2.2): /vue@3.3.8(typescript@5.3.2):
resolution: {integrity: sha512-5VSX/3DabBikOXMsxzlW8JyfeLKlG9mzqnWgLQLty88vdZL7ZJgrdgBOmrArwxiLtmS+lNNpPcBYqrhE6TQW5w==} resolution: {integrity: sha512-5VSX/3DabBikOXMsxzlW8JyfeLKlG9mzqnWgLQLty88vdZL7ZJgrdgBOmrArwxiLtmS+lNNpPcBYqrhE6TQW5w==}
peerDependencies: peerDependencies:
typescript: '*' typescript: '*'
@ -20386,7 +20317,7 @@ packages:
'@vue/runtime-dom': 3.3.8 '@vue/runtime-dom': 3.3.8
'@vue/server-renderer': 3.3.8(vue@3.3.8) '@vue/server-renderer': 3.3.8(vue@3.3.8)
'@vue/shared': 3.3.8 '@vue/shared': 3.3.8
typescript: 5.2.2 typescript: 5.3.2
/vuedraggable@4.1.0(vue@3.3.8): /vuedraggable@4.1.0(vue@3.3.8):
resolution: {integrity: sha512-FU5HCWBmsf20GpP3eudURW3WdWTKIbEIQxh9/8GE806hydR9qZqRRxRE3RjqX7PkuLuMQG/A7n3cfj9rCEchww==} resolution: {integrity: sha512-FU5HCWBmsf20GpP3eudURW3WdWTKIbEIQxh9/8GE806hydR9qZqRRxRE3RjqX7PkuLuMQG/A7n3cfj9rCEchww==}
@ -20394,7 +20325,7 @@ packages:
vue: ^3.0.1 vue: ^3.0.1
dependencies: dependencies:
sortablejs: 1.14.0 sortablejs: 1.14.0
vue: 3.3.8(typescript@5.2.2) vue: 3.3.8(typescript@5.3.2)
dev: false dev: false
/w3c-xmlserializer@4.0.0: /w3c-xmlserializer@4.0.0:
@ -20884,7 +20815,7 @@ packages:
sharp: 0.31.3 sharp: 0.31.3
dev: false dev: false
github.com/misskey-dev/storybook-addon-misskey-theme/cf583db098365b2ccc81a82f63ca9c93bc32b640(@storybook/blocks@7.5.3)(@storybook/components@7.5.2)(@storybook/core-events@7.5.3)(@storybook/manager-api@7.5.3)(@storybook/preview-api@7.5.3)(@storybook/theming@7.5.3)(@storybook/types@7.5.3)(react-dom@18.2.0)(react@18.2.0): github.com/misskey-dev/storybook-addon-misskey-theme/cf583db098365b2ccc81a82f63ca9c93bc32b640(@storybook/blocks@7.5.3)(@storybook/components@7.5.3)(@storybook/core-events@7.5.3)(@storybook/manager-api@7.5.3)(@storybook/preview-api@7.5.3)(@storybook/theming@7.5.3)(@storybook/types@7.5.3)(react-dom@18.2.0)(react@18.2.0):
resolution: {tarball: https://codeload.github.com/misskey-dev/storybook-addon-misskey-theme/tar.gz/cf583db098365b2ccc81a82f63ca9c93bc32b640} resolution: {tarball: https://codeload.github.com/misskey-dev/storybook-addon-misskey-theme/tar.gz/cf583db098365b2ccc81a82f63ca9c93bc32b640}
id: github.com/misskey-dev/storybook-addon-misskey-theme/cf583db098365b2ccc81a82f63ca9c93bc32b640 id: github.com/misskey-dev/storybook-addon-misskey-theme/cf583db098365b2ccc81a82f63ca9c93bc32b640
name: storybook-addon-misskey-theme name: storybook-addon-misskey-theme
@ -20906,7 +20837,7 @@ packages:
optional: true optional: true
dependencies: dependencies:
'@storybook/blocks': 7.5.3(react-dom@18.2.0)(react@18.2.0) '@storybook/blocks': 7.5.3(react-dom@18.2.0)(react@18.2.0)
'@storybook/components': 7.5.2(react-dom@18.2.0)(react@18.2.0) '@storybook/components': 7.5.3(react-dom@18.2.0)(react@18.2.0)
'@storybook/core-events': 7.5.3 '@storybook/core-events': 7.5.3
'@storybook/manager-api': 7.5.3(react-dom@18.2.0)(react@18.2.0) '@storybook/manager-api': 7.5.3(react-dom@18.2.0)(react@18.2.0)
'@storybook/preview-api': 7.5.3 '@storybook/preview-api': 7.5.3