Merge branch 'misskey-dev:develop' into notes-embed
This commit is contained in:
commit
bb06f64fe2
|
@ -5,7 +5,9 @@ on:
|
||||||
branches:
|
branches:
|
||||||
- master
|
- master
|
||||||
- develop
|
- develop
|
||||||
pull_request_target:
|
pull_request:
|
||||||
|
branches-ignore:
|
||||||
|
- l10n_develop
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
### Client
|
### Client
|
||||||
- 検索ページでURLを入力した際に照会したときと同等の挙動をするように
|
- 検索ページでURLを入力した際に照会したときと同等の挙動をするように
|
||||||
- ノートのリアクションを大きく表示するオプションを追加
|
- ノートのリアクションを大きく表示するオプションを追加
|
||||||
|
- ギャラリー一覧にメディア表示と同じように NSFW 設定を反映するように(ホバーで表示)
|
||||||
- オブジェクトストレージの設定画面を分かりやすく
|
- オブジェクトストレージの設定画面を分かりやすく
|
||||||
- 「にゃああああああああああああああ!!!!!!!!!!!!」 (`isCat`) 有効時にアバターに表示される猫耳について挙動を変更
|
- 「にゃああああああああああああああ!!!!!!!!!!!!」 (`isCat`) 有効時にアバターに表示される猫耳について挙動を変更
|
||||||
- 「UIにぼかし効果を使用」 (`useBlurEffect`) で次の挙動が有効になります
|
- 「UIにぼかし効果を使用」 (`useBlurEffect`) で次の挙動が有効になります
|
||||||
|
|
11
README.md
11
README.md
|
@ -54,6 +54,17 @@ With Misskey's built in drive, you get cloud storage right in your social media,
|
||||||
Misskey Documentation can be found at [Misskey Hub](https://misskey-hub.net/), some of the links and graphics above also lead to specific portions of it.
|
Misskey Documentation can be found at [Misskey Hub](https://misskey-hub.net/), some of the links and graphics above also lead to specific portions of it.
|
||||||
|
|
||||||
## Sponsors
|
## Sponsors
|
||||||
|
|
||||||
<div align="center">
|
<div align="center">
|
||||||
<a class="rss3" title="RSS3" href="https://rss3.io/" target="_blank"><img src="https://rss3.mypinata.cloud/ipfs/QmUG6H3Z7D5P511shn7sB4CPmpjH5uZWu4m5mWX7U3Gqbu" alt="RSS3" height="60"></a>
|
<a class="rss3" title="RSS3" href="https://rss3.io/" target="_blank"><img src="https://rss3.mypinata.cloud/ipfs/QmUG6H3Z7D5P511shn7sB4CPmpjH5uZWu4m5mWX7U3Gqbu" alt="RSS3" height="60"></a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
## Thanks
|
||||||
|
|
||||||
|
<a href="https://www.chromatic.com/"><img src="https://user-images.githubusercontent.com/321738/84662277-e3db4f80-af1b-11ea-88f5-91d67a5e59f6.png" width="153" height="30" alt="Chromatic" /></a>
|
||||||
|
|
||||||
|
Thanks to [Chromatic](https://www.chromatic.com/) for providing the visual testing platform that helps us review UI changes and catch visual regressions.
|
||||||
|
|
||||||
|
<a href="https://hub.docker.com/"><img src="https://user-images.githubusercontent.com/20679825/230148221-f8e73a32-a49b-47c3-9029-9a15c3824f92.png" width="117" height="30" alt="Docker" /></a>
|
||||||
|
|
||||||
|
Thanks to [Docker](https://hub.docker.com/) for providing the container platform that helps us run Misskey in production.
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "misskey",
|
"name": "misskey",
|
||||||
"version": "13.10.3",
|
"version": "13.11.0.beta-1",
|
||||||
"codename": "nasubi",
|
"codename": "nasubi",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
|
|
|
@ -43,6 +43,7 @@ export class NotificationService implements OnApplicationShutdown {
|
||||||
@bindThis
|
@bindThis
|
||||||
public async readAllNotification(
|
public async readAllNotification(
|
||||||
userId: User['id'],
|
userId: User['id'],
|
||||||
|
force = false,
|
||||||
) {
|
) {
|
||||||
const latestReadNotificationId = await this.redisClient.get(`latestReadNotification:${userId}`);
|
const latestReadNotificationId = await this.redisClient.get(`latestReadNotification:${userId}`);
|
||||||
|
|
||||||
|
@ -57,7 +58,7 @@ export class NotificationService implements OnApplicationShutdown {
|
||||||
|
|
||||||
this.redisClient.set(`latestReadNotification:${userId}`, latestNotificationId);
|
this.redisClient.set(`latestReadNotification:${userId}`, latestNotificationId);
|
||||||
|
|
||||||
if (latestReadNotificationId == null || (latestReadNotificationId < latestNotificationId)) {
|
if (force || latestReadNotificationId == null || (latestReadNotificationId < latestNotificationId)) {
|
||||||
return this.postReadAllNotifications(userId);
|
return this.postReadAllNotifications(userId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -95,7 +96,7 @@ export class NotificationService implements OnApplicationShutdown {
|
||||||
...data,
|
...data,
|
||||||
} as Notification;
|
} as Notification;
|
||||||
|
|
||||||
this.redisClient.xadd(
|
const redisIdPromise = this.redisClient.xadd(
|
||||||
`notificationTimeline:${notifieeId}`,
|
`notificationTimeline:${notifieeId}`,
|
||||||
'MAXLEN', '~', '300',
|
'MAXLEN', '~', '300',
|
||||||
`${this.idService.parse(notification.id).date.getTime()}-*`,
|
`${this.idService.parse(notification.id).date.getTime()}-*`,
|
||||||
|
@ -109,7 +110,7 @@ export class NotificationService implements OnApplicationShutdown {
|
||||||
// 2秒経っても(今回作成した)通知が既読にならなかったら「未読の通知がありますよ」イベントを発行する
|
// 2秒経っても(今回作成した)通知が既読にならなかったら「未読の通知がありますよ」イベントを発行する
|
||||||
setTimeout(2000, 'unread notification', { signal: this.#shutdownController.signal }).then(async () => {
|
setTimeout(2000, 'unread notification', { signal: this.#shutdownController.signal }).then(async () => {
|
||||||
const latestReadNotificationId = await this.redisClient.get(`latestReadNotification:${notifieeId}`);
|
const latestReadNotificationId = await this.redisClient.get(`latestReadNotification:${notifieeId}`);
|
||||||
if (latestReadNotificationId && (latestReadNotificationId >= notification.id)) return;
|
if (latestReadNotificationId && (latestReadNotificationId >= await redisIdPromise)) return;
|
||||||
|
|
||||||
this.globalEventService.publishMainStream(notifieeId, 'unreadNotification', packed);
|
this.globalEventService.publishMainStream(notifieeId, 'unreadNotification', packed);
|
||||||
this.pushNotificationService.pushNotification(notifieeId, 'notification', packed);
|
this.pushNotificationService.pushNotification(notifieeId, 'notification', packed);
|
||||||
|
|
|
@ -86,6 +86,10 @@ export class ImportCustomEmojisProcessorService {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const emojiInfo = record.emoji;
|
const emojiInfo = record.emoji;
|
||||||
|
if (!/^[a-zA-Z0-9_]+$/.test(emojiInfo.name)) {
|
||||||
|
this.logger.error(`invalid emojiname: ${emojiInfo.name}`);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
const emojiPath = outputPath + '/' + record.fileName;
|
const emojiPath = outputPath + '/' + record.fileName;
|
||||||
await this.emojisRepository.delete({
|
await this.emojisRepository.delete({
|
||||||
name: emojiInfo.name,
|
name: emojiInfo.name,
|
||||||
|
|
|
@ -24,7 +24,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
|
||||||
private notificationService: NotificationService,
|
private notificationService: NotificationService,
|
||||||
) {
|
) {
|
||||||
super(meta, paramDef, async (ps, me) => {
|
super(meta, paramDef, async (ps, me) => {
|
||||||
this.notificationService.readAllNotification(me.id);
|
this.notificationService.readAllNotification(me.id, true);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,54 +1,116 @@
|
||||||
import type { entities } from 'misskey-js'
|
import type { entities } from 'misskey-js'
|
||||||
|
|
||||||
export const userDetailed = {
|
export function abuseUserReport() {
|
||||||
id: 'someuserid',
|
return {
|
||||||
username: 'miskist',
|
id: 'someabusereportid',
|
||||||
host: 'misskey-hub.net',
|
createdAt: '2016-12-28T22:49:51.000Z',
|
||||||
name: 'Misskey User',
|
comment: 'This user is a spammer!',
|
||||||
onlineStatus: 'unknown',
|
resolved: false,
|
||||||
avatarUrl: 'https://github.com/misskey-dev/misskey/blob/master/packages/frontend/assets/about-icon.png?raw=true',
|
reporterId: 'reporterid',
|
||||||
avatarBlurhash: 'eQFRshof5NWBRi},juayfPju53WB?0ofs;s*a{ofjuay^SoMEJR%ay',
|
targetUserId: 'targetuserid',
|
||||||
emojis: [],
|
assigneeId: 'assigneeid',
|
||||||
bannerBlurhash: 'eQA^IW^-MH8w9tE8I=S^o{$*R4RikXtSxutRozjEnNR.RQadoyozog',
|
reporter: userDetailed('reporterid', 'reporter', 'misskey-hub.net', 'Reporter'),
|
||||||
bannerColor: '#000000',
|
targetUser: userDetailed('targetuserid', 'target', 'misskey-hub.net', 'Target'),
|
||||||
bannerUrl: 'https://github.com/misskey-dev/misskey/blob/master/packages/frontend/assets/fedi.jpg?raw=true',
|
assignee: userDetailed('assigneeid', 'assignee', 'misskey-hub.net', 'Assignee'),
|
||||||
birthday: '2014-06-20',
|
me: null,
|
||||||
createdAt: '2016-12-28T22:49:51.000Z',
|
forwarded: false,
|
||||||
description: 'I am a cool user!',
|
};
|
||||||
ffVisibility: 'public',
|
}
|
||||||
fields: [
|
|
||||||
{
|
export function galleryPost(isSensitive = false) {
|
||||||
name: 'Website',
|
return {
|
||||||
value: 'https://misskey-hub.net',
|
id: 'somepostid',
|
||||||
|
createdAt: '2016-12-28T22:49:51.000Z',
|
||||||
|
updatedAt: '2016-12-28T22:49:51.000Z',
|
||||||
|
userid: 'someuserid',
|
||||||
|
user: userDetailed(),
|
||||||
|
title: 'Some post title',
|
||||||
|
description: 'Some post description',
|
||||||
|
fileIds: ['somefileid'],
|
||||||
|
files: [
|
||||||
|
file(isSensitive),
|
||||||
|
],
|
||||||
|
isSensitive,
|
||||||
|
likedCount: 0,
|
||||||
|
isLiked: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function file(isSensitive = false) {
|
||||||
|
return {
|
||||||
|
id: 'somefileid',
|
||||||
|
createdAt: '2016-12-28T22:49:51.000Z',
|
||||||
|
name: 'somefile.jpg',
|
||||||
|
type: 'image/jpeg',
|
||||||
|
md5: 'f6fc51c73dc21b1fb85ead2cdf57530a',
|
||||||
|
size: 77752,
|
||||||
|
isSensitive,
|
||||||
|
blurhash: 'eQAmoa^-MH8w9ZIvNLSvo^$*MwRPbwtSxutRozjEiwR.RjWBoeozog',
|
||||||
|
properties: {
|
||||||
|
width: 1024,
|
||||||
|
height: 270
|
||||||
},
|
},
|
||||||
],
|
url: 'https://github.com/misskey-dev/misskey/blob/master/packages/frontend/assets/fedi.jpg?raw=true',
|
||||||
followersCount: 1024,
|
thumbnailUrl: 'https://github.com/misskey-dev/misskey/blob/master/packages/frontend/assets/fedi.jpg?raw=true',
|
||||||
followingCount: 16,
|
comment: null,
|
||||||
hasPendingFollowRequestFromYou: false,
|
folderId: null,
|
||||||
hasPendingFollowRequestToYou: false,
|
folder: null,
|
||||||
isAdmin: false,
|
userId: null,
|
||||||
isBlocked: false,
|
user: null,
|
||||||
isBlocking: false,
|
};
|
||||||
isBot: false,
|
}
|
||||||
isCat: false,
|
|
||||||
isFollowed: false,
|
export function userDetailed(id = 'someuserid', username = 'miskist', host = 'misskey-hub.net', name = 'Misskey User'): entities.UserDetailed {
|
||||||
isFollowing: false,
|
return {
|
||||||
isLocked: false,
|
id,
|
||||||
isModerator: false,
|
username,
|
||||||
isMuted: false,
|
host,
|
||||||
isSilenced: false,
|
name,
|
||||||
isSuspended: false,
|
onlineStatus: 'unknown',
|
||||||
lang: 'en',
|
avatarUrl: 'https://github.com/misskey-dev/misskey/blob/master/packages/frontend/assets/about-icon.png?raw=true',
|
||||||
location: 'Fediverse',
|
avatarBlurhash: 'eQFRshof5NWBRi},juayfPju53WB?0ofs;s*a{ofjuay^SoMEJR%ay',
|
||||||
notesCount: 65536,
|
emojis: [],
|
||||||
pinnedNoteIds: [],
|
bannerBlurhash: 'eQA^IW^-MH8w9tE8I=S^o{$*R4RikXtSxutRozjEnNR.RQadoyozog',
|
||||||
pinnedNotes: [],
|
bannerColor: '#000000',
|
||||||
pinnedPage: null,
|
bannerUrl: 'https://github.com/misskey-dev/misskey/blob/master/packages/frontend/assets/fedi.jpg?raw=true',
|
||||||
pinnedPageId: null,
|
birthday: '2014-06-20',
|
||||||
publicReactions: false,
|
createdAt: '2016-12-28T22:49:51.000Z',
|
||||||
securityKeys: false,
|
description: 'I am a cool user!',
|
||||||
twoFactorEnabled: false,
|
ffVisibility: 'public',
|
||||||
updatedAt: null,
|
fields: [
|
||||||
uri: null,
|
{
|
||||||
url: null,
|
name: 'Website',
|
||||||
} satisfies entities.UserDetailed
|
value: 'https://misskey-hub.net',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
followersCount: 1024,
|
||||||
|
followingCount: 16,
|
||||||
|
hasPendingFollowRequestFromYou: false,
|
||||||
|
hasPendingFollowRequestToYou: false,
|
||||||
|
isAdmin: false,
|
||||||
|
isBlocked: false,
|
||||||
|
isBlocking: false,
|
||||||
|
isBot: false,
|
||||||
|
isCat: false,
|
||||||
|
isFollowed: false,
|
||||||
|
isFollowing: false,
|
||||||
|
isLocked: false,
|
||||||
|
isModerator: false,
|
||||||
|
isMuted: false,
|
||||||
|
isSilenced: false,
|
||||||
|
isSuspended: false,
|
||||||
|
lang: 'en',
|
||||||
|
location: 'Fediverse',
|
||||||
|
notesCount: 65536,
|
||||||
|
pinnedNoteIds: [],
|
||||||
|
pinnedNotes: [],
|
||||||
|
pinnedPage: null,
|
||||||
|
pinnedPageId: null,
|
||||||
|
publicReactions: false,
|
||||||
|
securityKeys: false,
|
||||||
|
twoFactorEnabled: false,
|
||||||
|
updatedAt: null,
|
||||||
|
uri: null,
|
||||||
|
url: null,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
|
@ -394,13 +394,13 @@ function toStories(component: string): string {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// glob('src/{components,pages,ui,widgets}/**/*.vue').then(
|
// glob('src/{components,pages,ui,widgets}/**/*.vue')
|
||||||
glob('src/components/global/**/*.vue').then(
|
Promise.all([
|
||||||
(components) =>
|
glob('src/components/global/*.vue'),
|
||||||
Promise.all(
|
glob('src/components/MkGalleryPostPreview.vue'),
|
||||||
components.map((component) => {
|
])
|
||||||
const stories = component.replace(/\.vue$/, '.stories.ts');
|
.then((globs) => globs.flat())
|
||||||
return writeFile(stories, toStories(component));
|
.then((components) => Promise.all(components.map((component) => {
|
||||||
})
|
const stories = component.replace(/\.vue$/, '.stories.ts');
|
||||||
)
|
return writeFile(stories, toStories(component));
|
||||||
);
|
})));
|
||||||
|
|
|
@ -0,0 +1,85 @@
|
||||||
|
/* eslint-disable @typescript-eslint/explicit-function-return-type */
|
||||||
|
import { expect } from '@storybook/jest';
|
||||||
|
import { userEvent, waitFor, within } from '@storybook/testing-library';
|
||||||
|
import { StoryObj } from '@storybook/vue3';
|
||||||
|
import { galleryPost } from '../../.storybook/fakes';
|
||||||
|
import MkGalleryPostPreview from './MkGalleryPostPreview.vue';
|
||||||
|
export const Default = {
|
||||||
|
render(args) {
|
||||||
|
return {
|
||||||
|
components: {
|
||||||
|
MkGalleryPostPreview,
|
||||||
|
},
|
||||||
|
setup() {
|
||||||
|
return {
|
||||||
|
args,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
props() {
|
||||||
|
return {
|
||||||
|
...this.args,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
},
|
||||||
|
template: '<MkGalleryPostPreview v-bind="props" />',
|
||||||
|
};
|
||||||
|
},
|
||||||
|
async play({ canvasElement }) {
|
||||||
|
const canvas = within(canvasElement);
|
||||||
|
const links = canvas.getAllByRole('link');
|
||||||
|
await expect(links).toHaveLength(2);
|
||||||
|
await expect(links[0]).toHaveAttribute('href', `/gallery/${galleryPost().id}`);
|
||||||
|
await expect(links[1]).toHaveAttribute('href', `/@${galleryPost().user.username}@${galleryPost().user.host}`);
|
||||||
|
},
|
||||||
|
args: {
|
||||||
|
post: galleryPost(),
|
||||||
|
},
|
||||||
|
decorators: [
|
||||||
|
() => ({
|
||||||
|
template: '<div style="width:260px"><story /></div>',
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
parameters: {
|
||||||
|
layout: 'centered',
|
||||||
|
},
|
||||||
|
} satisfies StoryObj<typeof MkGalleryPostPreview>;
|
||||||
|
export const Hover = {
|
||||||
|
...Default,
|
||||||
|
async play(context) {
|
||||||
|
await Default.play(context);
|
||||||
|
const canvas = within(context.canvasElement);
|
||||||
|
const links = canvas.getAllByRole('link');
|
||||||
|
await waitFor(() => userEvent.hover(links[0]));
|
||||||
|
},
|
||||||
|
} satisfies StoryObj<typeof MkGalleryPostPreview>;
|
||||||
|
export const HoverThenUnhover = {
|
||||||
|
...Default,
|
||||||
|
async play(context) {
|
||||||
|
await Hover.play(context);
|
||||||
|
const canvas = within(context.canvasElement);
|
||||||
|
const links = canvas.getAllByRole('link');
|
||||||
|
await waitFor(() => userEvent.unhover(links[0]));
|
||||||
|
},
|
||||||
|
} satisfies StoryObj<typeof MkGalleryPostPreview>;
|
||||||
|
export const Sensitive = {
|
||||||
|
...Default,
|
||||||
|
args: {
|
||||||
|
...Default.args,
|
||||||
|
post: galleryPost(true),
|
||||||
|
},
|
||||||
|
} satisfies StoryObj<typeof MkGalleryPostPreview>;
|
||||||
|
export const SensitiveHover = {
|
||||||
|
...Hover,
|
||||||
|
args: {
|
||||||
|
...Hover.args,
|
||||||
|
post: galleryPost(true),
|
||||||
|
},
|
||||||
|
} satisfies StoryObj<typeof MkGalleryPostPreview>;
|
||||||
|
export const SensitiveHoverThenUnhover = {
|
||||||
|
...HoverThenUnhover,
|
||||||
|
args: {
|
||||||
|
...HoverThenUnhover.args,
|
||||||
|
post: galleryPost(true),
|
||||||
|
},
|
||||||
|
} satisfies StoryObj<typeof MkGalleryPostPreview>;
|
|
@ -1,7 +1,10 @@
|
||||||
<template>
|
<template>
|
||||||
<MkA :to="`/gallery/${post.id}`" class="ttasepnz _panel" tabindex="-1">
|
<MkA :to="`/gallery/${post.id}`" class="ttasepnz _panel" tabindex="-1" @pointerenter="enterHover" @pointerleave="leaveHover">
|
||||||
<div class="thumbnail">
|
<div class="thumbnail">
|
||||||
<ImgWithBlurhash class="img" :src="post.files[0].thumbnailUrl" :hash="post.files[0].blurhash"/>
|
<ImgWithBlurhash class="img" :hash="post.files[0].blurhash"/>
|
||||||
|
<Transition>
|
||||||
|
<ImgWithBlurhash v-if="show" class="img layered" :src="post.files[0].thumbnailUrl" :hash="post.files[0].blurhash"/>
|
||||||
|
</Transition>
|
||||||
</div>
|
</div>
|
||||||
<article>
|
<article>
|
||||||
<header>
|
<header>
|
||||||
|
@ -15,12 +18,25 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { } from 'vue';
|
import * as misskey from 'misskey-js';
|
||||||
|
import { computed, ref } from 'vue';
|
||||||
import ImgWithBlurhash from '@/components/MkImgWithBlurhash.vue';
|
import ImgWithBlurhash from '@/components/MkImgWithBlurhash.vue';
|
||||||
|
import { defaultStore } from '@/store';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
post: any;
|
post: misskey.entities.GalleryPost;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
|
const hover = ref(false);
|
||||||
|
const show = computed(() => defaultStore.state.nsfw === 'ignore' || defaultStore.state.nsfw === 'respect' && !props.post.isSensitive || hover.value);
|
||||||
|
|
||||||
|
function enterHover(): void {
|
||||||
|
hover.value = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function leaveHover(): void {
|
||||||
|
hover.value = false;
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
@ -56,6 +72,21 @@ const props = defineProps<{
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
object-fit: cover;
|
object-fit: cover;
|
||||||
|
|
||||||
|
&.layered {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
|
||||||
|
&.v-enter-active,
|
||||||
|
&.v-leave-active {
|
||||||
|
transition: opacity 0.5s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.v-enter-from,
|
||||||
|
&.v-leave-to {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -964,7 +964,7 @@ defineExpose({
|
||||||
padding: 0 12px;
|
padding: 0 12px;
|
||||||
line-height: 34px;
|
line-height: 34px;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
border-radius: 4px;
|
border-radius: 6px;
|
||||||
min-width: 90px;
|
min-width: 90px;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
color: var(--fgOnAccent);
|
color: var(--fgOnAccent);
|
||||||
|
|
|
@ -25,7 +25,7 @@ export const Default = {
|
||||||
},
|
},
|
||||||
args: {
|
args: {
|
||||||
user: {
|
user: {
|
||||||
...userDetailed,
|
...userDetailed(),
|
||||||
host: null,
|
host: null,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -37,7 +37,7 @@ export const Detail = {
|
||||||
...Default,
|
...Default,
|
||||||
args: {
|
args: {
|
||||||
...Default.args,
|
...Default.args,
|
||||||
user: userDetailed,
|
user: userDetailed(),
|
||||||
detail: true,
|
detail: true,
|
||||||
},
|
},
|
||||||
} satisfies StoryObj<typeof MkAcct>;
|
} satisfies StoryObj<typeof MkAcct>;
|
||||||
|
|
|
@ -24,7 +24,7 @@ const common = {
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
args: {
|
args: {
|
||||||
user: userDetailed,
|
user: userDetailed(),
|
||||||
},
|
},
|
||||||
decorators: [
|
decorators: [
|
||||||
(Story, context) => ({
|
(Story, context) => ({
|
||||||
|
@ -49,7 +49,7 @@ export const ProfilePageCat = {
|
||||||
args: {
|
args: {
|
||||||
...ProfilePage.args,
|
...ProfilePage.args,
|
||||||
user: {
|
user: {
|
||||||
...userDetailed,
|
...userDetailed(),
|
||||||
isCat: true,
|
isCat: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
/* eslint-disable @typescript-eslint/explicit-function-return-type */
|
||||||
|
import { expect } from '@storybook/jest';
|
||||||
|
import { waitFor } from '@storybook/testing-library';
|
||||||
|
import { StoryObj } from '@storybook/vue3';
|
||||||
|
import MkError from './MkError.vue';
|
||||||
|
export const Default = {
|
||||||
|
render(args) {
|
||||||
|
return {
|
||||||
|
components: {
|
||||||
|
MkError,
|
||||||
|
},
|
||||||
|
setup() {
|
||||||
|
return {
|
||||||
|
args,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
props() {
|
||||||
|
return {
|
||||||
|
...this.args,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
},
|
||||||
|
template: '<MkError v-bind="props" />',
|
||||||
|
};
|
||||||
|
},
|
||||||
|
async play({ canvasElement }) {
|
||||||
|
await expect(canvasElement.firstElementChild).not.toBeNull();
|
||||||
|
await waitFor(async () => expect(canvasElement.firstElementChild?.classList).not.toContain('_transition_zoom-enter-active'));
|
||||||
|
},
|
||||||
|
parameters: {
|
||||||
|
layout: 'centered',
|
||||||
|
},
|
||||||
|
} satisfies StoryObj<typeof MkError>;
|
|
@ -1,6 +1,6 @@
|
||||||
/* eslint-disable @typescript-eslint/explicit-function-return-type */
|
/* eslint-disable @typescript-eslint/explicit-function-return-type */
|
||||||
import { expect } from '@storybook/jest';
|
import { expect } from '@storybook/jest';
|
||||||
import { userEvent, within } from '@storybook/testing-library';
|
import { userEvent, waitFor, within } from '@storybook/testing-library';
|
||||||
import { StoryObj } from '@storybook/vue3';
|
import { StoryObj } from '@storybook/vue3';
|
||||||
import { rest } from 'msw';
|
import { rest } from 'msw';
|
||||||
import { commonHandlers } from '../../../.storybook/mocks';
|
import { commonHandlers } from '../../../.storybook/mocks';
|
||||||
|
@ -30,7 +30,7 @@ export const Default = {
|
||||||
const canvas = within(canvasElement);
|
const canvas = within(canvasElement);
|
||||||
const a = canvas.getByRole<HTMLAnchorElement>('link');
|
const a = canvas.getByRole<HTMLAnchorElement>('link');
|
||||||
await expect(a).toHaveAttribute('href', 'https://misskey-hub.net/');
|
await expect(a).toHaveAttribute('href', 'https://misskey-hub.net/');
|
||||||
await userEvent.hover(a);
|
await waitFor(() => userEvent.hover(a));
|
||||||
/*
|
/*
|
||||||
await tick(); // FIXME: wait for network request
|
await tick(); // FIXME: wait for network request
|
||||||
const anchors = canvas.getAllByRole<HTMLAnchorElement>('link');
|
const anchors = canvas.getAllByRole<HTMLAnchorElement>('link');
|
||||||
|
@ -44,7 +44,7 @@ export const Default = {
|
||||||
await expect(icon).toBeInTheDocument();
|
await expect(icon).toBeInTheDocument();
|
||||||
await expect(icon).toHaveAttribute('src', 'https://misskey-hub.net/favicon.ico');
|
await expect(icon).toHaveAttribute('src', 'https://misskey-hub.net/favicon.ico');
|
||||||
*/
|
*/
|
||||||
await userEvent.unhover(a);
|
await waitFor(() => userEvent.unhover(a));
|
||||||
},
|
},
|
||||||
args: {
|
args: {
|
||||||
url: 'https://misskey-hub.net/',
|
url: 'https://misskey-hub.net/',
|
||||||
|
|
|
@ -26,10 +26,10 @@ export const Default = {
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
async play({ canvasElement }) {
|
async play({ canvasElement }) {
|
||||||
await expect(canvasElement).toHaveTextContent(userDetailed.name);
|
await expect(canvasElement).toHaveTextContent(userDetailed().name);
|
||||||
},
|
},
|
||||||
args: {
|
args: {
|
||||||
user: userDetailed,
|
user: userDetailed(),
|
||||||
},
|
},
|
||||||
parameters: {
|
parameters: {
|
||||||
layout: 'centered',
|
layout: 'centered',
|
||||||
|
@ -38,12 +38,12 @@ export const Default = {
|
||||||
export const Anonymous = {
|
export const Anonymous = {
|
||||||
...Default,
|
...Default,
|
||||||
async play({ canvasElement }) {
|
async play({ canvasElement }) {
|
||||||
await expect(canvasElement).toHaveTextContent(userDetailed.username);
|
await expect(canvasElement).toHaveTextContent(userDetailed().username);
|
||||||
},
|
},
|
||||||
args: {
|
args: {
|
||||||
...Default.args,
|
...Default.args,
|
||||||
user: {
|
user: {
|
||||||
...userDetailed,
|
...userDetailed(),
|
||||||
name: null,
|
name: null,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -31,7 +31,7 @@
|
||||||
<button v-click-anime class="item _button account" @click="openAccountMenu">
|
<button v-click-anime 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="post">
|
<div class="post" @click="os.post()">
|
||||||
<MkButton class="button" gradate full rounded>
|
<MkButton class="button" gradate full rounded>
|
||||||
<i class="ti ti-pencil ti-fw"></i>
|
<i class="ti ti-pencil ti-fw"></i>
|
||||||
</MkButton>
|
</MkButton>
|
||||||
|
@ -41,93 +41,50 @@
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts" setup>
|
||||||
import { defineAsyncComponent, defineComponent } from 'vue';
|
import { computed, defineAsyncComponent, onMounted } from 'vue';
|
||||||
import { openInstanceMenu } from './_common_/common';
|
import { openInstanceMenu } from './_common_/common';
|
||||||
import { host } from '@/config';
|
|
||||||
import * as os from '@/os';
|
import * as os from '@/os';
|
||||||
import { navbarItemDef } from '@/navbar';
|
import { navbarItemDef } from '@/navbar';
|
||||||
import { openAccountMenu, $i } from '@/account';
|
import { openAccountMenu as openAccountMenu_, $i } from '@/account';
|
||||||
import MkButton from '@/components/MkButton.vue';
|
import MkButton from '@/components/MkButton.vue';
|
||||||
import { mainRouter } from '@/router';
|
|
||||||
import { defaultStore } from '@/store';
|
import { defaultStore } from '@/store';
|
||||||
import { instance } from '@/instance';
|
import { instance } from '@/instance';
|
||||||
import { i18n } from '@/i18n';
|
import { i18n } from '@/i18n';
|
||||||
|
|
||||||
export default defineComponent({
|
const WINDOW_THRESHOLD = 1400;
|
||||||
components: {
|
|
||||||
MkButton,
|
|
||||||
},
|
|
||||||
|
|
||||||
data() {
|
let settingsWindowed = $ref(window.innerWidth > WINDOW_THRESHOLD);
|
||||||
return {
|
let menu = $ref(defaultStore.state.menu);
|
||||||
host: host,
|
// const menuDisplay = computed(defaultStore.makeGetterSetter('menuDisplay'));
|
||||||
accounts: [],
|
let otherNavItemIndicated = computed<boolean>(() => {
|
||||||
connection: null,
|
for (const def in navbarItemDef) {
|
||||||
navbarItemDef: navbarItemDef,
|
if (menu.includes(def)) continue;
|
||||||
settingsWindowed: false,
|
if (navbarItemDef[def].indicated) return true;
|
||||||
defaultStore,
|
}
|
||||||
instance,
|
return false;
|
||||||
$i,
|
|
||||||
i18n,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
computed: {
|
|
||||||
menu(): string[] {
|
|
||||||
return defaultStore.state.menu;
|
|
||||||
},
|
|
||||||
|
|
||||||
otherNavItemIndicated(): boolean {
|
|
||||||
for (const def in this.navbarItemDef) {
|
|
||||||
if (this.menu.includes(def)) continue;
|
|
||||||
if (this.navbarItemDef[def].indicated) return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
watch: {
|
|
||||||
'defaultStore.reactiveState.menuDisplay.value'() {
|
|
||||||
this.calcViewState();
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
created() {
|
|
||||||
window.addEventListener('resize', this.calcViewState);
|
|
||||||
this.calcViewState();
|
|
||||||
},
|
|
||||||
|
|
||||||
methods: {
|
|
||||||
openInstanceMenu,
|
|
||||||
|
|
||||||
calcViewState() {
|
|
||||||
this.settingsWindowed = (window.innerWidth > 1400);
|
|
||||||
},
|
|
||||||
|
|
||||||
post() {
|
|
||||||
os.post();
|
|
||||||
},
|
|
||||||
|
|
||||||
search() {
|
|
||||||
mainRouter.push('/search');
|
|
||||||
},
|
|
||||||
|
|
||||||
more(ev) {
|
|
||||||
os.popup(defineAsyncComponent(() => import('@/components/MkLaunchPad.vue')), {
|
|
||||||
src: ev.currentTarget ?? ev.target,
|
|
||||||
anchor: { x: 'center', y: 'bottom' },
|
|
||||||
}, {
|
|
||||||
}, 'closed');
|
|
||||||
},
|
|
||||||
|
|
||||||
openAccountMenu: (ev) => {
|
|
||||||
openAccountMenu({
|
|
||||||
withExtraOperation: true,
|
|
||||||
}, ev);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function more(ev: MouseEvent) {
|
||||||
|
os.popup(defineAsyncComponent(() => import('@/components/MkLaunchPad.vue')), {
|
||||||
|
src: ev.currentTarget ?? ev.target,
|
||||||
|
anchor: { x: 'center', y: 'bottom' },
|
||||||
|
}, {
|
||||||
|
}, 'closed');
|
||||||
|
}
|
||||||
|
|
||||||
|
function openAccountMenu(ev: MouseEvent) {
|
||||||
|
openAccountMenu_({
|
||||||
|
withExtraOperation: true,
|
||||||
|
}, ev);
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
window.addEventListener('resize', () => {
|
||||||
|
settingsWindowed = (window.innerWidth >= WINDOW_THRESHOLD);
|
||||||
|
}, { passive: true });
|
||||||
|
});
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
<button v-click-anime class="item _button account" @click="openAccountMenu">
|
<button v-click-anime 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="post">
|
<div class="post" data-cy-open-post-form @click="os.post">
|
||||||
<MkButton class="button" gradate full rounded>
|
<MkButton class="button" gradate full rounded>
|
||||||
<i class="ti ti-pencil ti-fw"></i><span v-if="!iconOnly" class="text">{{ i18n.ts.note }}</span>
|
<i class="ti ti-pencil ti-fw"></i><span v-if="!iconOnly" class="text">{{ i18n.ts.note }}</span>
|
||||||
</MkButton>
|
</MkButton>
|
||||||
|
@ -40,109 +40,59 @@
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts" setup>
|
||||||
import { defineAsyncComponent, defineComponent } from 'vue';
|
import { defineAsyncComponent, onMounted, computed, watch, nextTick } from 'vue';
|
||||||
import { openInstanceMenu } from './_common_/common';
|
import { openInstanceMenu } from './_common_/common';
|
||||||
import { host } from '@/config';
|
// import { host } from '@/config';
|
||||||
import * as os from '@/os';
|
import * as os from '@/os';
|
||||||
import { navbarItemDef } from '@/navbar';
|
import { navbarItemDef } from '@/navbar';
|
||||||
import { openAccountMenu, $i } from '@/account';
|
import { openAccountMenu as openAccountMenu_, $i } from '@/account';
|
||||||
import MkButton from '@/components/MkButton.vue';
|
import MkButton from '@/components/MkButton.vue';
|
||||||
import { StickySidebar } from '@/scripts/sticky-sidebar';
|
// import { StickySidebar } from '@/scripts/sticky-sidebar';
|
||||||
import { mainRouter } from '@/router';
|
// import { mainRouter } from '@/router';
|
||||||
//import MisskeyLogo from '@assets/client/misskey.svg';
|
//import MisskeyLogo from '@assets/client/misskey.svg';
|
||||||
import { defaultStore } from '@/store';
|
import { defaultStore } from '@/store';
|
||||||
import { instance } from '@/instance';
|
import { instance } from '@/instance';
|
||||||
import { i18n } from '@/i18n';
|
import { i18n } from '@/i18n';
|
||||||
|
|
||||||
export default defineComponent({
|
const WINDOW_THRESHOLD = 1400;
|
||||||
components: {
|
|
||||||
MkButton,
|
|
||||||
//MisskeyLogo,
|
|
||||||
},
|
|
||||||
|
|
||||||
data() {
|
const menu = $ref(defaultStore.state.menu);
|
||||||
return {
|
const menuDisplay = computed(defaultStore.makeGetterSetter('menuDisplay'));
|
||||||
host: host,
|
const otherNavItemIndicated = computed<boolean>(() => {
|
||||||
accounts: [],
|
for (const def in navbarItemDef) {
|
||||||
connection: null,
|
if (menu.includes(def)) continue;
|
||||||
navbarItemDef: navbarItemDef,
|
if (navbarItemDef[def].indicated) return true;
|
||||||
iconOnly: false,
|
}
|
||||||
settingsWindowed: false,
|
return false;
|
||||||
defaultStore,
|
|
||||||
instance,
|
|
||||||
$i,
|
|
||||||
i18n,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
computed: {
|
|
||||||
menu(): string[] {
|
|
||||||
return this.defaultStore.state.menu;
|
|
||||||
},
|
|
||||||
|
|
||||||
otherNavItemIndicated(): boolean {
|
|
||||||
for (const def in this.navbarItemDef) {
|
|
||||||
if (this.menu.includes(def)) continue;
|
|
||||||
if (this.navbarItemDef[def].indicated) return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
watch: {
|
|
||||||
'defaultStore.reactiveState.menuDisplay.value'() {
|
|
||||||
this.calcViewState();
|
|
||||||
},
|
|
||||||
|
|
||||||
iconOnly() {
|
|
||||||
this.$nextTick(() => {
|
|
||||||
this.$emit('change-view-mode');
|
|
||||||
});
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
created() {
|
|
||||||
window.addEventListener('resize', this.calcViewState);
|
|
||||||
this.calcViewState();
|
|
||||||
},
|
|
||||||
|
|
||||||
mounted() {
|
|
||||||
const sticky = new StickySidebar(this.$el.parentElement, 16);
|
|
||||||
window.addEventListener('scroll', () => {
|
|
||||||
sticky.calc(window.scrollY);
|
|
||||||
}, { passive: true });
|
|
||||||
},
|
|
||||||
|
|
||||||
methods: {
|
|
||||||
openInstanceMenu,
|
|
||||||
|
|
||||||
calcViewState() {
|
|
||||||
this.iconOnly = (window.innerWidth <= 1400) || (this.defaultStore.state.menuDisplay === 'sideIcon');
|
|
||||||
this.settingsWindowed = (window.innerWidth > 1400);
|
|
||||||
},
|
|
||||||
|
|
||||||
post() {
|
|
||||||
os.post();
|
|
||||||
},
|
|
||||||
|
|
||||||
search() {
|
|
||||||
mainRouter.push('/search');
|
|
||||||
},
|
|
||||||
|
|
||||||
more(ev) {
|
|
||||||
os.popup(defineAsyncComponent(() => import('@/components/MkLaunchPad.vue')), {
|
|
||||||
src: ev.currentTarget ?? ev.target,
|
|
||||||
}, {}, 'closed');
|
|
||||||
},
|
|
||||||
|
|
||||||
openAccountMenu: (ev) => {
|
|
||||||
openAccountMenu({
|
|
||||||
withExtraOperation: true,
|
|
||||||
}, ev);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
let el = $shallowRef<HTMLElement>();
|
||||||
|
// let accounts = $ref([]);
|
||||||
|
// let connection = $ref(null);
|
||||||
|
let iconOnly = $ref(false);
|
||||||
|
let settingsWindowed = $ref(false);
|
||||||
|
|
||||||
|
function calcViewState() {
|
||||||
|
iconOnly = (window.innerWidth <= WINDOW_THRESHOLD) || (menuDisplay.value === 'sideIcon');
|
||||||
|
settingsWindowed = (window.innerWidth > WINDOW_THRESHOLD);
|
||||||
|
}
|
||||||
|
|
||||||
|
function more(ev: MouseEvent) {
|
||||||
|
os.popup(defineAsyncComponent(() => import('@/components/MkLaunchPad.vue')), {
|
||||||
|
src: ev.currentTarget ?? ev.target,
|
||||||
|
}, {}, 'closed');
|
||||||
|
}
|
||||||
|
|
||||||
|
function openAccountMenu(ev: MouseEvent) {
|
||||||
|
openAccountMenu_({
|
||||||
|
withExtraOperation: true,
|
||||||
|
}, ev);
|
||||||
|
}
|
||||||
|
|
||||||
|
watch(defaultStore.reactiveState.menuDisplay, () => {
|
||||||
|
calcViewState();
|
||||||
|
});
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
|
|
@ -166,8 +166,6 @@ export type Channels = {
|
||||||
readAllAntennas: () => void;
|
readAllAntennas: () => void;
|
||||||
unreadAntenna: (payload: Antenna) => void;
|
unreadAntenna: (payload: Antenna) => void;
|
||||||
readAllAnnouncements: () => void;
|
readAllAnnouncements: () => void;
|
||||||
readAllChannels: () => void;
|
|
||||||
unreadChannel: (payload: Note['id']) => void;
|
|
||||||
myTokenRegenerated: () => void;
|
myTokenRegenerated: () => void;
|
||||||
reversiNoInvites: () => void;
|
reversiNoInvites: () => void;
|
||||||
reversiInvited: (payload: FIXME) => void;
|
reversiInvited: (payload: FIXME) => void;
|
||||||
|
@ -1857,12 +1855,6 @@ export type Endpoints = {
|
||||||
req: NoParams;
|
req: NoParams;
|
||||||
res: null;
|
res: null;
|
||||||
};
|
};
|
||||||
'notifications/read': {
|
|
||||||
req: {
|
|
||||||
notificationId: Notification_2['id'];
|
|
||||||
};
|
|
||||||
res: null;
|
|
||||||
};
|
|
||||||
'page-push': {
|
'page-push': {
|
||||||
req: {
|
req: {
|
||||||
pageId: Page['id'];
|
pageId: Page['id'];
|
||||||
|
@ -2361,7 +2353,6 @@ type MeDetailed = UserDetailed & {
|
||||||
hasPendingReceivedFollowRequest: boolean;
|
hasPendingReceivedFollowRequest: boolean;
|
||||||
hasUnreadAnnouncement: boolean;
|
hasUnreadAnnouncement: boolean;
|
||||||
hasUnreadAntenna: boolean;
|
hasUnreadAntenna: boolean;
|
||||||
hasUnreadChannel: boolean;
|
|
||||||
hasUnreadMentions: boolean;
|
hasUnreadMentions: boolean;
|
||||||
hasUnreadMessagingMessage: boolean;
|
hasUnreadMessagingMessage: boolean;
|
||||||
hasUnreadNotification: boolean;
|
hasUnreadNotification: boolean;
|
||||||
|
@ -2618,7 +2609,11 @@ export class Stream extends EventEmitter<StreamEvents> {
|
||||||
// (undocumented)
|
// (undocumented)
|
||||||
removeSharedConnectionPool(pool: Pool): void;
|
removeSharedConnectionPool(pool: Pool): void;
|
||||||
// (undocumented)
|
// (undocumented)
|
||||||
send(typeOrPayload: any, payload?: any): void;
|
send(typeOrPayload: string): void;
|
||||||
|
// (undocumented)
|
||||||
|
send(typeOrPayload: string, payload: any): void;
|
||||||
|
// (undocumented)
|
||||||
|
send(typeOrPayload: Record<string, any> | any[]): void;
|
||||||
// (undocumented)
|
// (undocumented)
|
||||||
state: 'initializing' | 'reconnecting' | 'connected';
|
state: 'initializing' | 'reconnecting' | 'connected';
|
||||||
// (undocumented)
|
// (undocumented)
|
||||||
|
@ -2714,8 +2709,8 @@ type UserSorting = '+follower' | '-follower' | '+createdAt' | '-createdAt' | '+u
|
||||||
//
|
//
|
||||||
// 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:18:25 - (ae-forgotten-export) The symbol "NoParams" needs to be exported by the entry point index.d.ts
|
||||||
// src/api.types.ts:595:18 - (ae-forgotten-export) The symbol "ShowUserReq" needs to be exported by the entry point index.d.ts
|
// src/api.types.ts:594:18 - (ae-forgotten-export) The symbol "ShowUserReq" needs to be exported by the entry point index.d.ts
|
||||||
// src/streaming.types.ts:35: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
|
||||||
|
|
||||||
// (No @packageDocumentation comment for this package)
|
// (No @packageDocumentation comment for this package)
|
||||||
|
|
||||||
|
|
|
@ -169,14 +169,21 @@ export default class Stream extends EventEmitter<StreamEvents> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send a message to connection
|
* Send a message to connection
|
||||||
|
* ! ストリーム上のやり取りはすべてJSONで行われます !
|
||||||
*/
|
*/
|
||||||
public send(typeOrPayload: any, payload?: any): void {
|
public send(typeOrPayload: string): void
|
||||||
const data = payload === undefined ? typeOrPayload : {
|
public send(typeOrPayload: string, payload: any): void
|
||||||
type: typeOrPayload,
|
public send(typeOrPayload: Record<string, any> | any[]): void
|
||||||
body: payload,
|
public send(typeOrPayload: string | Record<string, any> | any[], payload?: any): void {
|
||||||
};
|
if (typeof typeOrPayload === 'string') {
|
||||||
|
this.stream.send(JSON.stringify({
|
||||||
|
type: typeOrPayload,
|
||||||
|
...(payload === undefined ? {} : { body: payload }),
|
||||||
|
}));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
this.stream.send(JSON.stringify(data));
|
this.stream.send(JSON.stringify(typeOrPayload));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in New Issue