summaryrefslogtreecommitdiff
path: root/packages/client/src
diff options
context:
space:
mode:
authorsyuilo <Syuilotan@yahoo.co.jp>2022-06-26 03:12:58 +0900
committersyuilo <Syuilotan@yahoo.co.jp>2022-06-26 03:12:58 +0900
commit5e95a1f7af841f10646133ad0cc155a2c5cea9fd (patch)
tree6aacbbdca450e7a0ae54e7040147395c934e787b /packages/client/src
parentenhance(client): tweak control panel dashboard (diff)
downloadsharkey-5e95a1f7af841f10646133ad0cc155a2c5cea9fd.tar.gz
sharkey-5e95a1f7af841f10646133ad0cc155a2c5cea9fd.tar.bz2
sharkey-5e95a1f7af841f10646133ad0cc155a2c5cea9fd.zip
refactor(client): extract interval logic to a composable function
あと`onUnmounted`を`onMounted`内で呼んでいたりしたのを修正したりとか
Diffstat (limited to 'packages/client/src')
-rw-r--r--packages/client/src/components/form/input.vue73
-rw-r--r--packages/client/src/components/form/range.vue24
-rw-r--r--packages/client/src/components/form/select.vue57
-rw-r--r--packages/client/src/components/global/time.vue18
-rw-r--r--packages/client/src/components/mini-chart.vue8
-rw-r--r--packages/client/src/components/notification.vue17
-rw-r--r--packages/client/src/components/notifications.vue10
-rw-r--r--packages/client/src/components/poll.vue14
-rw-r--r--packages/client/src/components/sparkle.vue17
-rw-r--r--packages/client/src/pages/admin/overview.federation.vue13
-rw-r--r--packages/client/src/scripts/use-interval.ts22
-rw-r--r--packages/client/src/widgets/aichan.vue31
-rw-r--r--packages/client/src/widgets/calendar.vue25
-rw-r--r--packages/client/src/widgets/federation.vue10
-rw-r--r--packages/client/src/widgets/online-users.vue12
-rw-r--r--packages/client/src/widgets/rss.vue12
-rw-r--r--packages/client/src/widgets/slideshow.vue15
-rw-r--r--packages/client/src/widgets/trends.vue12
18 files changed, 207 insertions, 183 deletions
diff --git a/packages/client/src/components/form/input.vue b/packages/client/src/components/form/input.vue
index 7165671af3..5065e28892 100644
--- a/packages/client/src/components/form/input.vue
+++ b/packages/client/src/components/form/input.vue
@@ -3,7 +3,8 @@
<div class="label" @click="focus"><slot name="label"></slot></div>
<div class="input" :class="{ inline, disabled, focused }">
<div ref="prefixEl" class="prefix"><slot name="prefix"></slot></div>
- <input ref="inputEl"
+ <input
+ ref="inputEl"
v-model="v"
v-adaptive-border
:type="type"
@@ -34,8 +35,9 @@
<script lang="ts">
import { defineComponent, onMounted, onUnmounted, nextTick, ref, watch, computed, toRefs } from 'vue';
-import MkButton from '@/components/ui/button.vue';
import { debounce } from 'throttle-debounce';
+import MkButton from '@/components/ui/button.vue';
+import { useInterval } from '@/scripts/use-interval';
export default defineComponent({
components: {
@@ -44,45 +46,45 @@ export default defineComponent({
props: {
modelValue: {
- required: true
+ required: true,
},
type: {
type: String,
- required: false
+ required: false,
},
required: {
type: Boolean,
- required: false
+ required: false,
},
readonly: {
type: Boolean,
- required: false
+ required: false,
},
disabled: {
type: Boolean,
- required: false
+ required: false,
},
pattern: {
type: String,
- required: false
+ required: false,
},
placeholder: {
type: String,
- required: false
+ required: false,
},
autofocus: {
type: Boolean,
required: false,
- default: false
+ default: false,
},
autocomplete: {
- required: false
+ required: false,
},
spellcheck: {
- required: false
+ required: false,
},
step: {
- required: false
+ required: false,
},
datalist: {
type: Array,
@@ -91,17 +93,17 @@ export default defineComponent({
inline: {
type: Boolean,
required: false,
- default: false
+ default: false,
},
debounce: {
type: Boolean,
required: false,
- default: false
+ default: false,
},
manualSave: {
type: Boolean,
required: false,
- default: false
+ default: false,
},
},
@@ -134,7 +136,7 @@ export default defineComponent({
const updated = () => {
changed.value = false;
- if (type?.value === 'number') {
+ if (type.value === 'number') {
context.emit('update:modelValue', parseFloat(v.value));
} else {
context.emit('update:modelValue', v.value);
@@ -159,30 +161,29 @@ export default defineComponent({
invalid.value = inputEl.value.validity.badInput;
});
+ // このコンポーネントが作成された時、非表示状態である場合がある
+ // 非表示状態だと要素の幅などは0になってしまうので、定期的に計算する
+ useInterval(() => {
+ if (prefixEl.value) {
+ if (prefixEl.value.offsetWidth) {
+ inputEl.value.style.paddingLeft = prefixEl.value.offsetWidth + 'px';
+ }
+ }
+ if (suffixEl.value) {
+ if (suffixEl.value.offsetWidth) {
+ inputEl.value.style.paddingRight = suffixEl.value.offsetWidth + 'px';
+ }
+ }
+ }, 100, {
+ immediate: true,
+ afterMounted: true,
+ });
+
onMounted(() => {
nextTick(() => {
if (autofocus.value) {
focus();
}
-
- // このコンポーネントが作成された時、非表示状態である場合がある
- // 非表示状態だと要素の幅などは0になってしまうので、定期的に計算する
- const clock = window.setInterval(() => {
- if (prefixEl.value) {
- if (prefixEl.value.offsetWidth) {
- inputEl.value.style.paddingLeft = prefixEl.value.offsetWidth + 'px';
- }
- }
- if (suffixEl.value) {
- if (suffixEl.value.offsetWidth) {
- inputEl.value.style.paddingRight = suffixEl.value.offsetWidth + 'px';
- }
- }
- }, 100);
-
- onUnmounted(() => {
- window.clearInterval(clock);
- });
});
});
diff --git a/packages/client/src/components/form/range.vue b/packages/client/src/components/form/range.vue
index 9bf7651119..221ad029a7 100644
--- a/packages/client/src/components/form/range.vue
+++ b/packages/client/src/components/form/range.vue
@@ -24,31 +24,31 @@ export default defineComponent({
modelValue: {
type: Number,
required: false,
- default: 0
+ default: 0,
},
disabled: {
type: Boolean,
required: false,
- default: false
+ default: false,
},
min: {
type: Number,
required: false,
- default: 0
+ default: 0,
},
max: {
type: Number,
required: false,
- default: 100
+ default: 100,
},
step: {
type: Number,
required: false,
- default: 1
+ default: 1,
},
autofocus: {
type: Boolean,
- required: false
+ required: false,
},
textConverter: {
type: Function,
@@ -90,14 +90,18 @@ export default defineComponent({
}
};
watch([steppedValue, containerEl], calcThumbPosition);
+
+ let ro: ResizeObserver | undefined;
+
onMounted(() => {
- const ro = new ResizeObserver((entries, observer) => {
+ ro = new ResizeObserver((entries, observer) => {
calcThumbPosition();
});
ro.observe(containerEl.value);
- onUnmounted(() => {
- ro.disconnect();
- });
+ });
+
+ onUnmounted(() => {
+ if (ro) ro.disconnect();
});
const steps = computed(() => {
diff --git a/packages/client/src/components/form/select.vue b/packages/client/src/components/form/select.vue
index 87196027a8..7f5f8784b6 100644
--- a/packages/client/src/components/form/select.vue
+++ b/packages/client/src/components/form/select.vue
@@ -3,7 +3,8 @@
<div class="label" @click="focus"><slot name="label"></slot></div>
<div ref="container" class="input" :class="{ inline, disabled, focused }" @click.prevent="onClick">
<div ref="prefixEl" class="prefix"><slot name="prefix"></slot></div>
- <select ref="inputEl"
+ <select
+ ref="inputEl"
v-model="v"
v-adaptive-border
class="select"
@@ -29,6 +30,7 @@
import { defineComponent, onMounted, onUnmounted, nextTick, ref, watch, computed, toRefs, VNode } from 'vue';
import MkButton from '@/components/ui/button.vue';
import * as os from '@/os';
+import { useInterval } from '@/scripts/use-interval';
export default defineComponent({
components: {
@@ -37,38 +39,38 @@ export default defineComponent({
props: {
modelValue: {
- required: true
+ required: true,
},
required: {
type: Boolean,
- required: false
+ required: false,
},
readonly: {
type: Boolean,
- required: false
+ required: false,
},
disabled: {
type: Boolean,
- required: false
+ required: false,
},
placeholder: {
type: String,
- required: false
+ required: false,
},
autofocus: {
type: Boolean,
required: false,
- default: false
+ default: false,
},
inline: {
type: Boolean,
required: false,
- default: false
+ default: false,
},
manualSave: {
type: Boolean,
required: false,
- default: false
+ default: false,
},
},
@@ -109,30 +111,29 @@ export default defineComponent({
invalid.value = inputEl.value.validity.badInput;
});
+ // このコンポーネントが作成された時、非表示状態である場合がある
+ // 非表示状態だと要素の幅などは0になってしまうので、定期的に計算する
+ useInterval(() => {
+ if (prefixEl.value) {
+ if (prefixEl.value.offsetWidth) {
+ inputEl.value.style.paddingLeft = prefixEl.value.offsetWidth + 'px';
+ }
+ }
+ if (suffixEl.value) {
+ if (suffixEl.value.offsetWidth) {
+ inputEl.value.style.paddingRight = suffixEl.value.offsetWidth + 'px';
+ }
+ }
+ }, 100, {
+ immediate: true,
+ afterMounted: true,
+ });
+
onMounted(() => {
nextTick(() => {
if (autofocus.value) {
focus();
}
-
- // このコンポーネントが作成された時、非表示状態である場合がある
- // 非表示状態だと要素の幅などは0になってしまうので、定期的に計算する
- const clock = window.setInterval(() => {
- if (prefixEl.value) {
- if (prefixEl.value.offsetWidth) {
- inputEl.value.style.paddingLeft = prefixEl.value.offsetWidth + 'px';
- }
- }
- if (suffixEl.value) {
- if (suffixEl.value.offsetWidth) {
- inputEl.value.style.paddingRight = suffixEl.value.offsetWidth + 'px';
- }
- }
- }, 100);
-
- onUnmounted(() => {
- window.clearInterval(clock);
- });
});
});
diff --git a/packages/client/src/components/global/time.vue b/packages/client/src/components/global/time.vue
index a7f142f961..801490225b 100644
--- a/packages/client/src/components/global/time.vue
+++ b/packages/client/src/components/global/time.vue
@@ -24,14 +24,14 @@ let now = $ref(new Date());
const relative = $computed(() => {
const ago = (now.getTime() - _time.getTime()) / 1000/*ms*/;
return (
- ago >= 31536000 ? i18n.t('_ago.yearsAgo', { n: Math.round(ago / 31536000).toString() }) :
- ago >= 2592000 ? i18n.t('_ago.monthsAgo', { n: Math.round(ago / 2592000).toString() }) :
- ago >= 604800 ? i18n.t('_ago.weeksAgo', { n: Math.round(ago / 604800).toString() }) :
- ago >= 86400 ? i18n.t('_ago.daysAgo', { n: Math.round(ago / 86400).toString() }) :
- ago >= 3600 ? i18n.t('_ago.hoursAgo', { n: Math.round(ago / 3600).toString() }) :
- ago >= 60 ? i18n.t('_ago.minutesAgo', { n: (~~(ago / 60)).toString() }) :
- ago >= 10 ? i18n.t('_ago.secondsAgo', { n: (~~(ago % 60)).toString() }) :
- ago >= -1 ? i18n.ts._ago.justNow :
+ ago >= 31536000 ? i18n.t('_ago.yearsAgo', { n: Math.round(ago / 31536000).toString() }) :
+ ago >= 2592000 ? i18n.t('_ago.monthsAgo', { n: Math.round(ago / 2592000).toString() }) :
+ ago >= 604800 ? i18n.t('_ago.weeksAgo', { n: Math.round(ago / 604800).toString() }) :
+ ago >= 86400 ? i18n.t('_ago.daysAgo', { n: Math.round(ago / 86400).toString() }) :
+ ago >= 3600 ? i18n.t('_ago.hoursAgo', { n: Math.round(ago / 3600).toString() }) :
+ ago >= 60 ? i18n.t('_ago.minutesAgo', { n: (~~(ago / 60)).toString() }) :
+ ago >= 10 ? i18n.t('_ago.secondsAgo', { n: (~~(ago % 60)).toString() }) :
+ ago >= -1 ? i18n.ts._ago.justNow :
i18n.ts._ago.future);
});
@@ -50,7 +50,7 @@ if (props.mode === 'relative' || props.mode === 'detail') {
tickId = window.requestAnimationFrame(tick);
onUnmounted(() => {
- window.clearTimeout(tickId);
+ window.cancelAnimationFrame(tickId);
});
}
</script>
diff --git a/packages/client/src/components/mini-chart.vue b/packages/client/src/components/mini-chart.vue
index 5e842b1975..c64ce163f9 100644
--- a/packages/client/src/components/mini-chart.vue
+++ b/packages/client/src/components/mini-chart.vue
@@ -29,6 +29,7 @@
import { onUnmounted, watch } from 'vue';
import { v4 as uuid } from 'uuid';
import tinycolor from 'tinycolor2';
+import { useInterval } from '@/scripts/use-interval';
const props = defineProps<{
src: number[];
@@ -65,9 +66,8 @@ function draw(): void {
watch(() => props.src, draw, { immediate: true });
// Vueが何故かWatchを発動させない場合があるので
-clock = window.setInterval(draw, 1000);
-
-onUnmounted(() => {
- window.clearInterval(clock);
+useInterval(draw, 1000, {
+ immediate: false,
+ afterMounted: true,
});
</script>
diff --git a/packages/client/src/components/notification.vue b/packages/client/src/components/notification.vue
index cbfd809f37..26fbeecb68 100644
--- a/packages/client/src/components/notification.vue
+++ b/packages/client/src/components/notification.vue
@@ -112,9 +112,12 @@ export default defineComponent({
const elRef = ref<HTMLElement>(null);
const reactionRef = ref(null);
+ let readObserver: IntersectionObserver | undefined;
+ let connection;
+
onMounted(() => {
if (!props.notification.isRead) {
- const readObserver = new IntersectionObserver((entries, observer) => {
+ readObserver = new IntersectionObserver((entries, observer) => {
if (!entries.some(entry => entry.isIntersecting)) return;
stream.send('readNotification', {
id: props.notification.id,
@@ -124,19 +127,19 @@ export default defineComponent({
readObserver.observe(elRef.value);
- const connection = stream.useChannel('main');
+ connection = stream.useChannel('main');
connection.on('readAllNotifications', () => readObserver.disconnect());
watch(props.notification.isRead, () => {
readObserver.disconnect();
});
-
- onUnmounted(() => {
- readObserver.disconnect();
- connection.dispose();
- });
}
});
+
+ onUnmounted(() => {
+ if (readObserver) readObserver.disconnect();
+ if (connection) connection.dispose();
+ });
const followRequestDone = ref(false);
const groupInviteDone = ref(false);
diff --git a/packages/client/src/components/notifications.vue b/packages/client/src/components/notifications.vue
index 8eb569c369..eb19ad488c 100644
--- a/packages/client/src/components/notifications.vue
+++ b/packages/client/src/components/notifications.vue
@@ -60,8 +60,10 @@ const onNotification = (notification) => {
}
};
+let connection;
+
onMounted(() => {
- const connection = stream.useChannel('main');
+ connection = stream.useChannel('main');
connection.on('notification', onNotification);
connection.on('readAllNotifications', () => {
if (pagingComponent.value) {
@@ -87,10 +89,10 @@ onMounted(() => {
}
}
});
+});
- onUnmounted(() => {
- connection.dispose();
- });
+onUnmounted(() => {
+ if (connection) connection.dispose();
});
</script>
diff --git a/packages/client/src/components/poll.vue b/packages/client/src/components/poll.vue
index d9ef5970cb..35f87325d8 100644
--- a/packages/client/src/components/poll.vue
+++ b/packages/client/src/components/poll.vue
@@ -27,18 +27,19 @@ import { sum } from '@/scripts/array';
import { pleaseLogin } from '@/scripts/please-login';
import * as os from '@/os';
import { i18n } from '@/i18n';
+import { useInterval } from '@/scripts/use-interval';
export default defineComponent({
props: {
note: {
type: Object,
- required: true
+ required: true,
},
readOnly: {
type: Boolean,
required: false,
default: false,
- }
+ },
},
setup(props) {
@@ -54,7 +55,7 @@ export default defineComponent({
s: Math.floor(remaining.value % 60),
m: Math.floor(remaining.value / 60) % 60,
h: Math.floor(remaining.value / 3600) % 24,
- d: Math.floor(remaining.value / 86400)
+ d: Math.floor(remaining.value / 86400),
}));
const showResult = ref(props.readOnly || isVoted.value);
@@ -68,10 +69,9 @@ export default defineComponent({
}
};
- tick();
- const intevalId = window.setInterval(tick, 3000);
- onUnmounted(() => {
- window.clearInterval(intevalId);
+ useInterval(tick, 3000, {
+ immediate: true,
+ afterMounted: false,
});
}
diff --git a/packages/client/src/components/sparkle.vue b/packages/client/src/components/sparkle.vue
index f52e5a3f9b..b52dbe31c4 100644
--- a/packages/client/src/components/sparkle.vue
+++ b/packages/client/src/components/sparkle.vue
@@ -33,7 +33,8 @@
</svg>
-->
<svg v-for="particle in particles" :key="particle.id" :width="width" :height="height" :viewBox="`0 0 ${width} ${height}`" xmlns="http://www.w3.org/2000/svg">
- <path style="transform-origin: center; transform-box: fill-box;"
+ <path
+ style="transform-origin: center; transform-box: fill-box;"
:transform="`translate(${particle.x} ${particle.y})`"
:fill="particle.color"
d="M29.427,2.011C29.721,0.83 30.782,0 32,0C33.218,0 34.279,0.83 34.573,2.011L39.455,21.646C39.629,22.347 39.991,22.987 40.502,23.498C41.013,24.009 41.653,24.371 42.354,24.545L61.989,29.427C63.17,29.721 64,30.782 64,32C64,33.218 63.17,34.279 61.989,34.573L42.354,39.455C41.653,39.629 41.013,39.991 40.502,40.502C39.991,41.013 39.629,41.653 39.455,42.354L34.573,61.989C34.279,63.17 33.218,64 32,64C30.782,64 29.721,63.17 29.427,61.989L24.545,42.354C24.371,41.653 24.009,41.013 23.498,40.502C22.987,39.991 22.347,39.629 21.646,39.455L2.011,34.573C0.83,34.279 0,33.218 0,32C0,30.782 0.83,29.721 2.011,29.427L21.646,24.545C22.347,24.371 22.987,24.009 23.498,23.498C24.009,22.987 24.371,22.347 24.545,21.646L29.427,2.011Z"
@@ -73,14 +74,15 @@ export default defineComponent({
const width = ref(0);
const height = ref(0);
const colors = ['#FF1493', '#00FFFF', '#FFE202', '#FFE202', '#FFE202'];
+ let stop = false;
+ let ro: ResizeObserver | undefined;
onMounted(() => {
- const ro = new ResizeObserver((entries, observer) => {
+ ro = new ResizeObserver((entries, observer) => {
width.value = el.value?.offsetWidth + 64;
height.value = el.value?.offsetHeight + 64;
});
ro.observe(el.value);
- let stop = false;
const add = () => {
if (stop) return;
const x = (Math.random() * (width.value - 64));
@@ -104,10 +106,11 @@ export default defineComponent({
}, 500 + (Math.random() * 500));
};
add();
- onUnmounted(() => {
- ro.disconnect();
- stop = true;
- });
+ });
+
+ onUnmounted(() => {
+ if (ro) ro.disconnect();
+ stop = true;
});
return {
diff --git a/packages/client/src/pages/admin/overview.federation.vue b/packages/client/src/pages/admin/overview.federation.vue
index 6da1fa4e98..6c99cad33c 100644
--- a/packages/client/src/pages/admin/overview.federation.vue
+++ b/packages/client/src/pages/admin/overview.federation.vue
@@ -18,6 +18,7 @@
import { onMounted, onUnmounted, ref } from 'vue';
import MkMiniChart from '@/components/mini-chart.vue';
import * as os from '@/os';
+import { useInterval } from '@/scripts/use-interval';
const instances = ref([]);
const charts = ref([]);
@@ -34,15 +35,9 @@ const fetch = async () => {
fetching.value = false;
};
-let intervalId;
-
-onMounted(() => {
- fetch();
- intervalId = window.setInterval(fetch, 1000 * 60);
-});
-
-onUnmounted(() => {
- window.clearInterval(intervalId);
+useInterval(fetch, 1000 * 60, {
+ immediate: true,
+ afterMounted: true,
});
</script>
diff --git a/packages/client/src/scripts/use-interval.ts b/packages/client/src/scripts/use-interval.ts
new file mode 100644
index 0000000000..eb6e44338d
--- /dev/null
+++ b/packages/client/src/scripts/use-interval.ts
@@ -0,0 +1,22 @@
+import { onMounted, onUnmounted } from 'vue';
+
+export function useInterval(fn: () => void, interval: number, options: {
+ immediate: boolean;
+ afterMounted: boolean;
+}): void {
+ let intervalId: number | null = null;
+
+ if (options.afterMounted) {
+ onMounted(() => {
+ if (options.immediate) fn();
+ intervalId = window.setInterval(fn, interval);
+ });
+ } else {
+ if (options.immediate) fn();
+ intervalId = window.setInterval(fn, interval);
+ }
+
+ onUnmounted(() => {
+ if (intervalId) window.clearInterval(intervalId);
+ });
+}
diff --git a/packages/client/src/widgets/aichan.vue b/packages/client/src/widgets/aichan.vue
index cdd367cc84..828490fd9c 100644
--- a/packages/client/src/widgets/aichan.vue
+++ b/packages/client/src/widgets/aichan.vue
@@ -6,8 +6,8 @@
<script lang="ts" setup>
import { onMounted, onUnmounted, reactive, ref } from 'vue';
-import { GetFormResultType } from '@/scripts/form';
import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget';
+import { GetFormResultType } from '@/scripts/form';
const name = 'ai';
@@ -38,22 +38,23 @@ const touched = () => {
//if (this.live2d) this.live2d.changeExpression('gurugurume');
};
-onMounted(() => {
- const onMousemove = (ev: MouseEvent) => {
- const iframeRect = live2d.value.getBoundingClientRect();
- live2d.value.contentWindow.postMessage({
- type: 'moveCursor',
- body: {
- x: ev.clientX - iframeRect.left,
- y: ev.clientY - iframeRect.top,
- }
- }, '*');
- };
+const onMousemove = (ev: MouseEvent) => {
+ const iframeRect = live2d.value.getBoundingClientRect();
+ live2d.value.contentWindow.postMessage({
+ type: 'moveCursor',
+ body: {
+ x: ev.clientX - iframeRect.left,
+ y: ev.clientY - iframeRect.top,
+ },
+ }, '*');
+};
+onMounted(() => {
window.addEventListener('mousemove', onMousemove, { passive: true });
- onUnmounted(() => {
- window.removeEventListener('mousemove', onMousemove);
- });
+});
+
+onUnmounted(() => {
+ window.removeEventListener('mousemove', onMousemove);
});
defineExpose<WidgetComponentExpose>({
diff --git a/packages/client/src/widgets/calendar.vue b/packages/client/src/widgets/calendar.vue
index 2a2b035541..3a0dc8970c 100644
--- a/packages/client/src/widgets/calendar.vue
+++ b/packages/client/src/widgets/calendar.vue
@@ -34,9 +34,10 @@
<script lang="ts" setup>
import { onUnmounted, ref } from 'vue';
-import { GetFormResultType } from '@/scripts/form';
import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget';
+import { GetFormResultType } from '@/scripts/form';
import { i18n } from '@/i18n';
+import { useInterval } from '@/scripts/use-interval';
const name = 'calendar';
@@ -85,28 +86,26 @@ const tick = () => {
i18n.ts._weekday.wednesday,
i18n.ts._weekday.thursday,
i18n.ts._weekday.friday,
- i18n.ts._weekday.saturday
+ i18n.ts._weekday.saturday,
][now.getDay()];
- const dayNumer = now.getTime() - new Date(ny, nm, nd).getTime();
- const dayDenom = 1000/*ms*/ * 60/*s*/ * 60/*m*/ * 24/*h*/;
+ const dayNumer = now.getTime() - new Date(ny, nm, nd).getTime();
+ const dayDenom = 1000/*ms*/ * 60/*s*/ * 60/*m*/ * 24/*h*/;
const monthNumer = now.getTime() - new Date(ny, nm, 1).getTime();
const monthDenom = new Date(ny, nm + 1, 1).getTime() - new Date(ny, nm, 1).getTime();
- const yearNumer = now.getTime() - new Date(ny, 0, 1).getTime();
- const yearDenom = new Date(ny + 1, 0, 1).getTime() - new Date(ny, 0, 1).getTime();
+ const yearNumer = now.getTime() - new Date(ny, 0, 1).getTime();
+ const yearDenom = new Date(ny + 1, 0, 1).getTime() - new Date(ny, 0, 1).getTime();
- dayP.value = dayNumer / dayDenom * 100;
+ dayP.value = dayNumer / dayDenom * 100;
monthP.value = monthNumer / monthDenom * 100;
- yearP.value = yearNumer / yearDenom * 100;
+ yearP.value = yearNumer / yearDenom * 100;
isHoliday.value = now.getDay() === 0 || now.getDay() === 6;
};
-tick();
-
-const intervalId = window.setInterval(tick, 1000);
-onUnmounted(() => {
- window.clearInterval(intervalId);
+useInterval(tick, 1000, {
+ immediate: true,
+ afterMounted: false,
});
defineExpose<WidgetComponentExpose>({
diff --git a/packages/client/src/widgets/federation.vue b/packages/client/src/widgets/federation.vue
index afe7af0e96..ac87cdac2e 100644
--- a/packages/client/src/widgets/federation.vue
+++ b/packages/client/src/widgets/federation.vue
@@ -25,6 +25,7 @@ import { GetFormResultType } from '@/scripts/form';
import MkContainer from '@/components/ui/container.vue';
import MkMiniChart from '@/components/mini-chart.vue';
import * as os from '@/os';
+import { useInterval } from '@/scripts/use-interval';
const name = 'federation';
@@ -64,12 +65,9 @@ const fetch = async () => {
fetching.value = false;
};
-onMounted(() => {
- fetch();
- const intervalId = window.setInterval(fetch, 1000 * 60);
- onUnmounted(() => {
- window.clearInterval(intervalId);
- });
+useInterval(fetch, 1000 * 60, {
+ immediate: true,
+ afterMounted: true,
});
defineExpose<WidgetComponentExpose>({
diff --git a/packages/client/src/widgets/online-users.vue b/packages/client/src/widgets/online-users.vue
index eb3184fe9d..4122a82657 100644
--- a/packages/client/src/widgets/online-users.vue
+++ b/packages/client/src/widgets/online-users.vue
@@ -8,9 +8,10 @@
<script lang="ts" setup>
import { onMounted, onUnmounted, ref } from 'vue';
-import { GetFormResultType } from '@/scripts/form';
import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget';
+import { GetFormResultType } from '@/scripts/form';
import * as os from '@/os';
+import { useInterval } from '@/scripts/use-interval';
const name = 'onlineUsers';
@@ -43,12 +44,9 @@ const tick = () => {
});
};
-onMounted(() => {
- tick();
- const intervalId = window.setInterval(tick, 1000 * 15);
- onUnmounted(() => {
- window.clearInterval(intervalId);
- });
+useInterval(tick, 1000 * 15, {
+ immediate: true,
+ afterMounted: true,
});
defineExpose<WidgetComponentExpose>({
diff --git a/packages/client/src/widgets/rss.vue b/packages/client/src/widgets/rss.vue
index fc65f11813..e5da291a8d 100644
--- a/packages/client/src/widgets/rss.vue
+++ b/packages/client/src/widgets/rss.vue
@@ -14,10 +14,11 @@
<script lang="ts" setup>
import { onMounted, onUnmounted, ref, watch } from 'vue';
-import { GetFormResultType } from '@/scripts/form';
import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget';
+import { GetFormResultType } from '@/scripts/form';
import * as os from '@/os';
import MkContainer from '@/components/ui/container.vue';
+import { useInterval } from '@/scripts/use-interval';
const name = 'rss';
@@ -60,12 +61,9 @@ const tick = () => {
watch(() => widgetProps.url, tick);
-onMounted(() => {
- tick();
- const intervalId = window.setInterval(tick, 60000);
- onUnmounted(() => {
- window.clearInterval(intervalId);
- });
+useInterval(tick, 60000, {
+ immediate: true,
+ afterMounted: true,
});
defineExpose<WidgetComponentExpose>({
diff --git a/packages/client/src/widgets/slideshow.vue b/packages/client/src/widgets/slideshow.vue
index fd78edbe40..c286312161 100644
--- a/packages/client/src/widgets/slideshow.vue
+++ b/packages/client/src/widgets/slideshow.vue
@@ -13,9 +13,10 @@
<script lang="ts" setup>
import { nextTick, onMounted, onUnmounted, reactive, ref } from 'vue';
-import { GetFormResultType } from '@/scripts/form';
import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget';
+import { GetFormResultType } from '@/scripts/form';
import * as os from '@/os';
+import { useInterval } from '@/scripts/use-interval';
const name = 'slideshow';
@@ -75,7 +76,7 @@ const fetch = () => {
os.api('drive/files', {
folderId: widgetProps.folderId,
type: 'image/*',
- limit: 100
+ limit: 100,
}).then(res => {
images.value = res;
fetching.value = false;
@@ -96,15 +97,15 @@ const choose = () => {
});
};
+useInterval(change, 10000, {
+ immediate: false,
+ afterMounted: true,
+});
+
onMounted(() => {
if (widgetProps.folderId != null) {
fetch();
}
-
- const intervalId = window.setInterval(change, 10000);
- onUnmounted(() => {
- window.clearInterval(intervalId);
- });
});
defineExpose<WidgetComponentExpose>({
diff --git a/packages/client/src/widgets/trends.vue b/packages/client/src/widgets/trends.vue
index 9680f1c892..0f34ea6341 100644
--- a/packages/client/src/widgets/trends.vue
+++ b/packages/client/src/widgets/trends.vue
@@ -19,11 +19,12 @@
<script lang="ts" setup>
import { onMounted, onUnmounted, ref } from 'vue';
-import { GetFormResultType } from '@/scripts/form';
import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget';
+import { GetFormResultType } from '@/scripts/form';
import MkContainer from '@/components/ui/container.vue';
import MkMiniChart from '@/components/mini-chart.vue';
import * as os from '@/os';
+import { useInterval } from '@/scripts/use-interval';
const name = 'hashtags';
@@ -58,12 +59,9 @@ const fetch = () => {
});
};
-onMounted(() => {
- fetch();
- const intervalId = window.setInterval(fetch, 1000 * 60);
- onUnmounted(() => {
- window.clearInterval(intervalId);
- });
+useInterval(fetch, 1000 * 60, {
+ immediate: true,
+ afterMounted: true,
});
defineExpose<WidgetComponentExpose>({