feat(client): add instance-cloud widget
This commit is contained in:
		
							parent
							
								
									6a7dff1c82
								
							
						
					
					
						commit
						99dcd7bb27
					
				
					 4 changed files with 84 additions and 0 deletions
				
			
		|  | @ -16,6 +16,7 @@ You should also include the user name that made the change. | ||||||
| - Server: Add rate limit to i/notifications @tamaina | - Server: Add rate limit to i/notifications @tamaina | ||||||
| - Client: Improve control panel @syuilo | - Client: Improve control panel @syuilo | ||||||
| - Client: Show warning in control panel when there is an unresolved abuse report @syuilo | - Client: Show warning in control panel when there is an unresolved abuse report @syuilo | ||||||
|  | - Client: Add instance-cloud widget @syuilo | ||||||
| - Make possible to delete an account by admin @syuilo | - Make possible to delete an account by admin @syuilo | ||||||
| - Improve player detection in URL preview @mei23 | - Improve player detection in URL preview @mei23 | ||||||
| - Add Badge Image to Push Notification #8012 @tamaina | - Add Badge Image to Push Notification #8012 @tamaina | ||||||
|  |  | ||||||
|  | @ -1247,6 +1247,7 @@ _widgets: | ||||||
|   photos: "フォト" |   photos: "フォト" | ||||||
|   digitalClock: "デジタル時計" |   digitalClock: "デジタル時計" | ||||||
|   federation: "連合" |   federation: "連合" | ||||||
|  |   instanceCloud: "インスタンスクラウド" | ||||||
|   postForm: "投稿フォーム" |   postForm: "投稿フォーム" | ||||||
|   slideshow: "スライドショー" |   slideshow: "スライドショー" | ||||||
|   button: "ボタン" |   button: "ボタン" | ||||||
|  |  | ||||||
|  | @ -17,6 +17,7 @@ export default function(app: App) { | ||||||
| 	app.component('MkwServerMetric', defineAsyncComponent(() => import('./server-metric/index.vue'))); | 	app.component('MkwServerMetric', defineAsyncComponent(() => import('./server-metric/index.vue'))); | ||||||
| 	app.component('MkwOnlineUsers', defineAsyncComponent(() => import('./online-users.vue'))); | 	app.component('MkwOnlineUsers', defineAsyncComponent(() => import('./online-users.vue'))); | ||||||
| 	app.component('MkwJobQueue', defineAsyncComponent(() => import('./job-queue.vue'))); | 	app.component('MkwJobQueue', defineAsyncComponent(() => import('./job-queue.vue'))); | ||||||
|  | 	app.component('MkwInstanceCloud', defineAsyncComponent(() => import('./instance-cloud.vue'))); | ||||||
| 	app.component('MkwButton', defineAsyncComponent(() => import('./button.vue'))); | 	app.component('MkwButton', defineAsyncComponent(() => import('./button.vue'))); | ||||||
| 	app.component('MkwAiscript', defineAsyncComponent(() => import('./aiscript.vue'))); | 	app.component('MkwAiscript', defineAsyncComponent(() => import('./aiscript.vue'))); | ||||||
| 	app.component('MkwAichan', defineAsyncComponent(() => import('./aichan.vue'))); | 	app.component('MkwAichan', defineAsyncComponent(() => import('./aichan.vue'))); | ||||||
|  | @ -34,6 +35,7 @@ export const widgets = [ | ||||||
| 	'photos', | 	'photos', | ||||||
| 	'digitalClock', | 	'digitalClock', | ||||||
| 	'federation', | 	'federation', | ||||||
|  | 	'instance-cloud', | ||||||
| 	'postForm', | 	'postForm', | ||||||
| 	'slideshow', | 	'slideshow', | ||||||
| 	'serverMetric', | 	'serverMetric', | ||||||
|  |  | ||||||
							
								
								
									
										80
									
								
								packages/client/src/widgets/instance-cloud.vue
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										80
									
								
								packages/client/src/widgets/instance-cloud.vue
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,80 @@ | ||||||
|  | <template> | ||||||
|  | <MkContainer :naked="widgetProps.transparent" :show-header="widgetProps.showHeader" class="mkw-instance-cloud"> | ||||||
|  | 	<div class=""> | ||||||
|  | 		<MkTagCloud v-if="activeInstances"> | ||||||
|  | 			<li v-for="instance in activeInstances"> | ||||||
|  | 				<a @click.prevent="onInstanceClick(instance)"> | ||||||
|  | 					<img style="width: 32px;" :src="instance.iconUrl"> | ||||||
|  | 				</a> | ||||||
|  | 			</li> | ||||||
|  | 		</MkTagCloud> | ||||||
|  | 	</div> | ||||||
|  | </MkContainer> | ||||||
|  | </template> | ||||||
|  | 
 | ||||||
|  | <script lang="ts" setup> | ||||||
|  | import { } from 'vue'; | ||||||
|  | import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget'; | ||||||
|  | import { GetFormResultType } from '@/scripts/form'; | ||||||
|  | import MkContainer from '@/components/ui/container.vue'; | ||||||
|  | import MkTagCloud from '@/components/tag-cloud.vue'; | ||||||
|  | import * as os from '@/os'; | ||||||
|  | import { useInterval } from '@/scripts/use-interval'; | ||||||
|  | 
 | ||||||
|  | const name = 'instanceCloud'; | ||||||
|  | 
 | ||||||
|  | const widgetPropsDef = { | ||||||
|  | 	transparent: { | ||||||
|  | 		type: 'boolean' as const, | ||||||
|  | 		default: false, | ||||||
|  | 	}, | ||||||
|  | 	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, | ||||||
|  | ); | ||||||
|  | 
 | ||||||
|  | let cloud = $ref<InstanceType<typeof MkTagCloud> | null>(); | ||||||
|  | let activeInstances = $shallowRef(null); | ||||||
|  | 
 | ||||||
|  | function onInstanceClick(i) { | ||||||
|  | 	os.pageWindow(`/instance-info/${i.host}`); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | useInterval(() => { | ||||||
|  | 	os.api('federation/instances', { | ||||||
|  | 		sort: '+lastCommunicatedAt', | ||||||
|  | 		limit: 25, | ||||||
|  | 	}).then(res => { | ||||||
|  | 		activeInstances = res; | ||||||
|  | 		if (cloud) cloud.update(); | ||||||
|  | 	}); | ||||||
|  | }, 1000 * 60 * 3, { | ||||||
|  | 	immediate: true, | ||||||
|  | 	afterMounted: true, | ||||||
|  | }); | ||||||
|  | 
 | ||||||
|  | defineExpose<WidgetComponentExpose>({ | ||||||
|  | 	name, | ||||||
|  | 	configure, | ||||||
|  | 	id: props.widget ? props.widget.id : null, | ||||||
|  | }); | ||||||
|  | </script> | ||||||
|  | 
 | ||||||
|  | <style lang="scss" scoped> | ||||||
|  | 
 | ||||||
|  | </style> | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue