feat(client): add tag cloud component
This commit is contained in:
		
							parent
							
								
									f997b7dff2
								
							
						
					
					
						commit
						c9b3ab80ca
					
				
					 3 changed files with 133 additions and 1 deletions
				
			
		
							
								
								
									
										21
									
								
								packages/client/assets/tagcanvas.min.js
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								packages/client/assets/tagcanvas.min.js
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										80
									
								
								packages/client/src/components/tag-cloud.vue
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										80
									
								
								packages/client/src/components/tag-cloud.vue
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,80 @@ | |||
| <template> | ||||
| <div class="root"> | ||||
| 	<canvas :id="idForCanvas" ref="canvasEl" class="canvas" width="300" height="300"></canvas> | ||||
| 	<div :id="idForTags" ref="tagsEl" class="tags"> | ||||
| 		<ul> | ||||
| 			<slot></slot> | ||||
| 		</ul> | ||||
| 	</div> | ||||
| </div> | ||||
| </template> | ||||
| 
 | ||||
| <script lang="ts" setup> | ||||
| import { onMounted, ref, watch, PropType, onBeforeUnmount } from 'vue'; | ||||
| import tinycolor from 'tinycolor2'; | ||||
| 
 | ||||
| const props = defineProps<{}>(); | ||||
| 
 | ||||
| const loaded = !!window.TagCanvas; | ||||
| const SAFE_FOR_HTML_ID = 'abcdefghijklmnopqrstuvwxyz'; | ||||
| const computedStyle = getComputedStyle(document.documentElement); | ||||
| const idForCanvas = Array.from(Array(16)).map(() => SAFE_FOR_HTML_ID[Math.floor(Math.random() * SAFE_FOR_HTML_ID.length)]).join(''); | ||||
| const idForTags = Array.from(Array(16)).map(() => SAFE_FOR_HTML_ID[Math.floor(Math.random() * SAFE_FOR_HTML_ID.length)]).join(''); | ||||
| let available = $ref(false); | ||||
| let canvasEl = $ref<HTMLCanvasElement | null>(null); | ||||
| let tagsEl = $ref<HTMLElement | null>(null); | ||||
| 
 | ||||
| watch($$(available), () => { | ||||
| 	window.TagCanvas.Start(idForCanvas, idForTags, { | ||||
| 		textColour: '#ffffff', | ||||
| 		outlineColour: tinycolor(computedStyle.getPropertyValue('--accent')).toHexString(), | ||||
| 		outlineRadius: 10, | ||||
| 		initial: [-0.030, -0.010], | ||||
| 		frontSelect: true, | ||||
| 		imageRadius: 8, | ||||
| 		//dragControl: true, | ||||
| 		dragThreshold: 3, | ||||
| 		wheelZoom: false, | ||||
| 		reverse: true, | ||||
| 		depth: 0.5, | ||||
| 		maxSpeed: 0.2, | ||||
| 		minSpeed: 0.003, | ||||
| 		stretchX: 0.8, | ||||
| 		stretchY: 0.8, | ||||
| 	}); | ||||
| }); | ||||
| 
 | ||||
| onMounted(() => { | ||||
| 	if (loaded) { | ||||
| 		available = true; | ||||
| 	} else { | ||||
| 		document.head.appendChild(Object.assign(document.createElement('script'), { | ||||
| 			async: true, | ||||
| 			src: '/client-assets/tagcanvas.min.js', | ||||
| 		})).addEventListener('load', () => available = true); | ||||
| 	} | ||||
| }); | ||||
| 
 | ||||
| onBeforeUnmount(() => { | ||||
| 	window.TagCanvas.Delete(idForCanvas); | ||||
| }); | ||||
| </script> | ||||
| 
 | ||||
| <style lang="scss" scoped> | ||||
| .root { | ||||
| 	position: relative; | ||||
| 	overflow: clip; | ||||
| 	display: grid; | ||||
| 	place-items: center; | ||||
| 
 | ||||
| 	> .canvas { | ||||
| 		display: block; | ||||
| 	} | ||||
| 
 | ||||
| 	> .tags { | ||||
| 		position: absolute; | ||||
| 		top: 999px; | ||||
| 		left: 999px; | ||||
| 	} | ||||
| } | ||||
| </style> | ||||
|  | @ -108,6 +108,17 @@ | |||
| 					</div> | ||||
| 				</div> | ||||
| 			</div> | ||||
| 			<div class="container tagCloud"> | ||||
| 				<div class="body"> | ||||
| 					<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> | ||||
| 			</div> | ||||
| 			<div v-if="fedStats" class="container federationPies"> | ||||
| 				<div class="body"> | ||||
| 					<div class="chart deliver"> | ||||
|  | @ -154,8 +165,8 @@ import XFederation from './overview.federation.vue'; | |||
| import XQueueChart from './overview.queue-chart.vue'; | ||||
| import XUser from './overview.user.vue'; | ||||
| import XPie from './overview.pie.vue'; | ||||
| import MkInstanceStats from '@/components/instance-stats.vue'; | ||||
| import MkNumberDiff from '@/components/number-diff.vue'; | ||||
| import MkTagCloud from '@/components/tag-cloud.vue'; | ||||
| import { version, url } from '@/config'; | ||||
| import number from '@/filters/number'; | ||||
| import * as os from '@/os'; | ||||
|  | @ -197,6 +208,7 @@ let federationPubActiveDiff = $ref<number | null>(null); | |||
| let federationSubActive = $ref<number | null>(null); | ||||
| let federationSubActiveDiff = $ref<number | null>(null); | ||||
| let newUsers = $ref(null); | ||||
| let activeInstances = $shallowRef(null); | ||||
| const queueStatsConnection = markRaw(stream.useChannel('queueStats')); | ||||
| const now = new Date(); | ||||
| let chartInstance: Chart = null; | ||||
|  | @ -363,6 +375,10 @@ async function renderChart() { | |||
| 	}); | ||||
| } | ||||
| 
 | ||||
| function onInstanceClick(i) { | ||||
| 	os.pageWindow(`/instance-info/${i.host}`); | ||||
| } | ||||
| 
 | ||||
| onMounted(async () => { | ||||
| 	/* | ||||
| 	const magicGrid = new MagicGrid({ | ||||
|  | @ -410,6 +426,13 @@ onMounted(async () => { | |||
| 		newUsers = res; | ||||
| 	}); | ||||
| 
 | ||||
| 	os.api('federation/instances', { | ||||
| 		sort: '+lastCommunicatedAt', | ||||
| 		limit: 25, | ||||
| 	}).then(res => { | ||||
| 		activeInstances = res; | ||||
| 	}); | ||||
| 
 | ||||
| 	nextTick(() => { | ||||
| 		queueStatsConnection.send('requestLog', { | ||||
| 			id: Math.random().toString().substr(2, 8), | ||||
|  | @ -577,6 +600,14 @@ definePageMetadata({ | |||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 
 | ||||
| 			&.tagCloud { | ||||
| 				> .body { | ||||
| 					background: var(--panel); | ||||
| 					border-radius: var(--radius); | ||||
| 					overflow: clip; | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue