Merge tag '2023.12.1' into merge-upstream
This commit is contained in:
commit
018ff4cbda
336 changed files with 1938 additions and 1116 deletions
|
@ -7,8 +7,8 @@
|
|||
import { action } from '@storybook/addon-actions';
|
||||
import { StoryObj } from '@storybook/vue3';
|
||||
import { rest } from 'msw';
|
||||
import { abuseUserReport } from '../../.storybook/fakes';
|
||||
import { commonHandlers } from '../../.storybook/mocks';
|
||||
import { abuseUserReport } from '../../.storybook/fakes.js';
|
||||
import { commonHandlers } from '../../.storybook/mocks.js';
|
||||
import MkAbuseReport from './MkAbuseReport.vue';
|
||||
export const Default = {
|
||||
render(args) {
|
||||
|
|
|
@ -7,8 +7,8 @@
|
|||
import { action } from '@storybook/addon-actions';
|
||||
import { StoryObj } from '@storybook/vue3';
|
||||
import { rest } from 'msw';
|
||||
import { userDetailed } from '../../.storybook/fakes';
|
||||
import { commonHandlers } from '../../.storybook/mocks';
|
||||
import { userDetailed } from '../../.storybook/fakes.js';
|
||||
import { commonHandlers } from '../../.storybook/mocks.js';
|
||||
import MkAbuseReportWindow from './MkAbuseReportWindow.vue';
|
||||
export const Default = {
|
||||
render(args) {
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
/* eslint-disable @typescript-eslint/explicit-function-return-type */
|
||||
import { StoryObj } from '@storybook/vue3';
|
||||
import { userDetailed } from '../../.storybook/fakes';
|
||||
import { userDetailed } from '../../.storybook/fakes.js';
|
||||
import MkAccountMoved from './MkAccountMoved.vue';
|
||||
export const Default = {
|
||||
render(args) {
|
||||
|
|
|
@ -6,8 +6,8 @@
|
|||
/* eslint-disable @typescript-eslint/explicit-function-return-type */
|
||||
import { StoryObj } from '@storybook/vue3';
|
||||
import { rest } from 'msw';
|
||||
import { userDetailed } from '../../.storybook/fakes';
|
||||
import { commonHandlers } from '../../.storybook/mocks';
|
||||
import { userDetailed } from '../../.storybook/fakes.js';
|
||||
import { commonHandlers } from '../../.storybook/mocks.js';
|
||||
import MkAchievements from './MkAchievements.vue';
|
||||
import { ACHIEVEMENT_TYPES } from '@/scripts/achievements.js';
|
||||
export const Empty = {
|
||||
|
|
|
@ -67,7 +67,7 @@ const props = withDefaults(defineProps<{
|
|||
withDescription: true,
|
||||
});
|
||||
|
||||
const achievements = ref();
|
||||
const achievements = ref<Misskey.entities.UsersAchievementsResponse | null>(null);
|
||||
const lockedAchievements = computed(() => ACHIEVEMENT_TYPES.filter(x => !(achievements.value ?? []).some(a => a.name === x)));
|
||||
|
||||
function fetch() {
|
||||
|
|
|
@ -11,7 +11,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</template>
|
||||
</div>
|
||||
<span v-else-if="c.type === 'text'" :class="{ [$style.fontSerif]: c.font === 'serif', [$style.fontMonospace]: c.font === 'monospace' }" :style="{ fontSize: c.size ? `${c.size * 100}%` : null, fontWeight: c.bold ? 'bold' : null, color: c.color ?? null }">{{ c.text }}</span>
|
||||
<Mfm v-else-if="c.type === 'mfm'" :class="{ [$style.fontSerif]: c.font === 'serif', [$style.fontMonospace]: c.font === 'monospace' }" :style="{ fontSize: c.size ? `${c.size * 100}%` : null, fontWeight: c.bold ? 'bold' : null, color: c.color ?? null }" :text="c.text"/>
|
||||
<Mfm v-else-if="c.type === 'mfm'" :class="{ [$style.fontSerif]: c.font === 'serif', [$style.fontMonospace]: c.font === 'monospace' }" :style="{ fontSize: c.size ? `${c.size * 100}%` : null, fontWeight: c.bold ? 'bold' : null, color: c.color ?? null }" :text="c.text" @clickEv="c.onClickEv"/>
|
||||
<MkButton v-else-if="c.type === 'button'" :primary="c.primary" :rounded="c.rounded" :disabled="c.disabled" :small="size === 'small'" inline @click="c.onClick">{{ c.text }}</MkButton>
|
||||
<div v-else-if="c.type === 'buttons'" class="_buttons" :style="{ justifyContent: align }">
|
||||
<MkButton v-for="button in c.buttons" :primary="button.primary" :rounded="button.rounded" :disabled="button.disabled" inline :small="size === 'small'" @click="button.onClick">{{ button.text }}</MkButton>
|
||||
|
|
|
@ -9,8 +9,8 @@ import { expect } from '@storybook/jest';
|
|||
import { userEvent, waitFor, within } from '@storybook/testing-library';
|
||||
import { StoryObj } from '@storybook/vue3';
|
||||
import { rest } from 'msw';
|
||||
import { userDetailed } from '../../.storybook/fakes';
|
||||
import { commonHandlers } from '../../.storybook/mocks';
|
||||
import { userDetailed } from '../../.storybook/fakes.js';
|
||||
import { commonHandlers } from '../../.storybook/mocks.js';
|
||||
import MkAutocomplete from './MkAutocomplete.vue';
|
||||
import MkInput from './MkInput.vue';
|
||||
import { tick } from '@/scripts/test-utils.js';
|
||||
|
|
|
@ -6,8 +6,8 @@
|
|||
/* eslint-disable @typescript-eslint/explicit-function-return-type */
|
||||
import { StoryObj } from '@storybook/vue3';
|
||||
import { rest } from 'msw';
|
||||
import { userDetailed } from '../../.storybook/fakes';
|
||||
import { commonHandlers } from '../../.storybook/mocks';
|
||||
import { userDetailed } from '../../.storybook/fakes.js';
|
||||
import { commonHandlers } from '../../.storybook/mocks.js';
|
||||
import MkAvatars from './MkAvatars.vue';
|
||||
export const Default = {
|
||||
render(args) {
|
||||
|
|
|
@ -26,7 +26,7 @@ export type Captcha = {
|
|||
getResponse(id: string): string;
|
||||
};
|
||||
|
||||
type CaptchaProvider = 'hcaptcha' | 'recaptcha' | 'turnstile';
|
||||
export type CaptchaProvider = 'hcaptcha' | 'recaptcha' | 'turnstile';
|
||||
|
||||
type CaptchaContainer = {
|
||||
readonly [_ in CaptchaProvider]?: Captcha;
|
||||
|
|
|
@ -20,7 +20,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
<script lang="ts" setup>
|
||||
import { onMounted, onBeforeUnmount, shallowRef, ref } from 'vue';
|
||||
import MkMenu from './MkMenu.vue';
|
||||
import { MenuItem } from './types/menu.vue';
|
||||
import { MenuItem } from '@/types/menu.js';
|
||||
import contains from '@/scripts/contains.js';
|
||||
import { defaultStore } from '@/store.js';
|
||||
import * as os from '@/os.js';
|
||||
|
|
|
@ -6,11 +6,11 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
<script lang="ts">
|
||||
import { defineComponent, h, PropType, TransitionGroup, useCssModule } from 'vue';
|
||||
import MkAd from '@/components/global/MkAd.vue';
|
||||
import { isDebuggerEnabled, stackTraceInstances } from '@/debug';
|
||||
import { isDebuggerEnabled, stackTraceInstances } from '@/debug.js';
|
||||
import { i18n } from '@/i18n.js';
|
||||
import * as os from '@/os.js';
|
||||
import { defaultStore } from '@/store.js';
|
||||
import { MisskeyEntity } from '@/types/date-separated-list';
|
||||
import { MisskeyEntity } from '@/types/date-separated-list.js';
|
||||
|
||||
export default defineComponent({
|
||||
props: {
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
import { expect } from '@storybook/jest';
|
||||
import { userEvent, waitFor, within } from '@storybook/testing-library';
|
||||
import { StoryObj } from '@storybook/vue3';
|
||||
import { galleryPost } from '../../.storybook/fakes';
|
||||
import { galleryPost } from '../../.storybook/fakes.js';
|
||||
import MkGalleryPostPreview from './MkGalleryPostPreview.vue';
|
||||
export const Default = {
|
||||
render(args) {
|
||||
|
|
|
@ -6,8 +6,8 @@
|
|||
/* 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 { userDetailed, inviteCode } from '../../.storybook/fakes.js';
|
||||
import { commonHandlers } from '../../.storybook/mocks.js';
|
||||
import MkInviteCode from './MkInviteCode.vue';
|
||||
|
||||
export const Default = {
|
||||
|
|
|
@ -29,7 +29,7 @@ const self = props.url.startsWith(local);
|
|||
const attr = self ? 'to' : 'href';
|
||||
const target = self ? null : '_blank';
|
||||
|
||||
const el = ref();
|
||||
const el = ref<HTMLElement>();
|
||||
|
||||
useTooltip(el, (showing) => {
|
||||
os.popup(defineAsyncComponent(() => import('@/components/MkUrlPreviewPopup.vue')), {
|
||||
|
|
|
@ -27,7 +27,7 @@ export default {
|
|||
},
|
||||
},
|
||||
setup(props) {
|
||||
const contentEl = ref();
|
||||
const contentEl = ref<HTMLElement>();
|
||||
|
||||
function calc() {
|
||||
const eachLength = contentEl.value.offsetWidth / props.repeat;
|
||||
|
|
|
@ -37,7 +37,7 @@ import XBanner from '@/components/MkMediaBanner.vue';
|
|||
import XImage from '@/components/MkMediaImage.vue';
|
||||
import XVideo from '@/components/MkMediaVideo.vue';
|
||||
import * as os from '@/os.js';
|
||||
import { FILE_TYPE_BROWSERSAFE } from '@/const';
|
||||
import { FILE_TYPE_BROWSERSAFE } from '@/const.js';
|
||||
import { defaultStore } from '@/store.js';
|
||||
|
||||
const props = defineProps<{
|
||||
|
|
|
@ -77,7 +77,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
import { computed, defineAsyncComponent, nextTick, onBeforeUnmount, onMounted, ref, shallowRef, watch } from 'vue';
|
||||
import { focusPrev, focusNext } from '@/scripts/focus.js';
|
||||
import MkSwitchButton from '@/components/MkSwitch.button.vue';
|
||||
import { MenuItem, InnerMenuItem, MenuPending, MenuAction, MenuSwitch, MenuParent } from '@/types/menu';
|
||||
import { MenuItem, InnerMenuItem, MenuPending, MenuAction, MenuSwitch, MenuParent } from '@/types/menu.js';
|
||||
import * as os from '@/os.js';
|
||||
import { i18n } from '@/i18n.js';
|
||||
import { isTouchUsing } from '@/scripts/touch.js';
|
||||
|
|
|
@ -243,7 +243,7 @@ const collapsed = ref(appearNote.value.cw == null && isLong);
|
|||
const isDeleted = ref(false);
|
||||
const muted = ref(checkMute(appearNote.value, $i?.mutedWords));
|
||||
const hardMuted = ref(props.withHardMute && checkMute(appearNote.value, $i?.hardMutedWords));
|
||||
const translation = ref<any>(null);
|
||||
const translation = ref<Misskey.entities.NotesTranslateResponse | null>(null);
|
||||
const translating = ref(false);
|
||||
const showTicker = (defaultStore.state.instanceTicker === 'always') || (defaultStore.state.instanceTicker === 'remote' && appearNote.value.user.instance);
|
||||
const canRenote = computed(() => ['public', 'home'].includes(appearNote.value.visibility) || (appearNote.value.visibility === 'followers' && appearNote.value.userId === $i.id));
|
||||
|
|
|
@ -273,7 +273,7 @@ const isMyRenote = $i && ($i.id === note.value.userId);
|
|||
const showContent = ref(false);
|
||||
const isDeleted = ref(false);
|
||||
const muted = ref($i ? checkWordMute(appearNote.value, $i, $i.mutedWords) : false);
|
||||
const translation = ref(null);
|
||||
const translation = ref<Misskey.entities.NotesTranslateResponse | null>(null);
|
||||
const translating = ref(false);
|
||||
const parsed = appearNote.value.text ? mfm.parse(appearNote.value.text) : null;
|
||||
const urls = parsed ? extractUrlFromMfm(parsed) : null;
|
||||
|
@ -299,7 +299,7 @@ provide('react', (reaction: string) => {
|
|||
});
|
||||
|
||||
const tab = ref('replies');
|
||||
const reactionTabType = ref(null);
|
||||
const reactionTabType = ref<string | null>(null);
|
||||
|
||||
const renotesPagination = computed(() => ({
|
||||
endpoint: 'notes/renotes',
|
||||
|
|
|
@ -37,7 +37,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
<i v-else-if="notification.type === 'quote'" class="ti ti-quote"></i>
|
||||
<i v-else-if="notification.type === 'pollEnded'" class="ti ti-chart-arrows"></i>
|
||||
<i v-else-if="notification.type === 'achievementEarned'" class="ti ti-medal"></i>
|
||||
<img v-else-if="notification.type === 'roleAssigned'" :src="notification.role.iconUrl" alt=""/>
|
||||
<img v-else-if="notification.type === 'roleAssigned'" style="height: 1.3em; vertical-align: -22%;" :src="notification.role.iconUrl" alt=""/>
|
||||
<!-- notification.reaction が null になることはまずないが、ここでoptional chaining使うと一部ブラウザで刺さるので念の為 -->
|
||||
<MkReactionIcon
|
||||
v-else-if="notification.type === 'reaction'"
|
||||
|
|
|
@ -37,7 +37,7 @@ import copyToClipboard from '@/scripts/copy-to-clipboard.js';
|
|||
import { url } from '@/config.js';
|
||||
import { mainRouter, routes, page } from '@/router.js';
|
||||
import { $i } from '@/account.js';
|
||||
import { Router, useScrollPositionManager } from '@/nirax';
|
||||
import { Router, useScrollPositionManager } from '@/nirax.js';
|
||||
import { i18n } from '@/i18n.js';
|
||||
import { PageMetadata, provideMetadataReceiver } from '@/scripts/page-metadata.js';
|
||||
import { openingWindowsCount } from '@/os.js';
|
||||
|
|
|
@ -49,7 +49,7 @@ import * as os from '@/os.js';
|
|||
import { onScrollTop, isTopVisible, getBodyScrollHeight, getScrollContainer, onScrollBottom, scrollToBottom, scroll, isBottomVisible } from '@/scripts/scroll.js';
|
||||
import { useDocumentVisibility } from '@/scripts/use-document-visibility.js';
|
||||
import { defaultStore } from '@/store.js';
|
||||
import { MisskeyEntity } from '@/types/date-separated-list';
|
||||
import { MisskeyEntity } from '@/types/date-separated-list.js';
|
||||
import { i18n } from '@/i18n.js';
|
||||
|
||||
const SECOND_FETCH_LIMIT = 30;
|
||||
|
|
|
@ -52,7 +52,7 @@ const emit = defineEmits<{
|
|||
const dialog = shallowRef<InstanceType<typeof MkModalWindow>>();
|
||||
const passwordInput = shallowRef<InstanceType<typeof MkInput>>();
|
||||
const password = ref('');
|
||||
const token = ref(null);
|
||||
const token = ref<string | null>(null);
|
||||
|
||||
function onClose() {
|
||||
emit('cancelled');
|
||||
|
|
|
@ -87,6 +87,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
<button v-tooltip="i18n.ts.hashtags" class="_button" :class="[$style.footerButton, { [$style.footerButtonActive]: withHashtags }]" @click="withHashtags = !withHashtags"><i class="ti ti-hash"></i></button>
|
||||
<button v-if="postFormActions.length > 0" v-tooltip="i18n.ts.plugin" class="_button" :class="$style.footerButton" @click="showActions"><i class="ti ti-plug"></i></button>
|
||||
<button v-tooltip="i18n.ts.emoji" :class="['_button', $style.footerButton]" @click="insertEmoji"><i class="ti ti-mood-happy"></i></button>
|
||||
<button v-if="showAddMfmFunction" v-tooltip="i18n.ts.addMfmFunction" :class="['_button', $style.footerButton]" @click="insertMfmFunction"><i class="ti ti-palette"></i></button>
|
||||
</div>
|
||||
<div :class="$style.footerRight">
|
||||
<button v-tooltip="i18n.ts.previewNoteText" class="_button" :class="[$style.footerButton, { [$style.previewButtonActive]: showPreview }]" @click="showPreview = !showPreview"><i class="ti ti-eye"></i></button>
|
||||
|
@ -127,6 +128,7 @@ import MkRippleEffect from '@/components/MkRippleEffect.vue';
|
|||
import { miLocalStorage } from '@/local-storage.js';
|
||||
import { claimAchievement } from '@/scripts/achievements.js';
|
||||
import { emojiPicker } from '@/scripts/emoji-picker.js';
|
||||
import { mfmFunctionPicker } from '@/scripts/mfm-function-picker.js';
|
||||
|
||||
const modal = inject('modal');
|
||||
|
||||
|
@ -183,10 +185,12 @@ const poll = ref<{
|
|||
const useCw = ref<boolean>(!!props.initialCw);
|
||||
const showPreview = ref(defaultStore.state.showPreview);
|
||||
watch(showPreview, () => defaultStore.set('showPreview', showPreview.value));
|
||||
const showAddMfmFunction = ref(defaultStore.state.enableQuickAddMfmFunction);
|
||||
watch(showAddMfmFunction, () => defaultStore.set('enableQuickAddMfmFunction', showAddMfmFunction.value));
|
||||
const cw = ref<string | null>(props.initialCw ?? null);
|
||||
const localOnly = ref<boolean>(props.initialLocalOnly ?? defaultStore.state.rememberNoteVisibility ? defaultStore.state.localOnly : defaultStore.state.defaultNoteLocalOnly);
|
||||
const visibility = ref(props.initialVisibility ?? (defaultStore.state.rememberNoteVisibility ? defaultStore.state.visibility : defaultStore.state.defaultNoteVisibility) as typeof Misskey.noteVisibilities[number]);
|
||||
const visibleUsers = ref([]);
|
||||
const visibleUsers = ref<Misskey.entities.UserDetailed[]>([]);
|
||||
if (props.initialVisibleUsers) {
|
||||
props.initialVisibleUsers.forEach(pushVisibleUser);
|
||||
}
|
||||
|
@ -195,7 +199,7 @@ const autocompleteTextareaInput = ref<Autocomplete | null>(null);
|
|||
const autocompleteCwInput = ref<Autocomplete | null>(null);
|
||||
const autocompleteHashtagsInput = ref<Autocomplete | null>(null);
|
||||
const draghover = ref(false);
|
||||
const quoteId = ref(null);
|
||||
const quoteId = ref<string | null>(null);
|
||||
const hasNotSpecifiedMentions = ref(false);
|
||||
const recentHashtags = ref(JSON.parse(miLocalStorage.getItem('hashtags') ?? '[]'));
|
||||
const imeText = ref('');
|
||||
|
@ -868,6 +872,14 @@ async function insertEmoji(ev: MouseEvent) {
|
|||
);
|
||||
}
|
||||
|
||||
async function insertMfmFunction(ev: MouseEvent) {
|
||||
mfmFunctionPicker(
|
||||
ev.currentTarget ?? ev.target,
|
||||
textareaEl.value,
|
||||
text,
|
||||
);
|
||||
}
|
||||
|
||||
function showActions(ev) {
|
||||
os.popupMenu(postFormActions.map(action => ({
|
||||
text: action.title,
|
||||
|
|
|
@ -198,7 +198,8 @@ if (!mock) {
|
|||
}
|
||||
|
||||
.limitWidth {
|
||||
max-width: 150px;
|
||||
max-width: 70px;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
.count {
|
||||
|
|
|
@ -28,10 +28,11 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
|
||||
<script lang="ts" setup>
|
||||
import { } from 'vue';
|
||||
import * as Misskey from 'misskey-js';
|
||||
import { i18n } from '@/i18n.js';
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
role: any;
|
||||
role: Misskey.entities.Role;
|
||||
forModeration: boolean;
|
||||
detailed: boolean;
|
||||
}>(), {
|
||||
|
|
|
@ -65,9 +65,9 @@ const changed = ref(false);
|
|||
const invalid = ref(false);
|
||||
const filled = computed(() => v.value !== '' && v.value != null);
|
||||
const inputEl = ref<HTMLSelectElement | null>(null);
|
||||
const prefixEl = ref(null);
|
||||
const suffixEl = ref(null);
|
||||
const container = ref(null);
|
||||
const prefixEl = ref<HTMLElement | null>(null);
|
||||
const suffixEl = ref<HTMLElement | null>(null);
|
||||
const container = ref<HTMLElement | null>(null);
|
||||
const height =
|
||||
props.small ? 33 :
|
||||
props.large ? 39 :
|
||||
|
|
|
@ -71,8 +71,6 @@ const host = ref(toUnicode(configHost));
|
|||
const totpLogin = ref(false);
|
||||
const queryingKey = ref(false);
|
||||
const credentialRequest = ref<CredentialRequestOptions | null>(null);
|
||||
const hCaptchaResponse = ref(null);
|
||||
const reCaptchaResponse = ref(null);
|
||||
|
||||
const emit = defineEmits<{
|
||||
(ev: 'login', v: any): void;
|
||||
|
@ -126,8 +124,6 @@ async function queryKey(): Promise<void> {
|
|||
username: username.value,
|
||||
password: password.value,
|
||||
credential: credential.toJSON(),
|
||||
'hcaptcha-response': hCaptchaResponse.value,
|
||||
'g-recaptcha-response': reCaptchaResponse.value,
|
||||
});
|
||||
}).then(res => {
|
||||
emit('login', res);
|
||||
|
@ -149,8 +145,6 @@ function onSubmit(): void {
|
|||
os.api('signin', {
|
||||
username: username.value,
|
||||
password: password.value,
|
||||
'hcaptcha-response': hCaptchaResponse.value,
|
||||
'g-recaptcha-response': reCaptchaResponse.value,
|
||||
}).then(res => {
|
||||
totpLogin.value = true;
|
||||
signing.value = false;
|
||||
|
@ -168,8 +162,6 @@ function onSubmit(): void {
|
|||
os.api('signin', {
|
||||
username: username.value,
|
||||
password: password.value,
|
||||
'hcaptcha-response': hCaptchaResponse.value,
|
||||
'g-recaptcha-response': reCaptchaResponse.value,
|
||||
token: user.value?.twoFactorEnabled ? token.value : undefined,
|
||||
}).then(res => {
|
||||
emit('login', res);
|
||||
|
|
|
@ -115,9 +115,9 @@ const emailState = ref<null | 'wait' | 'ok' | 'unavailable:used' | 'unavailable:
|
|||
const passwordStrength = ref<'' | 'low' | 'medium' | 'high'>('');
|
||||
const passwordRetypeState = ref<null | 'match' | 'not-match'>(null);
|
||||
const submitting = ref<boolean>(false);
|
||||
const hCaptchaResponse = ref(null);
|
||||
const reCaptchaResponse = ref(null);
|
||||
const turnstileResponse = ref(null);
|
||||
const hCaptchaResponse = ref<string | null>(null);
|
||||
const reCaptchaResponse = ref<string | null>(null);
|
||||
const turnstileResponse = ref<string | null>(null);
|
||||
const usernameAbortController = ref<null | AbortController>(null);
|
||||
const emailAbortController = ref<null | AbortController>(null);
|
||||
|
||||
|
|
|
@ -72,7 +72,14 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
<script lang="ts" setup>
|
||||
import { onMounted, onUnmounted, ref, shallowRef } from 'vue';
|
||||
|
||||
const particles = ref([]);
|
||||
const particles = ref<{
|
||||
id: string,
|
||||
x: number,
|
||||
y: number,
|
||||
size: number,
|
||||
dur: number,
|
||||
color: string
|
||||
}[]>([]);
|
||||
const el = shallowRef<HTMLElement>();
|
||||
const width = ref(0);
|
||||
const height = ref(0);
|
||||
|
|
|
@ -33,7 +33,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
<MkButton inline @click="enableAll">{{ i18n.ts.enableAll }}</MkButton>
|
||||
</div>
|
||||
<div class="_gaps_s">
|
||||
<MkSwitch v-for="kind in (initialPermissions || Misskey.permissions)" :key="kind" v-model="permissions[kind]">{{ i18n.t(`_permissions.${kind}`) }}</MkSwitch>
|
||||
<MkSwitch v-for="kind in Object.keys(permissions)" :key="kind" v-model="permissions[kind]">{{ i18n.t(`_permissions.${kind}`) }}</MkSwitch>
|
||||
</div>
|
||||
</div>
|
||||
</MkSpacer>
|
||||
|
@ -54,7 +54,7 @@ const props = withDefaults(defineProps<{
|
|||
title?: string | null;
|
||||
information?: string | null;
|
||||
initialName?: string | null;
|
||||
initialPermissions?: string[] | null;
|
||||
initialPermissions?: (typeof Misskey.permissions)[number][] | null;
|
||||
}>(), {
|
||||
title: null,
|
||||
information: null,
|
||||
|
@ -67,16 +67,17 @@ const emit = defineEmits<{
|
|||
(ev: 'done', result: { name: string | null, permissions: string[] }): void;
|
||||
}>();
|
||||
|
||||
const defaultPermissions = Misskey.permissions.filter(p => !p.startsWith('read:admin') && !p.startsWith('write:admin'));
|
||||
const dialog = shallowRef<InstanceType<typeof MkModalWindow>>();
|
||||
const name = ref(props.initialName);
|
||||
const permissions = ref({});
|
||||
const permissions = ref(<Record<(typeof Misskey.permissions)[number], boolean>>{});
|
||||
|
||||
if (props.initialPermissions) {
|
||||
for (const kind of props.initialPermissions) {
|
||||
permissions.value[kind] = true;
|
||||
}
|
||||
} else {
|
||||
for (const kind of Misskey.permissions) {
|
||||
for (const kind of defaultPermissions) {
|
||||
permissions.value[kind] = false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -83,7 +83,7 @@ const props = defineProps<{
|
|||
announcement?: any,
|
||||
}>();
|
||||
|
||||
const dialog = ref(null);
|
||||
const dialog = ref<InstanceType<typeof MkModalWindow> | null>(null);
|
||||
const title = ref<string>(props.announcement ? props.announcement.title : '');
|
||||
const text = ref<string>(props.announcement ? props.announcement.text : '');
|
||||
const icon = ref<string>(props.announcement ? props.announcement.icon : 'info');
|
||||
|
|
|
@ -6,8 +6,8 @@
|
|||
/* eslint-disable @typescript-eslint/explicit-function-return-type */
|
||||
import { StoryObj } from '@storybook/vue3';
|
||||
import { rest } from 'msw';
|
||||
import { commonHandlers } from '../../.storybook/mocks';
|
||||
import { userDetailed } from '../../.storybook/fakes';
|
||||
import { commonHandlers } from '../../.storybook/mocks.js';
|
||||
import { userDetailed } from '../../.storybook/fakes.js';
|
||||
import MkUserSetupDialog_Follow from './MkUserSetupDialog.Follow.vue';
|
||||
export const Default = {
|
||||
render(args) {
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
/* eslint-disable @typescript-eslint/explicit-function-return-type */
|
||||
import { StoryObj } from '@storybook/vue3';
|
||||
import { userDetailed } from '../../.storybook/fakes';
|
||||
import { userDetailed } from '../../.storybook/fakes.js';
|
||||
import MkUserSetupDialog_User from './MkUserSetupDialog.User.vue';
|
||||
export const Default = {
|
||||
render(args) {
|
||||
|
|
|
@ -6,8 +6,8 @@
|
|||
/* eslint-disable @typescript-eslint/explicit-function-return-type */
|
||||
import { StoryObj } from '@storybook/vue3';
|
||||
import { rest } from 'msw';
|
||||
import { commonHandlers } from '../../.storybook/mocks';
|
||||
import { userDetailed } from '../../.storybook/fakes';
|
||||
import { commonHandlers } from '../../.storybook/mocks.js';
|
||||
import { userDetailed } from '../../.storybook/fakes.js';
|
||||
import MkUserSetupDialog from './MkUserSetupDialog.vue';
|
||||
export const Default = {
|
||||
render(args) {
|
||||
|
|
|
@ -54,7 +54,7 @@ import { defineAsyncComponent, ref } from 'vue';
|
|||
import { v4 as uuid } from 'uuid';
|
||||
import MkSelect from '@/components/MkSelect.vue';
|
||||
import MkButton from '@/components/MkButton.vue';
|
||||
import { widgets as widgetDefs } from '@/widgets';
|
||||
import { widgets as widgetDefs } from '@/widgets/index.js';
|
||||
import * as os from '@/os.js';
|
||||
import { i18n } from '@/i18n.js';
|
||||
|
||||
|
@ -77,7 +77,7 @@ const widgetRefs = {};
|
|||
const configWidget = (id: string) => {
|
||||
widgetRefs[id].configure();
|
||||
};
|
||||
const widgetAdderSelected = ref(null);
|
||||
const widgetAdderSelected = ref<string | null>(null);
|
||||
const addWidget = () => {
|
||||
if (widgetAdderSelected.value == null) return;
|
||||
|
||||
|
|
|
@ -30,7 +30,7 @@ const props = defineProps<{
|
|||
const pending = ref(true);
|
||||
const resolved = ref(false);
|
||||
const rejected = ref(false);
|
||||
const result = ref(null);
|
||||
const result = ref<any>(null);
|
||||
|
||||
const process = () => {
|
||||
if (props.p == null) {
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
/* eslint-disable @typescript-eslint/explicit-function-return-type */
|
||||
import { StoryObj } from '@storybook/vue3';
|
||||
import { userDetailed } from '../../../.storybook/fakes';
|
||||
import { userDetailed } from '../../../.storybook/fakes.js';
|
||||
import MkAcct from './MkAcct.vue';
|
||||
export const Default = {
|
||||
render(args) {
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
/* eslint-disable @typescript-eslint/explicit-function-return-type */
|
||||
import { StoryObj } from '@storybook/vue3';
|
||||
import { userDetailed } from '../../../.storybook/fakes';
|
||||
import { userDetailed } from '../../../.storybook/fakes.js';
|
||||
import MkAvatar from './MkAvatar.vue';
|
||||
const common = {
|
||||
render(args) {
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
import { StoryObj } from '@storybook/vue3';
|
||||
import { within } from '@storybook/testing-library';
|
||||
import { expect } from '@storybook/jest';
|
||||
import MkMisskeyFlavoredMarkdown from './MkMisskeyFlavoredMarkdown.ts';
|
||||
import MkMisskeyFlavoredMarkdown from './MkMisskeyFlavoredMarkdown.js';
|
||||
export const Default = {
|
||||
render(args) {
|
||||
return {
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
import { VNode, h } from 'vue';
|
||||
import { VNode, h, SetupContext } from 'vue';
|
||||
import * as mfm from 'mfm-js';
|
||||
import * as Misskey from 'misskey-js';
|
||||
import MkUrl from '@/components/global/MkUrl.vue';
|
||||
|
@ -43,8 +43,12 @@ type MfmProps = {
|
|||
enableEmojiMenuReaction?: boolean;
|
||||
};
|
||||
|
||||
type MfmEvents = {
|
||||
clickEv(id: string): void;
|
||||
};
|
||||
|
||||
// eslint-disable-next-line import/no-default-export
|
||||
export default function(props: MfmProps) {
|
||||
export default function(props: MfmProps, context: SetupContext<MfmEvents>) {
|
||||
const isNote = props.isNote ?? true;
|
||||
const shouldNyaize = props.nyaize ? props.nyaize === 'respect' ? props.author?.isCat : false : false;
|
||||
|
||||
|
@ -238,13 +242,13 @@ export default function(props: MfmProps) {
|
|||
case 'fg': {
|
||||
let color = token.props.args.color;
|
||||
if (!/^[0-9a-f]{3,6}$/i.test(color)) color = 'f00';
|
||||
style = `color: #${color};`;
|
||||
style = `color: #${color}; overflow-wrap: anywhere;`;
|
||||
break;
|
||||
}
|
||||
case 'bg': {
|
||||
let color = token.props.args.color;
|
||||
if (!/^[0-9a-f]{3,6}$/i.test(color)) color = 'f00';
|
||||
style = `background-color: #${color};`;
|
||||
style = `background-color: #${color}; overflow-wrap: anywhere;`;
|
||||
break;
|
||||
}
|
||||
case 'ruby': {
|
||||
|
@ -281,6 +285,13 @@ export default function(props: MfmProps) {
|
|||
}),
|
||||
]);
|
||||
}
|
||||
case 'clickable': {
|
||||
return h('span', { onClick(ev: MouseEvent): void {
|
||||
ev.stopPropagation();
|
||||
ev.preventDefault();
|
||||
context.emit('clickEv', token.props.args.ev ?? '');
|
||||
} }, genEl(token.children, scale));
|
||||
}
|
||||
}
|
||||
if (style === undefined) {
|
||||
return h('span', {}, ['$[', token.props.name, ' ', ...genEl(token.children, scale), ']']);
|
||||
|
|
|
@ -20,7 +20,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
<script lang="ts" setup>
|
||||
import { onMounted, onUnmounted, provide, inject, Ref, ref, watch, shallowRef } from 'vue';
|
||||
|
||||
import { CURRENT_STICKY_BOTTOM, CURRENT_STICKY_TOP } from '@/const';
|
||||
import { CURRENT_STICKY_BOTTOM, CURRENT_STICKY_TOP } from '@/const.js';
|
||||
|
||||
const rootEl = shallowRef<HTMLElement>();
|
||||
const headerEl = shallowRef<HTMLElement>();
|
||||
|
|
|
@ -8,7 +8,7 @@ import { expect } from '@storybook/jest';
|
|||
import { userEvent, waitFor, within } from '@storybook/testing-library';
|
||||
import { StoryObj } from '@storybook/vue3';
|
||||
import { rest } from 'msw';
|
||||
import { commonHandlers } from '../../../.storybook/mocks';
|
||||
import { commonHandlers } from '../../../.storybook/mocks.js';
|
||||
import MkUrl from './MkUrl.vue';
|
||||
export const Default = {
|
||||
render(args) {
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
/* eslint-disable @typescript-eslint/explicit-function-return-type */
|
||||
import { expect } from '@storybook/jest';
|
||||
import { StoryObj } from '@storybook/vue3';
|
||||
import { userDetailed } from '../../../.storybook/fakes';
|
||||
import { userDetailed } from '../../../.storybook/fakes.js';
|
||||
import MkUserName from './MkUserName.vue';
|
||||
export const Default = {
|
||||
render(args) {
|
||||
|
|
|
@ -17,7 +17,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
|
||||
<script lang="ts" setup>
|
||||
import { inject, onBeforeUnmount, provide, shallowRef, ref } from 'vue';
|
||||
import { Resolved, Router } from '@/nirax';
|
||||
import { Resolved, Router } from '@/nirax.js';
|
||||
import { defaultStore } from '@/store.js';
|
||||
|
||||
const props = defineProps<{
|
||||
|
|
|
@ -14,7 +14,7 @@ import XText from './page.text.vue';
|
|||
import XSection from './page.section.vue';
|
||||
import XImage from './page.image.vue';
|
||||
import XNote from './page.note.vue';
|
||||
import { Block } from './block.type';
|
||||
import { Block } from './block.type.js';
|
||||
|
||||
function getComponent(type: string) {
|
||||
switch (type) {
|
||||
|
|
|
@ -16,7 +16,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
<script lang="ts" setup>
|
||||
import { ref } from 'vue';
|
||||
import * as Misskey from 'misskey-js';
|
||||
import { ImageBlock } from './block.type';
|
||||
import { ImageBlock } from './block.type.js';
|
||||
import MediaImage from '@/components/MkMediaImage.vue';
|
||||
|
||||
const props = defineProps<{
|
||||
|
|
|
@ -11,9 +11,9 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { onMounted, Ref, ref } from 'vue';
|
||||
import { onMounted, ref } from 'vue';
|
||||
import * as Misskey from 'misskey-js';
|
||||
import { NoteBlock } from './block.type';
|
||||
import { NoteBlock } from './block.type.js';
|
||||
import MkNote from '@/components/MkNote.vue';
|
||||
import MkNoteDetailed from '@/components/MkNoteDetailed.vue';
|
||||
import * as os from '@/os.js';
|
||||
|
@ -23,7 +23,7 @@ const props = defineProps<{
|
|||
page: Misskey.entities.Page,
|
||||
}>();
|
||||
|
||||
const note: Ref<Misskey.entities.Note | null> = ref(null);
|
||||
const note = ref<Misskey.entities.Note | null>(null);
|
||||
|
||||
onMounted(() => {
|
||||
os.api('notes/show', { noteId: props.block.note })
|
||||
|
|
|
@ -25,7 +25,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
<script lang="ts" setup>
|
||||
import { defineAsyncComponent } from 'vue';
|
||||
import * as Misskey from 'misskey-js';
|
||||
import { SectionBlock } from './block.type';
|
||||
import { SectionBlock } from './block.type.js';
|
||||
|
||||
const XBlock = defineAsyncComponent(() => import('./page.block.vue'));
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
import { defineAsyncComponent } from 'vue';
|
||||
import * as mfm from 'mfm-js';
|
||||
import * as Misskey from 'misskey-js';
|
||||
import { TextBlock } from './block.type';
|
||||
import { TextBlock } from './block.type.js';
|
||||
import { extractUrlFromMfm } from '@/scripts/extract-url-from-mfm.js';
|
||||
|
||||
const MkUrlPreview = defineAsyncComponent(() => import('@/components/MkUrlPreview.vue'));
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue