diff options
| author | syuilo <Syuilotan@yahoo.co.jp> | 2023-01-10 06:08:40 +0900 |
|---|---|---|
| committer | syuilo <Syuilotan@yahoo.co.jp> | 2023-01-10 06:08:40 +0900 |
| commit | 618405c4d39753c1a9135fd0759aff2ecb3a94b3 (patch) | |
| tree | b0551494d3ffd37ee3e7f7ad75bc81f54d3fb249 /packages/frontend/src/widgets/WidgetRss.vue | |
| parent | refactor(client): use css modules (diff) | |
| download | misskey-618405c4d39753c1a9135fd0759aff2ecb3a94b3.tar.gz misskey-618405c4d39753c1a9135fd0759aff2ecb3a94b3.tar.bz2 misskey-618405c4d39753c1a9135fd0759aff2ecb3a94b3.zip | |
refactor(client): rename widget filename
Diffstat (limited to 'packages/frontend/src/widgets/WidgetRss.vue')
| -rw-r--r-- | packages/frontend/src/widgets/WidgetRss.vue | 120 |
1 files changed, 120 insertions, 0 deletions
diff --git a/packages/frontend/src/widgets/WidgetRss.vue b/packages/frontend/src/widgets/WidgetRss.vue new file mode 100644 index 0000000000..554413cd1e --- /dev/null +++ b/packages/frontend/src/widgets/WidgetRss.vue @@ -0,0 +1,120 @@ +<template> +<MkContainer :show-header="widgetProps.showHeader" class="mkw-rss"> + <template #header><i class="ti ti-rss"></i>RSS</template> + <template #func><button class="_button" @click="configure"><i class="ti ti-settings"></i></button></template> + + <div class="ekmkgxbj"> + <MkLoading v-if="fetching"/> + <div class="_fullinfo" v-else-if="(!items || items.length === 0) && widgetProps.showHeader"> + <img src="https://xn--931a.moe/assets/info.jpg" class="_ghost"/> + <div>{{ i18n.ts.nothing }}</div> + </div> + <div v-else :class="$style.feed"> + <a v-for="item in items" :class="$style.item" :href="item.link" :key="item.link" rel="nofollow noopener" target="_blank" :title="item.title">{{ item.title }}</a> + </div> + </div> +</MkContainer> +</template> + +<script lang="ts" setup> +import { ref, watch, computed } from 'vue'; +import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget'; +import { GetFormResultType } from '@/scripts/form'; +import MkContainer from '@/components/MkContainer.vue'; +import { url as base } from '@/config'; +import { i18n } from '@/i18n'; +import { useInterval } from '@/scripts/use-interval'; + +const name = 'rss'; + +const widgetPropsDef = { + url: { + type: 'string' as const, + default: 'http://feeds.afpbb.com/rss/afpbb/afpbbnews', + }, + refreshIntervalSec: { + type: 'number' as const, + default: 60, + }, + maxEntries: { + type: 'number' as const, + default: 15, + }, + showHeader: { + type: 'boolean' as const, + default: true, + }, +}; + +type WidgetProps = GetFormResultType<typeof widgetPropsDef>; + +// 現時点ではvueの制限によりimportしたtypeをジェネリックに渡せない +//const props = defineProps<WidgetComponentProps<WidgetProps>>(); +//const emit = defineEmits<WidgetComponentEmits<WidgetProps>>(); +const props = defineProps<{ widget?: Widget<WidgetProps>; }>(); +const emit = defineEmits<{ (ev: 'updateProps', props: WidgetProps); }>(); + +const { widgetProps, configure } = useWidgetPropsManager(name, + widgetPropsDef, + props, + emit, +); + +const rawItems = ref([]); +const items = computed(() => rawItems.value.slice(0, widgetProps.maxEntries)); +const fetching = ref(true); +const fetchEndpoint = computed(() => { + const url = new URL('/api/fetch-rss', base); + url.searchParams.set('url', widgetProps.url); + return url; +}); +let intervalClear = $ref<(() => void) | undefined>(); + +const tick = () => { + if (document.visibilityState === 'hidden' && rawItems.value.length !== 0) return; + + window.fetch(fetchEndpoint.value, {}) + .then(res => res.json()) + .then(feed => { + rawItems.value = feed.items ?? []; + fetching.value = false; + }); +}; + +watch(() => fetchEndpoint, tick); +watch(() => widgetProps.refreshIntervalSec, () => { + if (intervalClear) { + intervalClear(); + } + intervalClear = useInterval(tick, Math.max(10000, widgetProps.refreshIntervalSec * 1000), { + immediate: true, + afterMounted: true, + }); +}, { immediate: true }); + +defineExpose<WidgetComponentExpose>({ + name, + configure, + id: props.widget ? props.widget.id : null, +}); +</script> + +<style lang="scss" module> +.feed { + padding: 0; + font-size: 0.9em; +} + +.item { + display: block; + padding: 8px 16px; + color: var(--fg); + white-space: nowrap; + text-overflow: ellipsis; + overflow: hidden; + + &:nth-child(even) { + background: rgba(#000, 0.05); + } +} +</style> |