mirror of
https://github.com/CorentinTh/it-tools.git
synced 2025-05-03 21:09:12 -04:00
feat(new tool): Countries/ISO 3166 Searcher
Browser countries and iso 3166 codes (and more) FIx #983
This commit is contained in:
parent
1c35ac3704
commit
98db1e7238
7 changed files with 175 additions and 3 deletions
2
components.d.ts
vendored
2
components.d.ts
vendored
|
@ -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']
|
||||
|
|
|
@ -54,6 +54,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",
|
||||
|
@ -68,6 +69,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
21
pnpm-lock.yaml
generated
|
@ -59,6 +59,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
|
||||
|
@ -101,6 +104,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
|
||||
|
@ -3395,7 +3401,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:
|
||||
|
@ -4037,8 +4043,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:
|
||||
|
@ -4657,6 +4663,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
|
||||
|
@ -6492,6 +6502,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'}
|
||||
|
|
|
@ -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,
|
||||
],
|
||||
},
|
||||
{
|
||||
|
|
35
src/tools/iso-3166-searcher/countries-db.d.ts
vendored
Normal file
35
src/tools/iso-3166-searcher/countries-db.d.ts
vendored
Normal 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;
|
||||
}
|
12
src/tools/iso-3166-searcher/index.ts
Normal file
12
src/tools/iso-3166-searcher/index.ts
Normal 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'),
|
||||
});
|
104
src/tools/iso-3166-searcher/iso-3166-searcher.vue
Normal file
104
src/tools/iso-3166-searcher/iso-3166-searcher.vue
Normal 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">
|
||||
> See on OpenStreetMap
|
||||
</n-a>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</n-table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
Loading…
Add table
Add a link
Reference in a new issue