mirror of
https://github.com/CorentinTh/it-tools.git
synced 2025-05-04 05:19:12 -04:00
parent
67094980c9
commit
8fdb31b55b
7 changed files with 799 additions and 1 deletions
|
@ -41,8 +41,10 @@
|
||||||
"@tiptap/pm": "2.1.6",
|
"@tiptap/pm": "2.1.6",
|
||||||
"@tiptap/starter-kit": "2.1.6",
|
"@tiptap/starter-kit": "2.1.6",
|
||||||
"@tiptap/vue-3": "2.0.3",
|
"@tiptap/vue-3": "2.0.3",
|
||||||
"@types/markdown-it": "^13.0.7",
|
|
||||||
"@types/figlet": "^1.5.8",
|
"@types/figlet": "^1.5.8",
|
||||||
|
"@types/markdown-it": "^13.0.7",
|
||||||
|
"@types/utf8": "^3.0.3",
|
||||||
|
"@unicode/unicode-15.1.0": "^1.6.0",
|
||||||
"@vicons/material": "^0.12.0",
|
"@vicons/material": "^0.12.0",
|
||||||
"@vicons/tabler": "^0.12.0",
|
"@vicons/tabler": "^0.12.0",
|
||||||
"@vueuse/core": "^10.3.0",
|
"@vueuse/core": "^10.3.0",
|
||||||
|
@ -89,6 +91,7 @@
|
||||||
"ulid": "^2.3.0",
|
"ulid": "^2.3.0",
|
||||||
"unicode-emoji-json": "^0.4.0",
|
"unicode-emoji-json": "^0.4.0",
|
||||||
"unplugin-auto-import": "^0.16.4",
|
"unplugin-auto-import": "^0.16.4",
|
||||||
|
"utf8": "^3.0.0",
|
||||||
"uuid": "^9.0.0",
|
"uuid": "^9.0.0",
|
||||||
"vue": "^3.3.4",
|
"vue": "^3.3.4",
|
||||||
"vue-i18n": "^9.9.1",
|
"vue-i18n": "^9.9.1",
|
||||||
|
@ -136,6 +139,7 @@
|
||||||
"unplugin-icons": "^0.17.0",
|
"unplugin-icons": "^0.17.0",
|
||||||
"unplugin-vue-components": "^0.25.0",
|
"unplugin-vue-components": "^0.25.0",
|
||||||
"vite": "^4.4.9",
|
"vite": "^4.4.9",
|
||||||
|
"vite-plugin-node-polyfills": "^0.22.0",
|
||||||
"vite-plugin-pwa": "^0.16.0",
|
"vite-plugin-pwa": "^0.16.0",
|
||||||
"vite-plugin-vue-markdown": "^0.23.5",
|
"vite-plugin-vue-markdown": "^0.23.5",
|
||||||
"vite-svg-loader": "^4.0.0",
|
"vite-svg-loader": "^4.0.0",
|
||||||
|
|
647
pnpm-lock.yaml
generated
647
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load diff
|
@ -2,6 +2,7 @@ import { tool as base64FileConverter } from './base64-file-converter';
|
||||||
import { tool as base64StringConverter } from './base64-string-converter';
|
import { tool as base64StringConverter } from './base64-string-converter';
|
||||||
import { tool as basicAuthGenerator } from './basic-auth-generator';
|
import { tool as basicAuthGenerator } from './basic-auth-generator';
|
||||||
import { tool as emailNormalizer } from './email-normalizer';
|
import { tool as emailNormalizer } from './email-normalizer';
|
||||||
|
import { tool as unicodeSearch } from './unicode-search';
|
||||||
|
|
||||||
import { tool as asciiTextDrawer } from './ascii-text-drawer';
|
import { tool as asciiTextDrawer } from './ascii-text-drawer';
|
||||||
|
|
||||||
|
@ -135,6 +136,7 @@ export const toolsByCategory: ToolCategory[] = [
|
||||||
httpStatusCodes,
|
httpStatusCodes,
|
||||||
jsonDiff,
|
jsonDiff,
|
||||||
safelinkDecoder,
|
safelinkDecoder,
|
||||||
|
unicodeSearch,
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
12
src/tools/unicode-search/index.ts
Normal file
12
src/tools/unicode-search/index.ts
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
import { FileText } from '@vicons/tabler';
|
||||||
|
import { defineTool } from '../tool';
|
||||||
|
|
||||||
|
export const tool = defineTool({
|
||||||
|
name: 'Unicode Search',
|
||||||
|
path: '/unicode-search',
|
||||||
|
description: 'Search in Unicode Characters',
|
||||||
|
keywords: ['unicode', 'search'],
|
||||||
|
component: () => import('./unicode-search.vue'),
|
||||||
|
icon: FileText,
|
||||||
|
createdAt: new Date('2024-08-15'),
|
||||||
|
});
|
122
src/tools/unicode-search/unicode-search.vue
Normal file
122
src/tools/unicode-search/unicode-search.vue
Normal file
|
@ -0,0 +1,122 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import unicodeNames from '@unicode/unicode-15.1.0/Names/index.js';
|
||||||
|
import unicodeCategories from '@unicode/unicode-15.1.0/General_Category';
|
||||||
|
import utf8 from 'utf8';
|
||||||
|
|
||||||
|
import { useFuzzySearch } from '@/composable/fuzzySearch';
|
||||||
|
import useDebouncedRef from '@/composable/debouncedref';
|
||||||
|
|
||||||
|
function toPaddedHex(num: number) {
|
||||||
|
return num.toString(16).padStart(4, '0').toUpperCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
function toUTF8(codePoint: number) {
|
||||||
|
const utf8String = utf8.encode(String.fromCodePoint(codePoint));
|
||||||
|
return [...utf8String].map(c => `\\x${c.codePointAt(0)?.toString(16).toUpperCase()}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const searchQuery = useDebouncedRef('', 500);
|
||||||
|
const parsedSearchQuery = computed(() => {
|
||||||
|
const parsedRegex = /^\s*(?:\&#x(?<hex1>[\da-f]+);|\&#(?<dec>\d+);|(?:U\+|\\u)?\s*(?<hex2>[\da-f]+))\s*$/gi; // NOSONAR
|
||||||
|
const parsedQuery = parsedRegex.exec(searchQuery.value);
|
||||||
|
if (parsedQuery) {
|
||||||
|
if (parsedQuery.groups?.hex1 || parsedQuery.groups?.hex2) {
|
||||||
|
return `=${toPaddedHex(Number.parseInt(parsedQuery.groups.hex1 || parsedQuery.groups.hex2, 16))}`;
|
||||||
|
}
|
||||||
|
if (parsedQuery.groups?.dec) {
|
||||||
|
return `=${toPaddedHex(Number.parseInt(parsedQuery.groups.dec, 10))}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return searchQuery.value;
|
||||||
|
});
|
||||||
|
|
||||||
|
const unicodeSearchData = [...unicodeNames].map(([codePoint, characterName]) => {
|
||||||
|
const hex = toPaddedHex(codePoint);
|
||||||
|
return {
|
||||||
|
codePoint,
|
||||||
|
characterName: `${characterName} (U+${hex})`,
|
||||||
|
hex,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
const { searchResult } = useFuzzySearch({
|
||||||
|
search: parsedSearchQuery,
|
||||||
|
data: unicodeSearchData,
|
||||||
|
options: {
|
||||||
|
keys: ['characterName', 'hex'],
|
||||||
|
threshold: 0.2,
|
||||||
|
isCaseSensitive: false,
|
||||||
|
minMatchCharLength: 3,
|
||||||
|
useExtendedSearch: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</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 Unicode by name (e.g. 'zero width') or code point..."
|
||||||
|
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>UCOD</th>
|
||||||
|
<th>Display/UTF8</th>
|
||||||
|
<th style="width:30%">
|
||||||
|
Category
|
||||||
|
</th>
|
||||||
|
<th>Html</th>
|
||||||
|
<th style="width:30%">
|
||||||
|
Name
|
||||||
|
</th>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr v-for="(result, ix) in searchResult" :key="ix">
|
||||||
|
<td>
|
||||||
|
<input-copyable :value="`U+${toPaddedHex(result.codePoint)}`" mb-1 />
|
||||||
|
<!-- //NOSONAR --><n-a :href="`https://unicodeplus.com/U+${toPaddedHex(result.codePoint)}`" target="_blank">
|
||||||
|
> More info
|
||||||
|
</n-a>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input-copyable :value="String.fromCodePoint(result.codePoint)" mb-1 />
|
||||||
|
<input-copyable :value="toUTF8(result.codePoint)" />
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input-copyable :value="unicodeCategories.get(result.codePoint)" />
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input-copyable :value="`\&\#x${toPaddedHex(result.codePoint)};`" mb-1 />
|
||||||
|
<input-copyable :value="`\&\#${result.codePoint};`" />
|
||||||
|
</td>
|
||||||
|
<td><input-copyable :value="result.characterName" /></td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</n-table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
9
src/tools/unicode-search/unicode.d.ts
vendored
Normal file
9
src/tools/unicode-search/unicode.d.ts
vendored
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
declare module '@unicode/unicode-15.1.0/Names/index.js'{
|
||||||
|
const unicode: HashSet<number, string>;
|
||||||
|
export default unicode;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare module '@unicode/unicode-15.1.0/General_Category'{
|
||||||
|
const unicode: HashSet<number, string>;
|
||||||
|
export default unicode;
|
||||||
|
}
|
|
@ -15,6 +15,7 @@ import { VitePWA } from 'vite-plugin-pwa';
|
||||||
import markdown from 'vite-plugin-vue-markdown';
|
import markdown from 'vite-plugin-vue-markdown';
|
||||||
import svgLoader from 'vite-svg-loader';
|
import svgLoader from 'vite-svg-loader';
|
||||||
import { configDefaults } from 'vitest/config';
|
import { configDefaults } from 'vitest/config';
|
||||||
|
import { nodePolyfills } from 'vite-plugin-node-polyfills';
|
||||||
|
|
||||||
const baseUrl = process.env.BASE_URL ?? '/';
|
const baseUrl = process.env.BASE_URL ?? '/';
|
||||||
|
|
||||||
|
@ -97,6 +98,7 @@ export default defineConfig({
|
||||||
resolvers: [NaiveUiResolver(), IconsResolver({ prefix: 'icon' })],
|
resolvers: [NaiveUiResolver(), IconsResolver({ prefix: 'icon' })],
|
||||||
}),
|
}),
|
||||||
Unocss(),
|
Unocss(),
|
||||||
|
nodePolyfills(),
|
||||||
],
|
],
|
||||||
base: baseUrl,
|
base: baseUrl,
|
||||||
resolve: {
|
resolve: {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue