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);">
|
<section v-else v-panel style="border-radius: 6px; border-bottom: 0.5px solid var(--divider);">
|
||||||
<header class="_acrylic" @click="shown = !shown">
|
<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>
|
</header>
|
||||||
<div v-if="shown" style="padding-left: 9px;">
|
<div v-if="shown" style="padding-left: 9px;">
|
||||||
<MkEmojiPickerSection
|
<MkEmojiPickerSection
|
||||||
|
@ -61,7 +61,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref, computed, Ref } from 'vue';
|
import { ref, computed, Ref } from 'vue';
|
||||||
import { CustomEmojiFolderTree, getEmojiName } from '@/scripts/emojilist.js';
|
import { CustomEmojiFolderTree, getEmojiName } from '@/scripts/emojilist.js';
|
||||||
import { i18n } from '../i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { customEmojis } from '@/custom-emojis.js';
|
import { customEmojis } from '@/custom-emojis.js';
|
||||||
import MkEmojiPickerSection from '@/components/MkEmojiPicker.section.vue';
|
import MkEmojiPickerSection from '@/components/MkEmojiPicker.section.vue';
|
||||||
|
|
||||||
|
@ -87,7 +87,7 @@ function computeButtonTitle(ev: MouseEvent): void {
|
||||||
elm.title = getEmojiName(emoji) ?? emoji;
|
elm.title = getEmojiName(emoji) ?? emoji;
|
||||||
}
|
}
|
||||||
|
|
||||||
function nestedChosen(emoji: any, ev?: MouseEvent) {
|
function nestedChosen(emoji: any, ev: MouseEvent) {
|
||||||
emit('chosen', emoji, ev);
|
emit('chosen', emoji, ev);
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -36,7 +36,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<div v-if="tab === 'index'" class="group index">
|
<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">
|
<div class="body">
|
||||||
<button
|
<button
|
||||||
v-for="emoji in pinned"
|
v-for="emoji in pinned"
|
||||||
|
@ -327,7 +327,7 @@ watch(q, () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
function filterAvailable(emoji: Misskey.entities.EmojiSimple): boolean {
|
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() {
|
function focus() {
|
||||||
|
|
|
@ -11,7 +11,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
:withOkButton="true"
|
:withOkButton="true"
|
||||||
:okButtonDisabled="false"
|
:okButtonDisabled="false"
|
||||||
@ok="ok()"
|
@ok="ok()"
|
||||||
@close="dialog.close()"
|
@close="dialog?.close()"
|
||||||
@closed="emit('closed')"
|
@closed="emit('closed')"
|
||||||
>
|
>
|
||||||
<template #header>{{ i18n.ts.describeFile }}</template>
|
<template #header>{{ i18n.ts.describeFile }}</template>
|
||||||
|
@ -48,6 +48,6 @@ const caption = ref(props.default);
|
||||||
|
|
||||||
async function ok() {
|
async function ok() {
|
||||||
emit('done', caption.value);
|
emit('done', caption.value);
|
||||||
dialog.value.close();
|
dialog.value?.close();
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -7,7 +7,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<div>
|
<div>
|
||||||
<MkPagination v-slot="{items}" :pagination="pagination" class="urempief" :class="{ grid: viewMode === 'grid' }">
|
<MkPagination v-slot="{items}" :pagination="pagination" class="urempief" :class="{ grid: viewMode === 'grid' }">
|
||||||
<MkA
|
<MkA
|
||||||
v-for="file in items"
|
v-for="file in (items as Misskey.entities.DriveFile[])"
|
||||||
:key="file.id"
|
: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'}`"
|
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}`"
|
:to="`/admin/file/${file.id}`"
|
||||||
|
|
|
@ -4,7 +4,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<template>
|
<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">
|
<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.title"><div><slot name="header"></slot></div></div>
|
||||||
<div :class="$style.divider"></div>
|
<div :class="$style.divider"></div>
|
||||||
|
@ -42,8 +42,8 @@ const props = withDefaults(defineProps<{
|
||||||
expanded: true,
|
expanded: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
const el = shallowRef<HTMLDivElement>();
|
const div = shallowRef<HTMLDivElement>();
|
||||||
const bg = ref<string | null>(null);
|
const bg = ref<string>();
|
||||||
const showBody = ref((props.persistKey && miLocalStorage.getItem(`${miLocalStoragePrefix}${props.persistKey}`)) ? (miLocalStorage.getItem(`${miLocalStoragePrefix}${props.persistKey}`) === 't') : props.expanded);
|
const showBody = ref((props.persistKey && miLocalStorage.getItem(`${miLocalStoragePrefix}${props.persistKey}`)) ? (miLocalStorage.getItem(`${miLocalStoragePrefix}${props.persistKey}`) === 't') : props.expanded);
|
||||||
|
|
||||||
watch(showBody, () => {
|
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;
|
const elementHeight = el.getBoundingClientRect().height;
|
||||||
el.style.height = 0;
|
el.style.height = 'unset';
|
||||||
el.offsetHeight; // reflow
|
el.offsetHeight; // reflow
|
||||||
el.style.height = elementHeight + 'px';
|
el.style.height = elementHeight + 'px';
|
||||||
}
|
}
|
||||||
|
|
||||||
function afterEnter(el: Element) {
|
function afterEnter(element: Element) {
|
||||||
el.style.height = null;
|
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;
|
const elementHeight = el.getBoundingClientRect().height;
|
||||||
el.style.height = elementHeight + 'px';
|
el.style.height = elementHeight + 'px';
|
||||||
el.offsetHeight; // reflow
|
el.offsetHeight; // reflow
|
||||||
el.style.height = 0;
|
el.style.height = '0';
|
||||||
}
|
}
|
||||||
|
|
||||||
function afterLeave(el: Element) {
|
function afterLeave(element: Element) {
|
||||||
el.style.height = null;
|
const el = element as HTMLElement;
|
||||||
|
el.style.height = 'unset';
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
function getParentBg(el: HTMLElement | null): string {
|
function getParentBg(el?: HTMLElement | null): string {
|
||||||
if (el == null || el.tagName === 'BODY') return 'var(--bg)';
|
if (el == null || el.tagName === 'BODY') return 'var(--bg)';
|
||||||
const bg = el.style.background || el.style.backgroundColor;
|
const background = el.style.background || el.style.backgroundColor;
|
||||||
if (bg) {
|
if (background) {
|
||||||
return bg;
|
return background;
|
||||||
} else {
|
} else {
|
||||||
return getParentBg(el.parentElement);
|
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);
|
const _bg = tinycolor(rawBg.startsWith('var(') ? getComputedStyle(document.documentElement).getPropertyValue(rawBg.slice(4, -1)) : rawBg);
|
||||||
_bg.setAlpha(0.85);
|
_bg.setAlpha(0.85);
|
||||||
bg.value = _bg.toRgbString();
|
bg.value = _bg.toRgbString();
|
||||||
|
|
|
@ -25,7 +25,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</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
|
<Transition
|
||||||
:enterActiveClass="defaultStore.state.animation ? $style.transition_toggle_enterActive : ''"
|
:enterActiveClass="defaultStore.state.animation ? $style.transition_toggle_enterActive : ''"
|
||||||
:leaveActiveClass="defaultStore.state.animation ? $style.transition_toggle_leaveActive : ''"
|
:leaveActiveClass="defaultStore.state.animation ? $style.transition_toggle_leaveActive : ''"
|
||||||
|
@ -109,7 +109,7 @@ function toggle() {
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
const computedStyle = getComputedStyle(document.documentElement);
|
const computedStyle = getComputedStyle(document.documentElement);
|
||||||
const parentBg = getBgColor(rootEl.value.parentElement);
|
const parentBg = getBgColor(rootEl.value!.parentElement!);
|
||||||
const myBg = computedStyle.getPropertyValue('--panel');
|
const myBg = computedStyle.getPropertyValue('--panel');
|
||||||
bgSame.value = parentBg === myBg;
|
bgSame.value = parentBg === myBg;
|
||||||
});
|
});
|
||||||
|
|
|
@ -111,6 +111,7 @@ async function onClick() {
|
||||||
|
|
||||||
claimAchievement('following1');
|
claimAchievement('following1');
|
||||||
|
|
||||||
|
if ($i) {
|
||||||
if ($i.followingCount >= 10) {
|
if ($i.followingCount >= 10) {
|
||||||
claimAchievement('following10');
|
claimAchievement('following10');
|
||||||
}
|
}
|
||||||
|
@ -125,6 +126,7 @@ async function onClick() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
} finally {
|
} finally {
|
||||||
|
|
|
@ -8,7 +8,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
ref="dialog"
|
ref="dialog"
|
||||||
:width="370"
|
:width="370"
|
||||||
:height="400"
|
:height="400"
|
||||||
@close="dialog.close()"
|
@close="dialog?.close()"
|
||||||
@closed="emit('closed')"
|
@closed="emit('closed')"
|
||||||
>
|
>
|
||||||
<template #header>{{ i18n.ts.forgotPassword }}</template>
|
<template #header>{{ i18n.ts.forgotPassword }}</template>
|
||||||
|
@ -66,6 +66,6 @@ async function onSubmit() {
|
||||||
email: email.value,
|
email: email.value,
|
||||||
});
|
});
|
||||||
emit('done');
|
emit('done');
|
||||||
dialog.value.close();
|
dialog.value?.close();
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -40,11 +40,11 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</MkSwitch>
|
</MkSwitch>
|
||||||
<MkSelect v-else-if="form[item].type === 'enum'" v-model="values[item]">
|
<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>
|
<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>
|
</MkSelect>
|
||||||
<MkRadios v-else-if="form[item].type === 'radio'" v-model="values[item]">
|
<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>
|
<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>
|
</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">
|
<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>
|
<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;
|
canceled?: boolean;
|
||||||
result?: any;
|
result?: any;
|
||||||
}): void;
|
}): void;
|
||||||
|
(ev: 'closed'): void;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const dialog = shallowRef<InstanceType<typeof MkModalWindow>>();
|
const dialog = shallowRef<InstanceType<typeof MkModalWindow>>();
|
||||||
|
@ -99,13 +100,13 @@ function ok() {
|
||||||
emit('done', {
|
emit('done', {
|
||||||
result: values,
|
result: values,
|
||||||
});
|
});
|
||||||
dialog.value.close();
|
dialog.value?.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
function cancel() {
|
function cancel() {
|
||||||
emit('done', {
|
emit('done', {
|
||||||
canceled: true,
|
canceled: true,
|
||||||
});
|
});
|
||||||
dialog.value.close();
|
dialog.value?.close();
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -14,8 +14,8 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
leaveActiveClass: $style.transition_toggle_leaveActive,
|
leaveActiveClass: $style.transition_toggle_leaveActive,
|
||||||
leaveToClass: $style.transition_toggle_leaveTo,
|
leaveToClass: $style.transition_toggle_leaveTo,
|
||||||
}"
|
}"
|
||||||
:src="post.files[0].thumbnailUrl"
|
:src="post.files?.[0]?.thumbnailUrl"
|
||||||
:hash="post.files[0].blurhash"
|
:hash="post.files?.[0]?.blurhash"
|
||||||
:forceBlurhash="!show"
|
:forceBlurhash="!show"
|
||||||
/>
|
/>
|
||||||
</Transition>
|
</Transition>
|
||||||
|
|
|
@ -27,10 +27,10 @@ const props = defineProps<{
|
||||||
src: string;
|
src: string;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const rootEl = shallowRef<HTMLDivElement>(null);
|
const rootEl = shallowRef<HTMLDivElement | null>(null);
|
||||||
const chartEl = shallowRef<HTMLCanvasElement>(null);
|
const chartEl = shallowRef<HTMLCanvasElement | null>(null);
|
||||||
const now = new Date();
|
const now = new Date();
|
||||||
let chartInstance: Chart = null;
|
let chartInstance: Chart | null = null;
|
||||||
const fetching = ref(true);
|
const fetching = ref(true);
|
||||||
|
|
||||||
const { handler: externalTooltipHandler } = useChartTooltip({
|
const { handler: externalTooltipHandler } = useChartTooltip({
|
||||||
|
@ -38,6 +38,7 @@ const { handler: externalTooltipHandler } = useChartTooltip({
|
||||||
});
|
});
|
||||||
|
|
||||||
async function renderChart() {
|
async function renderChart() {
|
||||||
|
if (!rootEl.value || !chartEl.value) return;
|
||||||
if (chartInstance) {
|
if (chartInstance) {
|
||||||
chartInstance.destroy();
|
chartInstance.destroy();
|
||||||
}
|
}
|
||||||
|
@ -56,7 +57,7 @@ async function renderChart() {
|
||||||
return new Date(y, m, d - ago);
|
return new Date(y, m, d - ago);
|
||||||
};
|
};
|
||||||
|
|
||||||
const format = (arr) => {
|
const format = (arr: number[]) => {
|
||||||
return arr.map((v, i) => {
|
return arr.map((v, i) => {
|
||||||
const dt = getDate(i);
|
const dt = getDate(i);
|
||||||
const iso = `${dt.getFullYear()}-${(dt.getMonth() + 1).toString().padStart(2, '0')}-${dt.getDate().toString().padStart(2, '0')}`;
|
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') {
|
if (props.src === 'active-users') {
|
||||||
const raw = await misskeyApi('charts/active-users', { limit: chartLimit, span: 'day' });
|
const raw = await misskeyApi('charts/active-users', { limit: chartLimit, span: 'day' });
|
||||||
|
@ -106,20 +107,18 @@ async function renderChart() {
|
||||||
data: {
|
data: {
|
||||||
datasets: [{
|
datasets: [{
|
||||||
label: 'Read & Write',
|
label: 'Read & Write',
|
||||||
data: format(values),
|
data: format(values) as any,
|
||||||
pointRadius: 0,
|
|
||||||
borderWidth: 0,
|
borderWidth: 0,
|
||||||
borderJoinStyle: 'round',
|
|
||||||
borderRadius: 3,
|
borderRadius: 3,
|
||||||
backgroundColor(c) {
|
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;
|
let a = (value - min) / max;
|
||||||
if (value !== 0) { // 0でない限りは完全に不可視にはしない
|
if (value !== 0) { // 0でない限りは完全に不可視にはしない
|
||||||
a = Math.max(a, 0.05);
|
a = Math.max(a, 0.05);
|
||||||
}
|
}
|
||||||
return alpha(color, a);
|
return alpha(color, a);
|
||||||
},
|
},
|
||||||
fill: true,
|
|
||||||
width(c) {
|
width(c) {
|
||||||
const a = c.chart.chartArea ?? {};
|
const a = c.chart.chartArea ?? {};
|
||||||
return (a.right - a.left) / weeks - marginEachCell;
|
return (a.right - a.left) / weeks - marginEachCell;
|
||||||
|
@ -190,11 +189,13 @@ async function renderChart() {
|
||||||
enabled: false,
|
enabled: false,
|
||||||
callbacks: {
|
callbacks: {
|
||||||
title(context) {
|
title(context) {
|
||||||
const v = context[0].dataset.data[context[0].dataIndex];
|
// @ts-expect-error TS(2339)
|
||||||
return v.d;
|
return context[0].dataset.data[context[0].dataIndex].d;
|
||||||
},
|
},
|
||||||
label(context) {
|
label(context) {
|
||||||
const v = context.dataset.data[context.dataIndex];
|
const v = context.dataset.data[context.dataIndex];
|
||||||
|
|
||||||
|
// @ts-expect-error TS(2339)
|
||||||
return ['Active: ' + v.v];
|
return ['Active: ' + v.v];
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -138,7 +138,8 @@ function createDoughnut(chartEl, tooltip, data) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
onClick: (ev) => {
|
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) {
|
if (hit && data[hit.index].onClick) {
|
||||||
data[hit.index].onClick();
|
data[hit.index].onClick();
|
||||||
}
|
}
|
||||||
|
@ -164,23 +165,46 @@ function createDoughnut(chartEl, tooltip, data) {
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
misskeyApiGet('federation/stats', { limit: 30 }).then(fedStats => {
|
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,
|
name: x.host,
|
||||||
color: x.themeColor,
|
color: x.themeColor,
|
||||||
value: x.followersCount,
|
value: x.followersCount,
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
os.pageWindow(`/instance-info/${x.host}`);
|
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,
|
name: x.host,
|
||||||
color: x.themeColor,
|
color: x.themeColor,
|
||||||
value: x.followingCount,
|
value: x.followingCount,
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
os.pageWindow(`/instance-info/${x.host}`);
|
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>
|
</script>
|
||||||
|
|
|
@ -30,7 +30,7 @@ const instance = props.instance ?? {
|
||||||
themeColor: (document.querySelector('meta[name="theme-color-orig"]') as HTMLMetaElement).content,
|
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';
|
const themeColor = instance.themeColor ?? '#777777';
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<template>
|
<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="szkkfdyq _popup _shadow" :class="{ asDrawer: type === 'drawer' }" :style="{ maxHeight: maxHeight ? maxHeight + 'px' : '' }">
|
||||||
<div class="main">
|
<div class="main">
|
||||||
<template v-for="item in items" :key="item.text">
|
<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() {
|
function close() {
|
||||||
modal.value.close();
|
modal.value?.close();
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -30,6 +30,7 @@ export default {
|
||||||
const contentEl = ref<HTMLElement>();
|
const contentEl = ref<HTMLElement>();
|
||||||
|
|
||||||
function calc() {
|
function calc() {
|
||||||
|
if (!contentEl.value) return;
|
||||||
const eachLength = contentEl.value.offsetWidth / props.repeat;
|
const eachLength = contentEl.value.offsetWidth / props.repeat;
|
||||||
const factor = 3000;
|
const factor = 3000;
|
||||||
const duration = props.duration / ((1 / eachLength) * factor);
|
const duration = props.duration / ((1 / eachLength) * factor);
|
||||||
|
|
|
@ -21,7 +21,7 @@ import { host as hostRaw } from '@/config.js';
|
||||||
import { defaultStore } from '@/store.js';
|
import { defaultStore } from '@/store.js';
|
||||||
|
|
||||||
defineProps<{
|
defineProps<{
|
||||||
user: Misskey.entities.UserDetailed;
|
user: Misskey.entities.User;
|
||||||
detail?: boolean;
|
detail?: boolean;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue