Merge a0b8cf0301 into 87984e2081
				
					
				
			This commit is contained in:
		
						commit
						0ebb48fd38
					
				
							
								
								
									
										5
									
								
								components.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										5
									
								
								components.d.ts
									
									
									
									
										vendored
									
									
								
							| @ -103,6 +103,7 @@ declare module '@vue/runtime-core' { | |||||||
|     IconMdiTriangleDown: typeof import('~icons/mdi/triangle-down')['default'] |     IconMdiTriangleDown: typeof import('~icons/mdi/triangle-down')['default'] | ||||||
|     InputCopyable: typeof import('./src/components/InputCopyable.vue')['default'] |     InputCopyable: typeof import('./src/components/InputCopyable.vue')['default'] | ||||||
|     IntegerBaseConverter: typeof import('./src/tools/integer-base-converter/integer-base-converter.vue')['default'] |     IntegerBaseConverter: typeof import('./src/tools/integer-base-converter/integer-base-converter.vue')['default'] | ||||||
|  |     IpGeoLocation: typeof import('./src/tools/ip-geo-location/ip-geo-location.vue')['default'] | ||||||
|     Ipv4AddressConverter: typeof import('./src/tools/ipv4-address-converter/ipv4-address-converter.vue')['default'] |     Ipv4AddressConverter: typeof import('./src/tools/ipv4-address-converter/ipv4-address-converter.vue')['default'] | ||||||
|     Ipv4RangeExpander: typeof import('./src/tools/ipv4-range-expander/ipv4-range-expander.vue')['default'] |     Ipv4RangeExpander: typeof import('./src/tools/ipv4-range-expander/ipv4-range-expander.vue')['default'] | ||||||
|     Ipv4SubnetCalculator: typeof import('./src/tools/ipv4-subnet-calculator/ipv4-subnet-calculator.vue')['default'] |     Ipv4SubnetCalculator: typeof import('./src/tools/ipv4-subnet-calculator/ipv4-subnet-calculator.vue')['default'] | ||||||
| @ -129,6 +130,8 @@ declare module '@vue/runtime-core' { | |||||||
|     MenuLayout: typeof import('./src/components/MenuLayout.vue')['default'] |     MenuLayout: typeof import('./src/components/MenuLayout.vue')['default'] | ||||||
|     MetaTagGenerator: typeof import('./src/tools/meta-tag-generator/meta-tag-generator.vue')['default'] |     MetaTagGenerator: typeof import('./src/tools/meta-tag-generator/meta-tag-generator.vue')['default'] | ||||||
|     MimeTypes: typeof import('./src/tools/mime-types/mime-types.vue')['default'] |     MimeTypes: typeof import('./src/tools/mime-types/mime-types.vue')['default'] | ||||||
|  |     NA: typeof import('naive-ui')['NA'] | ||||||
|  |     NAlert: typeof import('naive-ui')['NAlert'] | ||||||
|     NavbarButtons: typeof import('./src/components/NavbarButtons.vue')['default'] |     NavbarButtons: typeof import('./src/components/NavbarButtons.vue')['default'] | ||||||
|     NButton: typeof import('naive-ui')['NButton'] |     NButton: typeof import('naive-ui')['NButton'] | ||||||
|     NCode: typeof import('naive-ui')['NCode'] |     NCode: typeof import('naive-ui')['NCode'] | ||||||
| @ -144,6 +147,8 @@ declare module '@vue/runtime-core' { | |||||||
|     NLayout: typeof import('naive-ui')['NLayout'] |     NLayout: typeof import('naive-ui')['NLayout'] | ||||||
|     NLayoutSider: typeof import('naive-ui')['NLayoutSider'] |     NLayoutSider: typeof import('naive-ui')['NLayoutSider'] | ||||||
|     NMenu: typeof import('naive-ui')['NMenu'] |     NMenu: typeof import('naive-ui')['NMenu'] | ||||||
|  |     NP: typeof import('naive-ui')['NP'] | ||||||
|  |     NProgress: typeof import('naive-ui')['NProgress'] | ||||||
|     NScrollbar: typeof import('naive-ui')['NScrollbar'] |     NScrollbar: typeof import('naive-ui')['NScrollbar'] | ||||||
|     NSlider: typeof import('naive-ui')['NSlider'] |     NSlider: typeof import('naive-ui')['NSlider'] | ||||||
|     NSwitch: typeof import('naive-ui')['NSwitch'] |     NSwitch: typeof import('naive-ui')['NSwitch'] | ||||||
|  | |||||||
| @ -6,6 +6,7 @@ import { tool as emailNormalizer } from './email-normalizer'; | |||||||
| import { tool as asciiTextDrawer } from './ascii-text-drawer'; | import { tool as asciiTextDrawer } from './ascii-text-drawer'; | ||||||
| 
 | 
 | ||||||
| import { tool as textToUnicode } from './text-to-unicode'; | import { tool as textToUnicode } from './text-to-unicode'; | ||||||
|  | import { tool as ipGeoLocation } from './ip-geo-location'; | ||||||
| import { tool as safelinkDecoder } from './safelink-decoder'; | import { tool as safelinkDecoder } from './safelink-decoder'; | ||||||
| import { tool as xmlToJson } from './xml-to-json'; | import { tool as xmlToJson } from './xml-to-json'; | ||||||
| import { tool as jsonToXml } from './json-to-xml'; | import { tool as jsonToXml } from './json-to-xml'; | ||||||
| @ -160,7 +161,15 @@ export const toolsByCategory: ToolCategory[] = [ | |||||||
|   }, |   }, | ||||||
|   { |   { | ||||||
|     name: 'Network', |     name: 'Network', | ||||||
|     components: [ipv4SubnetCalculator, ipv4AddressConverter, ipv4RangeExpander, macAddressLookup, macAddressGenerator, ipv6UlaGenerator], |     components: [ | ||||||
|  |       ipv4SubnetCalculator, | ||||||
|  |       ipv4AddressConverter, | ||||||
|  |       ipv4RangeExpander, | ||||||
|  |       macAddressLookup, | ||||||
|  |       macAddressGenerator, | ||||||
|  |       ipv6UlaGenerator, | ||||||
|  |       ipGeoLocation, | ||||||
|  |     ], | ||||||
|   }, |   }, | ||||||
|   { |   { | ||||||
|     name: 'Math', |     name: 'Math', | ||||||
|  | |||||||
							
								
								
									
										12
									
								
								src/tools/ip-geo-location/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								src/tools/ip-geo-location/index.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,12 @@ | |||||||
|  | import { World } from '@vicons/tabler'; | ||||||
|  | import { defineTool } from '../tool'; | ||||||
|  | 
 | ||||||
|  | export const tool = defineTool({ | ||||||
|  |   name: 'IP Geo Location', | ||||||
|  |   path: '/ip-geo-location', | ||||||
|  |   description: 'Retrieve information about an IPv4/6 address or domain location', | ||||||
|  |   keywords: ['ip', 'domain', 'geo', 'location'], | ||||||
|  |   component: () => import('./ip-geo-location.vue'), | ||||||
|  |   icon: World, | ||||||
|  |   createdAt: new Date('2024-01-17'), | ||||||
|  | }); | ||||||
							
								
								
									
										116
									
								
								src/tools/ip-geo-location/ip-geo-location.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										116
									
								
								src/tools/ip-geo-location/ip-geo-location.vue
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,116 @@ | |||||||
|  | <script setup lang="ts"> | ||||||
|  | import type { CKeyValueListItems } from '@/ui/c-key-value-list/c-key-value-list.types'; | ||||||
|  | 
 | ||||||
|  | const ip = ref('8.8.8.8'); | ||||||
|  | const errorMessage = ref(''); | ||||||
|  | 
 | ||||||
|  | const fields: Array<{ field: string; name: string }> = [ | ||||||
|  |   { field: 'ip', name: 'IP' }, | ||||||
|  |   { field: 'hostname', name: 'Host Name' }, | ||||||
|  |   { field: 'country', name: 'Country Code' }, | ||||||
|  |   { field: 'region', name: 'Region/state Code' }, | ||||||
|  |   { field: 'city', name: 'City' }, | ||||||
|  |   { field: 'postal', name: 'Postal Code' }, | ||||||
|  |   { field: 'loc', name: 'Latitude/Longitude' }, | ||||||
|  |   { field: 'timezone', name: 'Timezone' }, | ||||||
|  |   { field: 'org', name: 'Organization Name' }, | ||||||
|  | ]; | ||||||
|  | 
 | ||||||
|  | const geoInfos = ref<CKeyValueListItems>([]); | ||||||
|  | const geoInfosData = ref<{ | ||||||
|  |   loc?: string | ||||||
|  | }>({}); | ||||||
|  | const status = ref<'pending' | 'error' | 'success'>('pending'); | ||||||
|  | const token = useStorage('ip-geoloc:token', ''); | ||||||
|  | 
 | ||||||
|  | const openStreetMapUrl = computed( | ||||||
|  |   () => { | ||||||
|  |     const [gpsLatitude, gpsLongitude] = geoInfosData.value.loc?.split(',') || []; | ||||||
|  |     return gpsLatitude && gpsLongitude ? `https://www.openstreetmap.org/?mlat=${gpsLatitude}&mlon=${gpsLongitude}#map=18/${gpsLatitude}/${gpsLongitude}` : undefined; | ||||||
|  |   }, | ||||||
|  | ); | ||||||
|  | 
 | ||||||
|  | async function onGetInfos() { | ||||||
|  |   try { | ||||||
|  |     status.value = 'pending'; | ||||||
|  | 
 | ||||||
|  |     const geoInfoQueryResponse = await fetch( | ||||||
|  |       token.value !== '' | ||||||
|  |         ? `https://ipinfo.io/${ip.value}/json?token=${token.value}` | ||||||
|  |         : `https://ipinfo.io/${ip.value}/json`); | ||||||
|  |     if (!geoInfoQueryResponse.ok) { | ||||||
|  |       throw geoInfoQueryResponse.statusText; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     const data = await geoInfoQueryResponse.json(); | ||||||
|  | 
 | ||||||
|  |     const allGeoInfos = []; | ||||||
|  |     for (const field of fields) { | ||||||
|  |       if (data[field.field]) { | ||||||
|  |         allGeoInfos.push({ | ||||||
|  |           label: field.name, | ||||||
|  |           value: data[field.field], | ||||||
|  |         }); | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     status.value = 'success'; | ||||||
|  |     geoInfos.value = allGeoInfos; | ||||||
|  |     geoInfosData.value = data; | ||||||
|  |   } | ||||||
|  |   catch (e: any) { | ||||||
|  |     errorMessage.value = e.toString(); | ||||||
|  |     status.value = 'error'; | ||||||
|  |     return []; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </script> | ||||||
|  | 
 | ||||||
|  | <template> | ||||||
|  |   <div> | ||||||
|  |     <div flex items-center gap-2> | ||||||
|  |       <c-input-text | ||||||
|  |         v-model:value="ip" | ||||||
|  |         placeholder="Enter an IPv4/6" | ||||||
|  |         @update:value="() => { status = 'pending' }" | ||||||
|  |       /> | ||||||
|  |       <c-button align-center @click="onGetInfos"> | ||||||
|  |         Get GEO Location Infos | ||||||
|  |       </c-button> | ||||||
|  |     </div> | ||||||
|  | 
 | ||||||
|  |     <details mt-2> | ||||||
|  |       <summary>Optional ipinfo.io token</summary> | ||||||
|  |       <c-input-text | ||||||
|  |         v-model:value="token" | ||||||
|  |         placeholder="Optional ipinfo.io token" | ||||||
|  |         @update:value="() => { status = 'pending' }" | ||||||
|  |       /> | ||||||
|  |       <n-p> | ||||||
|  |         <n-a href="https://ipinfo.io/"> | ||||||
|  |           Signup for a free token | ||||||
|  |         </n-a> | ||||||
|  |       </n-p> | ||||||
|  |     </details> | ||||||
|  | 
 | ||||||
|  |     <n-divider /> | ||||||
|  | 
 | ||||||
|  |     <c-card v-if="status === 'pending'" mt-5> | ||||||
|  |       Click on button above to get latest infos | ||||||
|  |     </c-card> | ||||||
|  | 
 | ||||||
|  |     <c-card v-if="status === 'success' && openStreetMapUrl" mt-4> | ||||||
|  |       <c-button :href="openStreetMapUrl" target="_blank"> | ||||||
|  |         Localize on Open Street Map | ||||||
|  |       </c-button> | ||||||
|  |     </c-card> | ||||||
|  | 
 | ||||||
|  |     <c-card v-if="status === 'success'" mt-5> | ||||||
|  |       <c-key-value-list :items="geoInfos" /> | ||||||
|  |     </c-card> | ||||||
|  | 
 | ||||||
|  |     <n-alert v-if="status === 'error'" title="Errors occured" type="error" mt-5> | ||||||
|  |       {{ errorMessage }} | ||||||
|  |     </n-alert> | ||||||
|  |   </div> | ||||||
|  | </template> | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user