diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index a073d789a244b9d7a2aec916a2dd5589bb8a4f24..ec767aafa992523eb506aa0e5d10a5ecb7625aa2 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -732,6 +732,7 @@ _widgets: activity: "アクティビティ" photos: "フォト" digitalClock: "デジタル時計" + federation: "連åˆ" _cw: hide: "éš ã™" diff --git a/src/client/widgets/federation.vue b/src/client/widgets/federation.vue new file mode 100644 index 0000000000000000000000000000000000000000..b99ef1b0aa4709ac47ccd7efe45ab8ae54c33e03 --- /dev/null +++ b/src/client/widgets/federation.vue @@ -0,0 +1,111 @@ +<template> +<mk-container :show-header="props.showHeader"> + <template #header><fa :icon="faGlobe"/>{{ $t('_widgets.federation') }}</template> + + <div class="wbrkwalb"> + <mk-loading v-if="fetching"/> + <transition-group tag="div" name="chart" class="instances" v-else> + <div v-for="instance in instances" :key="instance.id"> + <div class="instance"> + <a class="a" :href="'https://' + instance.host" target="_blank" :title="instance.host">#{{ instance.host }}</a> + <p>{{ instance.softwareName }} {{ instance.softwareVersion }}</p> + </div> + <x-chart class="chart" :src="stat.chart"/> + </div> + </transition-group> + </div> +</mk-container> +</template> + +<script lang="ts"> +import { faGlobe } from '@fortawesome/free-solid-svg-icons'; +import MkContainer from '../components/ui/container.vue'; +import define from './define'; +import XChart from './trends.chart.vue'; + +export default define({ + name: 'federation', + props: () => ({ + showHeader: { + type: 'boolean', + default: true, + }, + }) +}).extend({ + components: { + MkContainer, XChart + }, + data() { + return { + instances: [], + fetching: true, + faGlobe + }; + }, + mounted() { + this.fetch(); + this.clock = setInterval(this.fetch, 1000 * 60); + }, + beforeDestroy() { + clearInterval(this.clock); + }, + methods: { + fetch() { + this.$root.api('federation/instances', { + sort: '+lastCommunicatedAt', + limit: 5 + }).then(instances => { + this.instances = instances; + this.fetching = false; + }); + } + } +}); +</script> + +<style lang="scss" scoped> +.wbrkwalb { + height: (62px + 1px) + (62px + 1px) + (62px + 1px) + (62px + 1px) + 62px; + overflow: hidden; + + > .instances { + .chart-move { + transition: transform 1s ease; + } + + > div { + display: flex; + align-items: center; + padding: 14px 16px; + border-bottom: solid 1px var(--divider); + + > .instance { + flex: 1; + overflow: hidden; + font-size: 0.9em; + color: var(--fg); + + > .a { + display: block; + width: 100%; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + line-height: 18px; + } + + > p { + margin: 0; + font-size: 75%; + opacity: 0.7; + line-height: 16px; + } + } + + > .chart { + height: 30px; + } + } + } +} +</style> diff --git a/src/client/widgets/index.ts b/src/client/widgets/index.ts index 2d27d27e58ab1712294f41e40b5925429c53ebd7..743146193c9a7ab9755f55ae032d2aa73bd24909 100644 --- a/src/client/widgets/index.ts +++ b/src/client/widgets/index.ts @@ -11,6 +11,7 @@ Vue.component('mkw-clock', () => import('./clock.vue').then(m => m.default)); Vue.component('mkw-activity', () => import('./activity.vue').then(m => m.default)); Vue.component('mkw-photos', () => import('./photos.vue').then(m => m.default)); Vue.component('mkw-digitalClock', () => import('./digital-clock.vue').then(m => m.default)); +Vue.component('mkw-federation', () => import('./federation.vue').then(m => m.default)); export const widgets = [ 'memo', @@ -23,4 +24,5 @@ export const widgets = [ 'activity', 'photos', 'digitalClock', + 'federation', ];