refactor: fix some type errors
This commit is contained in:
parent
62aaaf9e92
commit
897b5d9bb1
|
@ -27,7 +27,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
<!-- フォルダの中にはカスタム絵文字やフォルダがある -->
|
||||
<section v-else v-panel style="border-radius: 6px; border-bottom: 0.5px solid var(--divider);">
|
||||
<header class="_acrylic" @click="shown = !shown">
|
||||
<i class="toggle ti-fw" :class="shown ? 'ti ti-chevron-down' : 'ti ti-chevron-up'"></i> <slot></slot> (<i class="ti ti-folder ti-fw"></i>:{{ customEmojiTree.length }} <i class="ti ti-icons ti-fw"></i>:{{ emojis.length }})
|
||||
<i class="toggle ti-fw" :class="shown ? 'ti ti-chevron-down' : 'ti ti-chevron-up'"></i> <slot></slot> (<i class="ti ti-folder ti-fw"></i>:{{ customEmojiTree?.length }} <i class="ti ti-icons ti-fw"></i>:{{ emojis.length }})
|
||||
</header>
|
||||
<div v-if="shown" style="padding-left: 9px;">
|
||||
<MkEmojiPickerSection
|
||||
|
@ -61,7 +61,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
<script lang="ts" setup>
|
||||
import { ref, computed, Ref } from 'vue';
|
||||
import { CustomEmojiFolderTree, getEmojiName } from '@/scripts/emojilist.js';
|
||||
import { i18n } from '../i18n.js';
|
||||
import { i18n } from '@/i18n.js';
|
||||
import { customEmojis } from '@/custom-emojis.js';
|
||||
import MkEmojiPickerSection from '@/components/MkEmojiPicker.section.vue';
|
||||
|
||||
|
@ -87,7 +87,7 @@ function computeButtonTitle(ev: MouseEvent): void {
|
|||
elm.title = getEmojiName(emoji) ?? emoji;
|
||||
}
|
||||
|
||||
function nestedChosen(emoji: any, ev?: MouseEvent) {
|
||||
function nestedChosen(emoji: any, ev: MouseEvent) {
|
||||
emit('chosen', emoji, ev);
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -36,7 +36,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</section>
|
||||
|
||||
<div v-if="tab === 'index'" class="group index">
|
||||
<section v-if="showPinned && pinned.length > 0">
|
||||
<section v-if="showPinned && (pinned && pinned.length > 0)">
|
||||
<div class="body">
|
||||
<button
|
||||
v-for="emoji in pinned"
|
||||
|
@ -327,7 +327,7 @@ watch(q, () => {
|
|||
});
|
||||
|
||||
function filterAvailable(emoji: Misskey.entities.EmojiSimple): boolean {
|
||||
return (emoji.roleIdsThatCanBeUsedThisEmojiAsReaction == null || emoji.roleIdsThatCanBeUsedThisEmojiAsReaction.length === 0) || ($i && $i.roles.some(r => emoji.roleIdsThatCanBeUsedThisEmojiAsReaction.includes(r.id)));
|
||||
return ((emoji.roleIdsThatCanBeUsedThisEmojiAsReaction == null || emoji.roleIdsThatCanBeUsedThisEmojiAsReaction.length === 0) || ($i && $i.roles.some(r => emoji.roleIdsThatCanBeUsedThisEmojiAsReaction?.includes(r.id)))) ?? false;
|
||||
}
|
||||
|
||||
function focus() {
|
||||
|
|
|
@ -11,7 +11,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
:withOkButton="true"
|
||||
:okButtonDisabled="false"
|
||||
@ok="ok()"
|
||||
@close="dialog.close()"
|
||||
@close="dialog?.close()"
|
||||
@closed="emit('closed')"
|
||||
>
|
||||
<template #header>{{ i18n.ts.describeFile }}</template>
|
||||
|
@ -48,6 +48,6 @@ const caption = ref(props.default);
|
|||
|
||||
async function ok() {
|
||||
emit('done', caption.value);
|
||||
dialog.value.close();
|
||||
dialog.value?.close();
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -7,7 +7,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
<div>
|
||||
<MkPagination v-slot="{items}" :pagination="pagination" class="urempief" :class="{ grid: viewMode === 'grid' }">
|
||||
<MkA
|
||||
v-for="file in items"
|
||||
v-for="file in (items as Misskey.entities.DriveFile[])"
|
||||
:key="file.id"
|
||||
v-tooltip.mfm="`${file.type}\n${bytes(file.size)}\n${dateString(file.createdAt)}\nby ${file.user ? '@' + Misskey.acct.toString(file.user) : 'system'}`"
|
||||
:to="`/admin/file/${file.id}`"
|
||||
|
|
|
@ -4,7 +4,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
-->
|
||||
|
||||
<template>
|
||||
<div ref="el" :class="$style.root">
|
||||
<div ref="div" :class="$style.root">
|
||||
<header :class="$style.header" class="_button" :style="{ background: bg }" @click="showBody = !showBody">
|
||||
<div :class="$style.title"><div><slot name="header"></slot></div></div>
|
||||
<div :class="$style.divider"></div>
|
||||
|
@ -42,8 +42,8 @@ const props = withDefaults(defineProps<{
|
|||
expanded: true,
|
||||
});
|
||||
|
||||
const el = shallowRef<HTMLDivElement>();
|
||||
const bg = ref<string | null>(null);
|
||||
const div = shallowRef<HTMLDivElement>();
|
||||
const bg = ref<string>();
|
||||
const showBody = ref((props.persistKey && miLocalStorage.getItem(`${miLocalStoragePrefix}${props.persistKey}`)) ? (miLocalStorage.getItem(`${miLocalStoragePrefix}${props.persistKey}`) === 't') : props.expanded);
|
||||
|
||||
watch(showBody, () => {
|
||||
|
@ -52,40 +52,44 @@ watch(showBody, () => {
|
|||
}
|
||||
});
|
||||
|
||||
function enter(el: Element) {
|
||||
function enter(element: Element) {
|
||||
const el = element as HTMLElement;
|
||||
const elementHeight = el.getBoundingClientRect().height;
|
||||
el.style.height = 0;
|
||||
el.style.height = 'unset';
|
||||
el.offsetHeight; // reflow
|
||||
el.style.height = elementHeight + 'px';
|
||||
}
|
||||
|
||||
function afterEnter(el: Element) {
|
||||
el.style.height = null;
|
||||
function afterEnter(element: Element) {
|
||||
const el = element as HTMLElement;
|
||||
el.style.height = 'unset';
|
||||
}
|
||||
|
||||
function leave(el: Element) {
|
||||
function leave(element: Element) {
|
||||
const el = element as HTMLElement;
|
||||
const elementHeight = el.getBoundingClientRect().height;
|
||||
el.style.height = elementHeight + 'px';
|
||||
el.offsetHeight; // reflow
|
||||
el.style.height = 0;
|
||||
el.style.height = '0';
|
||||
}
|
||||
|
||||
function afterLeave(el: Element) {
|
||||
el.style.height = null;
|
||||
function afterLeave(element: Element) {
|
||||
const el = element as HTMLElement;
|
||||
el.style.height = 'unset';
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
function getParentBg(el: HTMLElement | null): string {
|
||||
function getParentBg(el?: HTMLElement | null): string {
|
||||
if (el == null || el.tagName === 'BODY') return 'var(--bg)';
|
||||
const bg = el.style.background || el.style.backgroundColor;
|
||||
if (bg) {
|
||||
return bg;
|
||||
const background = el.style.background || el.style.backgroundColor;
|
||||
if (background) {
|
||||
return background;
|
||||
} else {
|
||||
return getParentBg(el.parentElement);
|
||||
}
|
||||
}
|
||||
|
||||
const rawBg = getParentBg(el.value);
|
||||
const rawBg = getParentBg(div.value);
|
||||
const _bg = tinycolor(rawBg.startsWith('var(') ? getComputedStyle(document.documentElement).getPropertyValue(rawBg.slice(4, -1)) : rawBg);
|
||||
_bg.setAlpha(0.85);
|
||||
bg.value = _bg.toRgbString();
|
||||
|
|
|
@ -25,7 +25,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</div>
|
||||
</template>
|
||||
|
||||
<div v-if="openedAtLeastOnce" :class="[$style.body, { [$style.bgSame]: bgSame }]" :style="{ maxHeight: maxHeight ? `${maxHeight}px` : null, overflow: maxHeight ? `auto` : null }" :aria-hidden="!opened">
|
||||
<div v-if="openedAtLeastOnce" :class="[$style.body, { [$style.bgSame]: bgSame }]" :style="{ maxHeight: maxHeight ? `${maxHeight}px` : undefined, overflow: maxHeight ? `auto` : undefined }" :aria-hidden="!opened">
|
||||
<Transition
|
||||
:enterActiveClass="defaultStore.state.animation ? $style.transition_toggle_enterActive : ''"
|
||||
:leaveActiveClass="defaultStore.state.animation ? $style.transition_toggle_leaveActive : ''"
|
||||
|
@ -109,7 +109,7 @@ function toggle() {
|
|||
|
||||
onMounted(() => {
|
||||
const computedStyle = getComputedStyle(document.documentElement);
|
||||
const parentBg = getBgColor(rootEl.value.parentElement);
|
||||
const parentBg = getBgColor(rootEl.value!.parentElement!);
|
||||
const myBg = computedStyle.getPropertyValue('--panel');
|
||||
bgSame.value = parentBg === myBg;
|
||||
});
|
||||
|
|
|
@ -111,17 +111,19 @@ async function onClick() {
|
|||
|
||||
claimAchievement('following1');
|
||||
|
||||
if ($i.followingCount >= 10) {
|
||||
claimAchievement('following10');
|
||||
}
|
||||
if ($i.followingCount >= 50) {
|
||||
claimAchievement('following50');
|
||||
}
|
||||
if ($i.followingCount >= 100) {
|
||||
claimAchievement('following100');
|
||||
}
|
||||
if ($i.followingCount >= 300) {
|
||||
claimAchievement('following300');
|
||||
if ($i) {
|
||||
if ($i.followingCount >= 10) {
|
||||
claimAchievement('following10');
|
||||
}
|
||||
if ($i.followingCount >= 50) {
|
||||
claimAchievement('following50');
|
||||
}
|
||||
if ($i.followingCount >= 100) {
|
||||
claimAchievement('following100');
|
||||
}
|
||||
if ($i.followingCount >= 300) {
|
||||
claimAchievement('following300');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
ref="dialog"
|
||||
:width="370"
|
||||
:height="400"
|
||||
@close="dialog.close()"
|
||||
@close="dialog?.close()"
|
||||
@closed="emit('closed')"
|
||||
>
|
||||
<template #header>{{ i18n.ts.forgotPassword }}</template>
|
||||
|
@ -66,6 +66,6 @@ async function onSubmit() {
|
|||
email: email.value,
|
||||
});
|
||||
emit('done');
|
||||
dialog.value.close();
|
||||
dialog.value?.close();
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -40,11 +40,11 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</MkSwitch>
|
||||
<MkSelect v-else-if="form[item].type === 'enum'" v-model="values[item]">
|
||||
<template #label><span v-text="form[item].label || item"></span><span v-if="form[item].required === false"> ({{ i18n.ts.optional }})</span></template>
|
||||
<option v-for="item in form[item].enum" :key="item.value" :value="item.value">{{ item.label }}</option>
|
||||
<option v-for="option in form[item].enum" :key="option.value" :value="option.value">{{ option.label }}</option>
|
||||
</MkSelect>
|
||||
<MkRadios v-else-if="form[item].type === 'radio'" v-model="values[item]">
|
||||
<template #label><span v-text="form[item].label || item"></span><span v-if="form[item].required === false"> ({{ i18n.ts.optional }})</span></template>
|
||||
<option v-for="item in form[item].options" :key="item.value" :value="item.value">{{ item.label }}</option>
|
||||
<option v-for="option in form[item].options" :key="option.value" :value="option.value">{{ option.label }}</option>
|
||||
</MkRadios>
|
||||
<MkRange v-else-if="form[item].type === 'range'" v-model="values[item]" :min="form[item].min" :max="form[item].max" :step="form[item].step" :textConverter="form[item].textConverter">
|
||||
<template #label><span v-text="form[item].label || item"></span><span v-if="form[item].required === false"> ({{ i18n.ts.optional }})</span></template>
|
||||
|
@ -86,6 +86,7 @@ const emit = defineEmits<{
|
|||
canceled?: boolean;
|
||||
result?: any;
|
||||
}): void;
|
||||
(ev: 'closed'): void;
|
||||
}>();
|
||||
|
||||
const dialog = shallowRef<InstanceType<typeof MkModalWindow>>();
|
||||
|
@ -99,13 +100,13 @@ function ok() {
|
|||
emit('done', {
|
||||
result: values,
|
||||
});
|
||||
dialog.value.close();
|
||||
dialog.value?.close();
|
||||
}
|
||||
|
||||
function cancel() {
|
||||
emit('done', {
|
||||
canceled: true,
|
||||
});
|
||||
dialog.value.close();
|
||||
dialog.value?.close();
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -14,8 +14,8 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
leaveActiveClass: $style.transition_toggle_leaveActive,
|
||||
leaveToClass: $style.transition_toggle_leaveTo,
|
||||
}"
|
||||
:src="post.files[0].thumbnailUrl"
|
||||
:hash="post.files[0].blurhash"
|
||||
:src="post.files?.[0]?.thumbnailUrl"
|
||||
:hash="post.files?.[0]?.blurhash"
|
||||
:forceBlurhash="!show"
|
||||
/>
|
||||
</Transition>
|
||||
|
|
|
@ -27,10 +27,10 @@ const props = defineProps<{
|
|||
src: string;
|
||||
}>();
|
||||
|
||||
const rootEl = shallowRef<HTMLDivElement>(null);
|
||||
const chartEl = shallowRef<HTMLCanvasElement>(null);
|
||||
const rootEl = shallowRef<HTMLDivElement | null>(null);
|
||||
const chartEl = shallowRef<HTMLCanvasElement | null>(null);
|
||||
const now = new Date();
|
||||
let chartInstance: Chart = null;
|
||||
let chartInstance: Chart | null = null;
|
||||
const fetching = ref(true);
|
||||
|
||||
const { handler: externalTooltipHandler } = useChartTooltip({
|
||||
|
@ -38,6 +38,7 @@ const { handler: externalTooltipHandler } = useChartTooltip({
|
|||
});
|
||||
|
||||
async function renderChart() {
|
||||
if (!rootEl.value || !chartEl.value) return;
|
||||
if (chartInstance) {
|
||||
chartInstance.destroy();
|
||||
}
|
||||
|
@ -56,7 +57,7 @@ async function renderChart() {
|
|||
return new Date(y, m, d - ago);
|
||||
};
|
||||
|
||||
const format = (arr) => {
|
||||
const format = (arr: number[]) => {
|
||||
return arr.map((v, i) => {
|
||||
const dt = getDate(i);
|
||||
const iso = `${dt.getFullYear()}-${(dt.getMonth() + 1).toString().padStart(2, '0')}-${dt.getDate().toString().padStart(2, '0')}`;
|
||||
|
@ -69,7 +70,7 @@ async function renderChart() {
|
|||
});
|
||||
};
|
||||
|
||||
let values;
|
||||
let values: number[] = [];
|
||||
|
||||
if (props.src === 'active-users') {
|
||||
const raw = await misskeyApi('charts/active-users', { limit: chartLimit, span: 'day' });
|
||||
|
@ -106,20 +107,18 @@ async function renderChart() {
|
|||
data: {
|
||||
datasets: [{
|
||||
label: 'Read & Write',
|
||||
data: format(values),
|
||||
pointRadius: 0,
|
||||
data: format(values) as any,
|
||||
borderWidth: 0,
|
||||
borderJoinStyle: 'round',
|
||||
borderRadius: 3,
|
||||
backgroundColor(c) {
|
||||
const value = c.dataset.data[c.dataIndex].v;
|
||||
// @ts-expect-error TS(2339)
|
||||
const value = c.dataset.data[c.dataIndex].v as number;
|
||||
let a = (value - min) / max;
|
||||
if (value !== 0) { // 0でない限りは完全に不可視にはしない
|
||||
a = Math.max(a, 0.05);
|
||||
}
|
||||
return alpha(color, a);
|
||||
},
|
||||
fill: true,
|
||||
width(c) {
|
||||
const a = c.chart.chartArea ?? {};
|
||||
return (a.right - a.left) / weeks - marginEachCell;
|
||||
|
@ -190,11 +189,13 @@ async function renderChart() {
|
|||
enabled: false,
|
||||
callbacks: {
|
||||
title(context) {
|
||||
const v = context[0].dataset.data[context[0].dataIndex];
|
||||
return v.d;
|
||||
// @ts-expect-error TS(2339)
|
||||
return context[0].dataset.data[context[0].dataIndex].d;
|
||||
},
|
||||
label(context) {
|
||||
const v = context.dataset.data[context.dataIndex];
|
||||
|
||||
// @ts-expect-error TS(2339)
|
||||
return ['Active: ' + v.v];
|
||||
},
|
||||
},
|
||||
|
|
|
@ -138,7 +138,8 @@ function createDoughnut(chartEl, tooltip, data) {
|
|||
},
|
||||
},
|
||||
onClick: (ev) => {
|
||||
const hit = chartInstance.getElementsAtEventForMode(ev, 'nearest', { intersect: true }, false)[0];
|
||||
if (!ev.native) return;
|
||||
const hit = chartInstance.getElementsAtEventForMode(ev.native, 'nearest', { intersect: true }, false)[0];
|
||||
if (hit && data[hit.index].onClick) {
|
||||
data[hit.index].onClick();
|
||||
}
|
||||
|
@ -164,23 +165,46 @@ function createDoughnut(chartEl, tooltip, data) {
|
|||
|
||||
onMounted(() => {
|
||||
misskeyApiGet('federation/stats', { limit: 30 }).then(fedStats => {
|
||||
createDoughnut(subDoughnutEl.value, externalTooltipHandler1, fedStats.topSubInstances.map(x => ({
|
||||
type ChartData = {
|
||||
name: string,
|
||||
color: string | null,
|
||||
value: number,
|
||||
onClick?: () => void,
|
||||
}[];
|
||||
|
||||
const subs: ChartData = fedStats.topSubInstances.map(x => ({
|
||||
name: x.host,
|
||||
color: x.themeColor,
|
||||
value: x.followersCount,
|
||||
onClick: () => {
|
||||
os.pageWindow(`/instance-info/${x.host}`);
|
||||
},
|
||||
})).concat([{ name: '(other)', color: '#80808080', value: fedStats.otherFollowersCount }]));
|
||||
}));
|
||||
|
||||
createDoughnut(pubDoughnutEl.value, externalTooltipHandler2, fedStats.topPubInstances.map(x => ({
|
||||
subs.push({
|
||||
name: '(other)',
|
||||
color: '#80808080',
|
||||
value: fedStats.otherFollowersCount,
|
||||
});
|
||||
|
||||
createDoughnut(subDoughnutEl.value, externalTooltipHandler1, subs);
|
||||
|
||||
const pubs: ChartData = fedStats.topPubInstances.map(x => ({
|
||||
name: x.host,
|
||||
color: x.themeColor,
|
||||
value: x.followingCount,
|
||||
onClick: () => {
|
||||
os.pageWindow(`/instance-info/${x.host}`);
|
||||
},
|
||||
})).concat([{ name: '(other)', color: '#80808080', value: fedStats.otherFollowingCount }]));
|
||||
}));
|
||||
|
||||
pubs.push({
|
||||
name: '(other)',
|
||||
color: '#80808080',
|
||||
value: fedStats.otherFollowingCount,
|
||||
});
|
||||
|
||||
createDoughnut(pubDoughnutEl.value, externalTooltipHandler2, pubs);
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -30,7 +30,7 @@ const instance = props.instance ?? {
|
|||
themeColor: (document.querySelector('meta[name="theme-color-orig"]') as HTMLMetaElement).content,
|
||||
};
|
||||
|
||||
const faviconUrl = computed(() => props.instance ? getProxiedImageUrlNullable(props.instance.faviconUrl, 'preview') : getProxiedImageUrlNullable(Instance.iconUrl, 'preview') ?? getProxiedImageUrlNullable(Instance.faviconUrl, 'preview') ?? '/favicon.ico');
|
||||
const faviconUrl = computed(() => props.instance ? getProxiedImageUrlNullable(props.instance.faviconUrl, 'preview') : getProxiedImageUrlNullable(Instance.iconUrl, 'preview') ?? '/favicon.ico');
|
||||
|
||||
const themeColor = instance.themeColor ?? '#777777';
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
-->
|
||||
|
||||
<template>
|
||||
<MkModal ref="modal" v-slot="{ type, maxHeight }" :preferType="preferedModalType" :anchor="anchor" :transparentBg="true" :src="src" @click="modal.close()" @closed="emit('closed')">
|
||||
<MkModal ref="modal" v-slot="{ type, maxHeight }" :preferType="preferedModalType" :anchor="anchor" :transparentBg="true" :src="src" @click="modal?.close()" @closed="emit('closed')">
|
||||
<div class="szkkfdyq _popup _shadow" :class="{ asDrawer: type === 'drawer' }" :style="{ maxHeight: maxHeight ? maxHeight + 'px' : '' }">
|
||||
<div class="main">
|
||||
<template v-for="item in items" :key="item.text">
|
||||
|
@ -63,7 +63,7 @@ const items = Object.keys(navbarItemDef).filter(k => !menu.includes(k)).map(k =>
|
|||
}));
|
||||
|
||||
function close() {
|
||||
modal.value.close();
|
||||
modal.value?.close();
|
||||
}
|
||||
</script>
|
||||
|
||||
|
|
|
@ -30,6 +30,7 @@ export default {
|
|||
const contentEl = ref<HTMLElement>();
|
||||
|
||||
function calc() {
|
||||
if (!contentEl.value) return;
|
||||
const eachLength = contentEl.value.offsetWidth / props.repeat;
|
||||
const factor = 3000;
|
||||
const duration = props.duration / ((1 / eachLength) * factor);
|
||||
|
|
|
@ -21,7 +21,7 @@ import { host as hostRaw } from '@/config.js';
|
|||
import { defaultStore } from '@/store.js';
|
||||
|
||||
defineProps<{
|
||||
user: Misskey.entities.UserDetailed;
|
||||
user: Misskey.entities.User;
|
||||
detail?: boolean;
|
||||
}>();
|
||||
|
||||
|
|
Loading…
Reference in New Issue