✨ More embeddable widgets
This commit is contained in:
		
							
								
								
									
										131
									
								
								pages/embed/gallery/[id].vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										131
									
								
								pages/embed/gallery/[id].vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,131 @@ | ||||
| <template> | ||||
|   <div> | ||||
|     <div class="mt-3 mb-4.5 mx-[2.5ch] flex flex-row gap-4 items-center"> | ||||
|       <v-avatar :image="attachment.account?.avatar" /> | ||||
|       <div class="flex flex-col"> | ||||
|         <span class="text-xs">Uploaded by</span> | ||||
|         <span>{{ attachment.account?.nick }} <span class="text-xs">@{{ attachment.account?.name }}</span></span> | ||||
|       </div> | ||||
|     </div> | ||||
|  | ||||
|     <h2 class="section-header">Preview</h2> | ||||
|     <v-card class="mb-5"> | ||||
|       <attachment-renderer :item="attachment" /> | ||||
|     </v-card> | ||||
|  | ||||
|     <h2 class="section-header">Metadata</h2> | ||||
|     <v-card class="mb-5"> | ||||
|       <v-card-text class="flex flex-col gap-4"> | ||||
|         <div class="flex flex-col" v-if="attachment?.alt"> | ||||
|           <span class="text-xs font-bold">Alternative</span> | ||||
|           <span class="text-truncate">{{ attachment?.alt }}</span> | ||||
|         </div> | ||||
|         <div class="flex flex-col"> | ||||
|           <span class="text-xs font-bold">Original File Name</span> | ||||
|           <span class="text-truncate">{{ attachment?.name }}</span> | ||||
|         </div> | ||||
|         <div class="flex flex-col"> | ||||
|           <span class="text-xs font-bold">Size</span> | ||||
|           <span>{{ formatBytes(attachment?.size) }}</span> | ||||
|         </div> | ||||
|         <div class="flex flex-col" v-if="attachment?.metadata?.ratio"> | ||||
|           <span class="text-xs font-bold">Aspect Ratio</span> | ||||
|           <span> | ||||
|             {{ attachment?.metadata?.width }}x{{ attachment?.metadata?.height }} | ||||
|             {{ attachment?.metadata?.ratio.toFixed(2) }} | ||||
|           </span> | ||||
|         </div> | ||||
|         <div class="flex flex-col" v-if="attachment?.mimetype"> | ||||
|           <span class="text-xs font-bold">Mimetype</span> | ||||
|           <span>{{ attachment?.mimetype }}</span> | ||||
|         </div> | ||||
|         <div class="flex flex-col"> | ||||
|           <span class="text-xs font-bold">Raw Data</span> | ||||
|           <v-code class="font-mono mt-1">{{ JSON.stringify(attachment.metadata, null, 4) }}</v-code> | ||||
|         </div> | ||||
|       </v-card-text> | ||||
|     </v-card> | ||||
|  | ||||
|     <div class="text-xs text-grey flex flex-col mx-[2.5ch]"> | ||||
|       <span>Solar Network Attachment Web Preview</span> | ||||
|       <span>Powered by <a class="underline" target="_blank" href="https://git.solsynth.dev/Hydrogen/Paperclip">Hydrogen.Paperclip</a></span> | ||||
|     </div> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| <script setup lang="ts"> | ||||
| definePageMeta({ | ||||
|   layout: "embed", | ||||
| }) | ||||
|  | ||||
| const route = useRoute() | ||||
| const config = useRuntimeConfig() | ||||
|  | ||||
| const firstImage = ref<string | null>() | ||||
| const firstVideo = ref<string | null>() | ||||
|  | ||||
| const { data: attachment } = await useFetch<any>(`${config.public.solarNetworkApi}/cgi/files/attachments/${route.params.id}/meta`) | ||||
|  | ||||
| if (!attachment.value) { | ||||
|   throw createError({ | ||||
|     statusCode: 404, | ||||
|     statusMessage: "Attachment Not Found", | ||||
|   }) | ||||
| } | ||||
|  | ||||
| const title = computed(() => `Attachment from ${attachment.value.account.nick}`) | ||||
|  | ||||
| watch(attachment, (value) => { | ||||
|   if (value.mimetype.split("/")[0] == "image") { | ||||
|     firstImage.value = `${config.public.solarNetworkApi}/cgi/files/attachments/${value.id}` | ||||
|   } | ||||
|  | ||||
|   if (value.mimetype.split("/")[0] == "video") { | ||||
|     firstVideo.value = `${config.public.solarNetworkApi}/cgi/files/attachments/${value.id}` | ||||
|   } | ||||
| }, { immediate: true, deep: true }) | ||||
|  | ||||
| useHead({ | ||||
|   title: title.value, | ||||
|   titleTemplate: "%s on Solar Network", | ||||
|   link: [ | ||||
|     { rel: "icon", type: "image/png", href: "/favicon-solian.png" }, | ||||
|     { rel: "apple-touch-icon", type: "image/png", href: "/favicon-solian.png" }, | ||||
|   ], | ||||
| }) | ||||
|  | ||||
| useSeoMeta({ | ||||
|   author: attachment.value?.account.nick, | ||||
|   title: title, | ||||
|   description: attachment.value?.alt, | ||||
|   ogTitle: title, | ||||
|   ogDescription: attachment.value?.alt, | ||||
|   ogUrl: `${useRuntimeConfig().public.siteUrl}${route.fullPath}`, | ||||
|   ogImage: firstImage, | ||||
|   ogVideo: firstVideo, | ||||
|   publisher: "Solar Network", | ||||
|   ogSiteName: "Solsynth Capital", | ||||
| }) | ||||
|  | ||||
| function formatBytes(bytes: number, decimals = 2) { | ||||
|   if (!+bytes) return "0 Bytes" | ||||
|  | ||||
|   const k = 1024 | ||||
|   const dm = decimals < 0 ? 0 : decimals | ||||
|   const sizes = ["Bytes", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB"] | ||||
|  | ||||
|   const i = Math.floor(Math.log(bytes) / Math.log(k)) | ||||
|  | ||||
|   return `${parseFloat((bytes / Math.pow(k, i)).toFixed(dm))} ${sizes[i]}` | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <style scoped> | ||||
| .section-header { | ||||
|   margin-left: 2.5ch; | ||||
|   margin-right: 2.5ch; | ||||
|   margin-bottom: 8px; | ||||
|  | ||||
|   @apply text-lg; | ||||
| } | ||||
| </style> | ||||
							
								
								
									
										58
									
								
								pages/embed/gallery/index.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								pages/embed/gallery/index.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,58 @@ | ||||
| <template> | ||||
|   <div> | ||||
|     <div class="mt-3 mb-6.5 mx-[3.5ch] text-center"> | ||||
|       <h1 class="text-2xl">{{ t("navGallery") }}</h1> | ||||
|       <span>{{ t("navGalleryCaption") }}</span> | ||||
|     </div> | ||||
|  | ||||
|     <div class="album"> | ||||
|       <v-card v-for="item in items" class="album-item mb-3" :to="`/gallery/${item.id}`"> | ||||
|         <attachment-renderer :item="item" /> | ||||
|       </v-card> | ||||
|  | ||||
|       <div class="flex p-5 justify-center items-center"> | ||||
|         <v-btn variant="outlined" text="Load more" :loading="loading" @click="load" /> | ||||
|       </div> | ||||
|     </div> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| <script setup lang="ts"> | ||||
| definePageMeta({ | ||||
|   layout: "embed", | ||||
| }) | ||||
|  | ||||
| const { t } = useI18n() | ||||
|  | ||||
| useHead({ | ||||
|   title: t("navGallery"), | ||||
| }) | ||||
|  | ||||
| useSeoMeta({ | ||||
|   title: t("navGallery"), | ||||
|   ogTitle: t("navGallery"), | ||||
|   description: t("navGalleryCaption"), | ||||
|   ogDescription: t("navGalleryCaption"), | ||||
|   ogType: "website", | ||||
| }) | ||||
|  | ||||
| const config = useRuntimeConfig() | ||||
|  | ||||
| const items = ref<any[]>([]) | ||||
| const loading = ref(false) | ||||
|  | ||||
| async function load() { | ||||
|   loading.value = true | ||||
|  | ||||
|   const res = await fetch(`${config.public.solarNetworkApi}/cgi/files/attachments?take=20&offset=${items.value.length}&original=true`) | ||||
|   const result = await res.json() | ||||
|  | ||||
|   items.value.push(...result.data) | ||||
|  | ||||
|   loading.value = false | ||||
| } | ||||
|  | ||||
| onMounted(() => { | ||||
|   load() | ||||
| }) | ||||
| </script> | ||||
							
								
								
									
										54
									
								
								pages/embed/users/[...name].vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								pages/embed/users/[...name].vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,54 @@ | ||||
| <template> | ||||
|   <div> | ||||
|     <v-img v-if="urlOfBanner" :src="urlOfBanner" :aspect-ratio="16 / 5" class="rounded-md mb-3" cover /> | ||||
|  | ||||
|     <div class="mx-[2.5ch]"> | ||||
|       <div class="my-5 flex flex-row gap-4"> | ||||
|         <v-avatar :image="urlOfAvatar" /> | ||||
|         <div class="flex flex-col"> | ||||
|           <span>{{ account?.nick }} <span class="text-xs">@{{ account?.name }}</span></span> | ||||
|           <span class="text-sm">{{ account?.description }}</span> | ||||
|         </div> | ||||
|       </div> | ||||
|  | ||||
|       <div class="mb-5 text-xs text-grey flex flex-col"> | ||||
|         <span>Solar Network User Web Preview</span> | ||||
|         <span> | ||||
|           To get full view of this user's profile, open it on <a class="underline" :href="externalOpenLink">Solian</a> | ||||
|         </span> | ||||
|       </div> | ||||
|  | ||||
|       <div> | ||||
|         <h1 class="text-xl">{{ t("userActivity") }}</h1> | ||||
|         <span>{{ t("userActivityCaption") }}</span> | ||||
|       </div> | ||||
|     </div> | ||||
|  | ||||
|     <post-list v-if="account" :author="account.name" /> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| <script setup lang="ts"> | ||||
| definePageMeta({ | ||||
|   layout: "embed", | ||||
|   alias: ["/embed/@:name(.*)*"], | ||||
| }) | ||||
|  | ||||
| const { t } = useI18n() | ||||
| const route = useRoute() | ||||
| const config = useRuntimeConfig() | ||||
|  | ||||
| const { data: account } = await useFetch<any>(`${config.public.solarNetworkApi}/cgi/auth/users/${route.params.name}`) | ||||
|  | ||||
| if (account.value == null) { | ||||
|   throw createError({ | ||||
|     statusCode: 404, | ||||
|     statusMessage: "User Not Found", | ||||
|   }) | ||||
| } | ||||
|  | ||||
| const urlOfAvatar = computed(() => account.value?.avatar ? `${config.public.solarNetworkApi}/cgi/files/attachments/${account.value.avatar}` : void 0) | ||||
| const urlOfBanner = computed(() => account.value?.banner ? `${config.public.solarNetworkApi}/cgi/files/attachments/${account.value.banner}` : void 0) | ||||
|  | ||||
| const externalOpenLink = computed(() => `${config.public.solianUrl}/accounts/view/${route.params.name}`) | ||||
| </script> | ||||
| @@ -37,8 +37,6 @@ const { t } = useI18n() | ||||
| const route = useRoute() | ||||
| const config = useRuntimeConfig() | ||||
|  | ||||
| const posts = ref<any[]>([]) | ||||
|  | ||||
| const { data: account } = await useFetch<any>(`${config.public.solarNetworkApi}/cgi/auth/users/${route.params.name}`) | ||||
|  | ||||
| if (account.value == null) { | ||||
| @@ -52,15 +50,6 @@ const urlOfAvatar = computed(() => account.value?.avatar ? `${config.public.sola | ||||
| const urlOfBanner = computed(() => account.value?.banner ? `${config.public.solarNetworkApi}/cgi/files/attachments/${account.value.banner}` : void 0) | ||||
|  | ||||
| const externalOpenLink = computed(() => `${config.public.solianUrl}/accounts/view/${route.params.name}`) | ||||
|  | ||||
| async function loadPost({ done }: any) { | ||||
|   const res = await fetch(`${config.public.solarNetworkApi}/cgi/interactive/posts?take=10&author=${route.params.name}&offset=${posts.value.length}`) | ||||
|   const result = await res.json() | ||||
|  | ||||
|   posts.value.push(...result.data) | ||||
|  | ||||
|   done("ok") | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <style scoped> | ||||
|   | ||||
| @@ -1,4 +1,5 @@ | ||||
| User-agent: * | ||||
| Disallow: /embed | ||||
| Allow: / | ||||
|  | ||||
| Sitemap: https://solsynth.dev/sitemap.xml | ||||
|   | ||||
		Reference in New Issue
	
	Block a user