Merge 8fdb31b55b into 67094980c9
				
					
				
			This commit is contained in:
		
						commit
						58ad2a2b87
					
				| @ -41,8 +41,10 @@ | ||||
|     "@tiptap/pm": "2.1.6", | ||||
|     "@tiptap/starter-kit": "2.1.6", | ||||
|     "@tiptap/vue-3": "2.0.3", | ||||
|     "@types/markdown-it": "^13.0.7", | ||||
|     "@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/tabler": "^0.12.0", | ||||
|     "@vueuse/core": "^10.3.0", | ||||
| @ -89,6 +91,7 @@ | ||||
|     "ulid": "^2.3.0", | ||||
|     "unicode-emoji-json": "^0.4.0", | ||||
|     "unplugin-auto-import": "^0.16.4", | ||||
|     "utf8": "^3.0.0", | ||||
|     "uuid": "^9.0.0", | ||||
|     "vue": "^3.3.4", | ||||
|     "vue-i18n": "^9.9.1", | ||||
| @ -136,6 +139,7 @@ | ||||
|     "unplugin-icons": "^0.17.0", | ||||
|     "unplugin-vue-components": "^0.25.0", | ||||
|     "vite": "^4.4.9", | ||||
|     "vite-plugin-node-polyfills": "^0.22.0", | ||||
|     "vite-plugin-pwa": "^0.16.0", | ||||
|     "vite-plugin-vue-markdown": "^0.23.5", | ||||
|     "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 basicAuthGenerator } from './basic-auth-generator'; | ||||
| import { tool as emailNormalizer } from './email-normalizer'; | ||||
| import { tool as unicodeSearch } from './unicode-search'; | ||||
| 
 | ||||
| import { tool as asciiTextDrawer } from './ascii-text-drawer'; | ||||
| 
 | ||||
| @ -135,6 +136,7 @@ export const toolsByCategory: ToolCategory[] = [ | ||||
|       httpStatusCodes, | ||||
|       jsonDiff, | ||||
|       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 svgLoader from 'vite-svg-loader'; | ||||
| import { configDefaults } from 'vitest/config'; | ||||
| import { nodePolyfills } from 'vite-plugin-node-polyfills'; | ||||
| 
 | ||||
| const baseUrl = process.env.BASE_URL ?? '/'; | ||||
| 
 | ||||
| @ -97,6 +98,7 @@ export default defineConfig({ | ||||
|       resolvers: [NaiveUiResolver(), IconsResolver({ prefix: 'icon' })], | ||||
|     }), | ||||
|     Unocss(), | ||||
|     nodePolyfills(), | ||||
|   ], | ||||
|   base: baseUrl, | ||||
|   resolve: { | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user