This commit is contained in:
sharevb 2024-11-30 23:50:38 +00:00 committed by GitHub
commit c442d9f040
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 175 additions and 3 deletions

2
components.d.ts vendored
View file

@ -107,6 +107,7 @@ declare module '@vue/runtime-core' {
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']
Ipv6UlaGenerator: typeof import('./src/tools/ipv6-ula-generator/ipv6-ula-generator.vue')['default']
Iso3166Searcher: typeof import('./src/tools/iso-3166-searcher/iso-3166-searcher.vue')['default']
JsonDiff: typeof import('./src/tools/json-diff/json-diff.vue')['default']
JsonMinify: typeof import('./src/tools/json-minify/json-minify.vue')['default']
JsonToCsv: typeof import('./src/tools/json-to-csv/json-to-csv.vue')['default']
@ -129,6 +130,7 @@ declare module '@vue/runtime-core' {
MenuLayout: typeof import('./src/components/MenuLayout.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']
NA: typeof import('naive-ui')['NA']
NavbarButtons: typeof import('./src/components/NavbarButtons.vue')['default']
NCheckbox: typeof import('naive-ui')['NCheckbox']
NCollapseTransition: typeof import('naive-ui')['NCollapseTransition']

View file

@ -55,6 +55,7 @@
"change-case": "^4.1.2",
"colord": "^2.9.3",
"composerize-ts": "^0.6.2",
"countries-db": "^1.2.0",
"country-code-lookup": "^0.1.0",
"cron-validator": "^1.3.1",
"cronstrue": "^2.26.0",
@ -69,6 +70,7 @@
"highlight.js": "^11.7.0",
"iarna-toml-esm": "^3.0.5",
"ibantools": "^4.3.3",
"iso-639-1": "^3.1.3",
"js-base64": "^3.7.6",
"json5": "^2.2.3",
"jwt-decode": "^3.1.2",

21
pnpm-lock.yaml generated
View file

@ -62,6 +62,9 @@ dependencies:
composerize-ts:
specifier: ^0.6.2
version: 0.6.2
countries-db:
specifier: ^1.2.0
version: 1.2.0
country-code-lookup:
specifier: ^0.1.0
version: 0.1.0
@ -104,6 +107,9 @@ dependencies:
ibantools:
specifier: ^4.3.3
version: 4.3.3
iso-639-1:
specifier: ^3.1.3
version: 3.1.3
js-base64:
specifier: ^3.7.6
version: 3.7.7
@ -3412,7 +3418,7 @@ packages:
dependencies:
'@unhead/dom': 0.5.1
'@unhead/schema': 0.5.1
'@vueuse/shared': 11.0.3(vue@3.3.4)
'@vueuse/shared': 11.1.0(vue@3.3.4)
unhead: 0.5.1
vue: 3.3.4
transitivePeerDependencies:
@ -4054,8 +4060,8 @@ packages:
- vue
dev: false
/@vueuse/shared@11.0.3(vue@3.3.4):
resolution: {integrity: sha512-0rY2m6HS5t27n/Vp5cTDsKTlNnimCqsbh/fmT2LgE+aaU42EMfXo8+bNX91W9I7DDmxfuACXMmrd7d79JxkqWA==}
/@vueuse/shared@11.1.0(vue@3.3.4):
resolution: {integrity: sha512-YUtIpY122q7osj+zsNMFAfMTubGz0sn5QzE5gPzAIiCmtt2ha3uQUY1+JPyL4gRCTsLPX82Y9brNbo/aqlA91w==}
dependencies:
vue-demi: 0.14.10(vue@3.3.4)
transitivePeerDependencies:
@ -4674,6 +4680,10 @@ packages:
browserslist: 4.22.1
dev: true
/countries-db@1.2.0:
resolution: {integrity: sha512-eZQgxVsNSRQ4yv9xQbgyR1psJBHDBhnhhU4OMXXUdrfbWW9gaiglKgueTq3ZWGuvxoR78g2ljVFsJmEptfNPmw==}
dev: false
/country-code-lookup@0.1.0:
resolution: {integrity: sha512-IOI66HEG+8bXfWPy+sTzuN7161vmDZOHg1wgIPFf3WfD73FeLajnn6C+fnxOIa9RL1WRBDMXQQWW/FOaOYaQ3w==}
dev: false
@ -6509,6 +6519,11 @@ packages:
resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
dev: true
/iso-639-1@3.1.3:
resolution: {integrity: sha512-1jz0Wh9hyLMRwqEPchb/KZCiTqfFWtc9R3nm7GHPygBAKS8wdKJ3FH4lvLsri6UtAE5Kz5SnowtXZa//6bqMyw==}
engines: {node: '>=6.0'}
dev: false
/isobject@3.0.1:
resolution: {integrity: sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==}
engines: {node: '>=0.10.0'}

View file

@ -12,6 +12,7 @@ import { tool as jsonToXml } from './json-to-xml';
import { tool as regexTester } from './regex-tester';
import { tool as regexMemo } from './regex-memo';
import { tool as markdownToHtml } from './markdown-to-html';
import { tool as iso3166Searcher } from './iso-3166-searcher';
import { tool as pdfSignatureChecker } from './pdf-signature-checker';
import { tool as numeronymGenerator } from './numeronym-generator';
import { tool as macAddressGenerator } from './mac-address-generator';
@ -184,6 +185,7 @@ export const toolsByCategory: ToolCategory[] = [
textDiff,
numeronymGenerator,
asciiTextDrawer,
iso3166Searcher,
],
},
{

View file

@ -0,0 +1,35 @@
declare module 'countries-db'{
export interface CountryInfo {
id: string
name: string
officialName: string
emoji: string
emojiUnicode: string
iso2: string
iso3: string
isoNumeric: string
geonameId: number
continentId: string
population: number
elevation: number
areaSqKm: number
coordinates: {
latitude: number
longitude: number
},
timezones: Array<string>
domain: string
currencyCode: string
currencyName: string
postalCodeFormat: string
postalCodeRegex: string
phoneCode: string
neighborCountryIds: Array<string>
languages: Array<string>
locales: Array<string>
}
export function getAllCountries(): {[id:string]: CountryInfo};
export function getCountry(id: string, property: string): string | Array<string> | number;
export function getCountry(id: string): CountryInfo;
}

View file

@ -0,0 +1,12 @@
import { Flag } from '@vicons/tabler';
import { defineTool } from '../tool';
export const tool = defineTool({
name: 'ISO 3166 Country Codes Searcher',
path: '/iso-3166-searcher',
description: 'Allow searching for Country Code (ISO 3166) and info',
keywords: ['iso', 'iso2', 'iso3', 'phone', 'currency', 'timezones', 'domain', 'lang', 'iso3166', 'country', 'ccltd', 'searcher'],
component: () => import('./iso-3166-searcher.vue'),
icon: Flag,
createdAt: new Date('2024-04-20'),
});

View file

@ -0,0 +1,104 @@
<script setup lang="ts">
import CountriesDB from 'countries-db';
import ISO6391 from 'iso-639-1';
import { useFuzzySearch } from '@/composable/fuzzySearch';
import useDebouncedRef from '@/composable/debouncedref';
const searchQuery = useDebouncedRef('', 500);
const countriesSearchData = Object.entries(CountriesDB.getAllCountries()).map(([_, info]) => {
return {
iso2: info.iso2,
iso3: info.iso3,
domain: info.domain,
name: `${info.name} ${info.officialName}`,
info,
};
});
const { searchResult } = useFuzzySearch({
search: searchQuery,
data: countriesSearchData,
options: {
keys: ['name', { name: 'iso3', weight: 3 }, { name: 'iso2', weight: 2 }, 'domain'],
threshold: 0.3,
isCaseSensitive: false,
useExtendedSearch: true,
},
});
function langToName(code: string) {
const name = ISO6391.getName(code);
if (!name) {
return code;
}
return `${code} (${name})`;
}
</script>
<template>
<div mx-auto max-w-2400px important:flex-1>
<div flex items-center gap-3>
<c-input-text
v-model:value="searchQuery"
placeholder="Search Countries by name, iso2, iso3..."
mx-auto max-w-600px
>
<template #prefix>
<icon-mdi-search mr-6px color-black op-70 dark:color-white />
</template>
</c-input-text>
</div>
<div v-if="searchQuery.trim().length > 0">
<div
v-if="searchResult.length === 0"
mt-4
text-20px
font-bold
>
No results
</div>
<div v-else>
<div mt-4 text-20px font-bold>
Search result
</div>
<n-table>
<thead>
<th>Iso2/Iso3</th>
<th>Name and Info</th>
</thead>
<tbody>
<tr v-for="(result, ix) in searchResult" :key="ix">
<td style="vertical-align: top">
<input-copyable :value="result.iso2" />
<input-copyable :value="result.iso3" />
</td>
<td>
<input-copyable label-width="150px" label="Name" label-position="left" :value="result.name" mb-1 />
<input-copyable label-width="150px" label="Official Name" label-position="left" :value="result.info.officialName" mb-1 />
<input-copyable label-width="150px" label="Domain" label-position="left" :value="result.info.domain" mb-1 />
<input-copyable label-width="150px" label="Emoji" label-position="left" :value="`${result.info.emoji} (${result.info.emojiUnicode})`" mb-1 />
<input-copyable label-width="150px" label="ISO Num" label-position="left" :value="result.info.isoNumeric" mb-1 />
<input-copyable label-width="150px" label="Continent" label-position="left" :value="result.info.continentId" mb-1 />
<input-copyable label-width="150px" label="Elevation (m)" label-position="left" :value="result.info.elevation" mb-1 />
<input-copyable label-width="150px" label="Population" label-position="left" :value="result.info.population" mb-1 />
<input-copyable label-width="150px" label="Area (km²)" label-position="left" :value="result.info.areaSqKm" mb-1 />
<input-copyable label-width="150px" label="Timezones" label-position="left" :value="result.info.timezones.join('\n')" mb-1 />
<input-copyable label-width="150px" label="Currency" label-position="left" :value="`${result.info.currencyCode} / ${result.info.currencyName}`" mb-1 />
<input-copyable label-width="150px" label="Postal Code" label-position="left" :value="`${result.info.postalCodeFormat} / ${result.info.postalCodeRegex}`" mb-1 />
<input-copyable label-width="150px" label="Phone Code" label-position="left" :value="result.info.phoneCode" mb-1 />
<input-copyable label-width="150px" label="Neighbor Countries" label-position="left" :value="result.info.neighborCountryIds.map(id => CountriesDB.getCountry(id, 'name')?.toString() || id).join(', ')" mb-1 />
<input-copyable label-width="150px" label="Languages" label-position="left" :value="result.info.languages.map(langToName).join(', ')" mb-1 />
<input-copyable label-width="150px" label="Locales" label-position="left" :value="result.info.locales.map(langToName).join(', ')" mb-1 />
<!-- //NOSONAR --><n-a :href="`https://www.openstreetmap.org/#map=5/${result.info.coordinates.latitude}/${result.info.coordinates.longitude}`" target="_blank">
&gt; See on OpenStreetMap
</n-a>
</td>
</tr>
</tbody>
</n-table>
</div>
</div>
</div>
</template>