Merge branch 'develop' into pag-back

This commit is contained in:
tamaina 2023-07-17 07:29:32 +00:00
commit b330ede502
92 changed files with 3176 additions and 1027 deletions

View file

@ -356,9 +356,7 @@ onMounted(() => {
props.textarea.addEventListener('keydown', onKeydown);
for (const el of Array.from(document.querySelectorAll('body *'))) {
el.addEventListener('mousedown', onMousedown);
}
document.body.addEventListener('mousedown', onMousedown);
nextTick(() => {
exec();
@ -374,9 +372,7 @@ onMounted(() => {
onBeforeUnmount(() => {
props.textarea.removeEventListener('keydown', onKeydown);
for (const el of Array.from(document.querySelectorAll('body *'))) {
el.removeEventListener('mousedown', onMousedown);
}
document.body.removeEventListener('mousedown', onMousedown);
});
</script>

View file

@ -61,15 +61,11 @@ onMounted(() => {
rootEl.style.top = `${top}px`;
rootEl.style.left = `${left}px`;
for (const el of Array.from(document.querySelectorAll('body *'))) {
el.addEventListener('mousedown', onMousedown);
}
document.body.addEventListener('mousedown', onMousedown);
});
onBeforeUnmount(() => {
for (const el of Array.from(document.querySelectorAll('body *'))) {
el.removeEventListener('mousedown', onMousedown);
}
document.body.removeEventListener('mousedown', onMousedown);
});
function onMousedown(evt: Event) {

View file

@ -0,0 +1,60 @@
/* eslint-disable @typescript-eslint/explicit-function-return-type */
import { StoryObj } from '@storybook/vue3';
import { rest } from 'msw';
import { userDetailed, inviteCode } from '../../.storybook/fakes';
import { commonHandlers } from '../../.storybook/mocks';
import MkInviteCode from './MkInviteCode.vue';
export const Default = {
render(args) {
return {
components: {
MkInviteCode,
},
setup() {
return {
args,
};
},
computed: {
props() {
return {
...this.args,
};
},
},
template: '<MkInviteCode v-bind="props" />',
};
},
args: {
invite: inviteCode() as any,
},
parameters: {
layout: 'centered',
msw: {
handlers: [
...commonHandlers,
rest.post('/api/users/show', (req, res, ctx) => {
return res(ctx.json(userDetailed(req.params.userId as string)));
}),
],
},
},
decorators: [() => ({
template: '<div style="width:100cqmin"><story/></div>',
})],
} satisfies StoryObj<typeof MkInviteCode>;
export const Used = {
...Default,
args: {
invite: inviteCode(true) as any
},
} satisfies StoryObj<typeof MkInviteCode>;
export const Expired = {
...Default,
args: {
invite: inviteCode(false, true, true) as any
},
} satisfies StoryObj<typeof MkInviteCode>;

View file

@ -0,0 +1,124 @@
<template>
<MkFolder>
<template #label>{{ invite.code }}</template>
<template #suffix>
<span v-if="invite.used">{{ i18n.ts.used }}</span>
<span v-else-if="isExpired" style="color: var(--error)">{{ i18n.ts.expired }}</span>
<span v-else style="color: var(--success)">{{ i18n.ts.unused }}</span>
</template>
<div class="_gaps_s" :class="$style.root">
<div :class="$style.items">
<div>
<div :class="$style.label">{{ i18n.ts.invitationCode }}</div>
<div>{{ invite.code }}</div>
</div>
<div v-if="moderator">
<div :class="$style.label">{{ i18n.ts.inviteCodeCreator }}</div>
<div v-if="invite.createdBy" :class="$style.user">
<MkAvatar :user="invite.createdBy" :class="$style.avatar" link preview/>
<MkUserName :user="invite.createdBy" :nowrap="false"/>
<div v-if="moderator">({{ invite.createdBy.id }})</div>
</div>
<div v-else>system</div>
</div>
<div v-if="invite.used">
<div :class="$style.label">{{ i18n.ts.registeredUserUsingInviteCode }}</div>
<div v-if="invite.usedBy" :class="$style.user">
<MkAvatar :user="invite.usedBy" :class="$style.avatar" link preview/>
<MkUserName :user="invite.usedBy" :nowrap="false"/>
<div v-if="moderator">({{ invite.usedBy.id }})</div>
</div>
<div v-else>{{ i18n.ts.unknown }} ({{ i18n.ts.waitingForMailAuth }})</div>
</div>
<div v-if="invite.expiresAt && !invite.used">
<div :class="$style.label">{{ i18n.ts.expirationDate }}</div>
<div><MkTime :time="invite.expiresAt" mode="absolute"/></div>
</div>
<div v-if="invite.usedAt">
<div :class="$style.label">{{ i18n.ts.inviteCodeUsedAt }}</div>
<div><MkTime :time="invite.usedAt" mode="absolute"/></div>
</div>
<div v-if="moderator">
<div :class="$style.label">{{ i18n.ts.createdAt }}</div>
<div><MkTime :time="invite.createdAt" mode="absolute"/></div>
</div>
</div>
<div :class="$style.buttons">
<MkButton v-if="!invite.used && !isExpired" primary rounded @click="copyInviteCode()"><i class="ti ti-copy"></i> {{ i18n.ts.copy }}</MkButton>
<MkButton v-if="!invite.used || moderator" danger rounded @click="deleteCode()"><i class="ti ti-trash"></i> {{ i18n.ts.delete }}</MkButton>
</div>
</div>
</MkFolder>
</template>
<script lang="ts" setup>
import { computed } from 'vue';
import * as misskey from 'misskey-js';
import MkFolder from '@/components/MkFolder.vue';
import MkButton from '@/components/MkButton.vue';
import copyToClipboard from '@/scripts/copy-to-clipboard';
import { i18n } from '@/i18n';
import * as os from '@/os';
const props = defineProps<{
invite: misskey.entities.Invite;
moderator?: boolean;
}>();
const emits = defineEmits<{
(event: 'deleted', value: string): void;
}>();
const isExpired = computed(() => {
return props.invite.expiresAt && new Date(props.invite.expiresAt) < new Date();
});
function deleteCode() {
os.apiWithDialog('invite/delete', {
inviteId: props.invite.id,
});
emits('deleted', props.invite.id);
}
function copyInviteCode() {
copyToClipboard(props.invite.code);
os.success();
}
</script>
<style lang="scss" module>
.root {
text-align: left;
}
.items {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
grid-gap: 12px;
}
.label {
font-size: 0.85em;
padding: 0 0 8px 0;
user-select: none;
opacity: 0.7;
}
.user {
display: flex;
align-items: center;
gap: 8px;
}
.avatar {
--height: 24px;
width: var(--height);
height: var(--height);
}
.buttons {
display: flex;
gap: 8px;
}
</style>

View file

@ -256,7 +256,7 @@ export default function(props: {
case 'mention': {
return [h(MkMention, {
key: Math.random(),
host: (token.props.host == null && props.author && props.author.host != null ? props.author.host : token.props.host) || host,
host: (token.props.host == null && props.author && props.author.host != null ? props.author.host : token.props.host) ?? host,
username: token.props.username,
})];
}