From 9c6a2208107d8046c2f9c7eb302363cc214a8861 Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Sat, 2 Jul 2022 22:07:04 +0900 Subject: [PATCH] chore(client): tweak ui --- packages/client/src/components/form/range.vue | 3 +- packages/client/src/components/marquee.vue | 4 +- packages/client/src/scripts/use-interval.ts | 2 + packages/client/src/widgets/rss-marquee.vue | 65 +++++++++++-------- 4 files changed, 46 insertions(+), 28 deletions(-) diff --git a/packages/client/src/components/form/range.vue b/packages/client/src/components/form/range.vue index d46174acc1..387ad26f3d 100644 --- a/packages/client/src/components/form/range.vue +++ b/packages/client/src/components/form/range.vue @@ -6,7 +6,7 @@ <div class="track"> <div class="highlight" :style="{ width: (steppedRawValue * 100) + '%' }"></div> </div> - <div v-if="steps" class="ticks"> + <div v-if="steps && showTicks" class="ticks"> <div v-for="i in (steps + 1)" class="tick" :style="{ left: (((i - 1) / steps) * 100) + '%' }"></div> </div> <div ref="thumbEl" v-tooltip="textConverter(finalValue)" class="thumb" :style="{ left: thumbPosition + 'px' }" @mousedown="onMousedown" @touchstart="onMousedown"></div> @@ -27,6 +27,7 @@ const props = withDefaults(defineProps<{ max: number; step?: number; textConverter?: (value: number) => string, + showTicks?: boolean; }>(), { step: 1, textConverter: (v) => v.toString(), diff --git a/packages/client/src/components/marquee.vue b/packages/client/src/components/marquee.vue index 2fd76a54f0..4685033517 100644 --- a/packages/client/src/components/marquee.vue +++ b/packages/client/src/components/marquee.vue @@ -1,5 +1,5 @@ <script lang="ts"> -import { h, onMounted, onUnmounted, ref } from 'vue'; +import { h, onMounted, onUnmounted, ref, watch } from 'vue'; export default { name: 'MarqueeText', @@ -32,6 +32,8 @@ export default { contentEl.value.style.animationDuration = `${duration}s`; } + watch(() => props.duration, calc); + onMounted(() => { calc(); }); diff --git a/packages/client/src/scripts/use-interval.ts b/packages/client/src/scripts/use-interval.ts index eb6e44338d..201ba417ef 100644 --- a/packages/client/src/scripts/use-interval.ts +++ b/packages/client/src/scripts/use-interval.ts @@ -4,6 +4,8 @@ export function useInterval(fn: () => void, interval: number, options: { immediate: boolean; afterMounted: boolean; }): void { + if (Number.isNaN(interval)) return; + let intervalId: number | null = null; if (options.afterMounted) { diff --git a/packages/client/src/widgets/rss-marquee.vue b/packages/client/src/widgets/rss-marquee.vue index 2f92c09f38..c20954c1e0 100644 --- a/packages/client/src/widgets/rss-marquee.vue +++ b/packages/client/src/widgets/rss-marquee.vue @@ -6,11 +6,13 @@ <div class="ekmkgxbk"> <MkLoading v-if="fetching"/> <div v-else class="feed"> - <MarqueeText :key="key" :duration="widgetProps.speed" :reverse="widgetProps.reverse"> - <span v-for="item in items" class="item"> - <a class="link" :href="item.link" rel="nofollow noopener" target="_blank" :title="item.title">{{ item.title }}</a><span class="divider"></span> - </span> - </MarqueeText> + <transition name="change" mode="default"> + <MarqueeText :key="key" :duration="widgetProps.duration" :reverse="widgetProps.reverse"> + <span v-for="item in items" class="item"> + <a class="link" :href="item.link" rel="nofollow noopener" target="_blank" :title="item.title">{{ item.title }}</a><span class="divider"></span> + </span> + </MarqueeText> + </transition> </div> </div> </MkContainer> @@ -32,6 +34,21 @@ const widgetPropsDef = { type: 'string' as const, default: 'http://feeds.afpbb.com/rss/afpbb/afpbbnews', }, + refreshIntervalSec: { + type: 'number' as const, + default: 60, + }, + duration: { + type: 'range' as const, + default: 70, + step: 1, + min: 5, + max: 200, + }, + reverse: { + type: 'boolean' as const, + default: false, + }, showHeader: { type: 'boolean' as const, default: false, @@ -40,25 +57,6 @@ const widgetPropsDef = { type: 'boolean' as const, default: false, }, - speed: { - type: 'radio' as const, - default: 70, - options: [{ - value: 170, label: 'very slow', - }, { - value: 100, label: 'slow', - }, { - value: 70, label: 'medium', - }, { - value: 40, label: 'fast', - }, { - value: 20, label: 'very fast', - }], - }, - reverse: { - type: 'boolean' as const, - default: false, - }, }; type WidgetProps = GetFormResultType<typeof widgetPropsDef>; @@ -91,7 +89,7 @@ const tick = () => { watch(() => widgetProps.url, tick); -useInterval(tick, 60000, { +useInterval(tick, Math.max(10000, widgetProps.refreshIntervalSec * 1000), { immediate: true, afterMounted: true, }); @@ -104,17 +102,32 @@ defineExpose<WidgetComponentExpose>({ </script> <style lang="scss" scoped> +.change-enter-active, .change-leave-active { + position: absolute; + top: 0; + transition: all 1s ease; +} +.change-enter-from { + opacity: 0; + transform: translateY(-100%); +} +.change-leave-to { + opacity: 0; + transform: translateY(100%); +} + .ekmkgxbk { > .feed { padding: 0; font-size: 0.9em; + line-height: 42px; + height: 42px; ::v-deep(.item) { display: inline-flex; align-items: center; vertical-align: bottom; color: var(--fg); - margin: 12px 0; > .divider { display: inline-block;