diff --git a/components.d.ts b/components.d.ts index e31119b3..7424161c 100644 --- a/components.d.ts +++ b/components.d.ts @@ -127,24 +127,18 @@ declare module '@vue/runtime-core' { MetaTagGenerator: typeof import('./src/tools/meta-tag-generator/meta-tag-generator.vue')['default'] MimeTypes: typeof import('./src/tools/mime-types/mime-types.vue')['default'] NavbarButtons: typeof import('./src/components/NavbarButtons.vue')['default'] - NCode: typeof import('naive-ui')['NCode'] + NButton: typeof import('naive-ui')['NButton'] NCollapseTransition: typeof import('naive-ui')['NCollapseTransition'] NConfigProvider: typeof import('naive-ui')['NConfigProvider'] - NDivider: typeof import('naive-ui')['NDivider'] NEllipsis: typeof import('naive-ui')['NEllipsis'] NFormItem: typeof import('naive-ui')['NFormItem'] - NGi: typeof import('naive-ui')['NGi'] - NGrid: typeof import('naive-ui')['NGrid'] NH1: typeof import('naive-ui')['NH1'] NH3: typeof import('naive-ui')['NH3'] NIcon: typeof import('naive-ui')['NIcon'] - NInputNumber: typeof import('naive-ui')['NInputNumber'] - NLabel: typeof import('naive-ui')['NLabel'] NLayout: typeof import('naive-ui')['NLayout'] NLayoutSider: typeof import('naive-ui')['NLayoutSider'] NMenu: typeof import('naive-ui')['NMenu'] - NScrollbar: typeof import('naive-ui')['NScrollbar'] - NSpin: typeof import('naive-ui')['NSpin'] + NSpace: typeof import('naive-ui')['NSpace'] NumeronymGenerator: typeof import('./src/tools/numeronym-generator/numeronym-generator.vue')['default'] OtpCodeGeneratorAndValidator: typeof import('./src/tools/otp-code-generator-and-validator/otp-code-generator-and-validator.vue')['default'] PasswordStrengthAnalyser: typeof import('./src/tools/password-strength-analyser/password-strength-analyser.vue')['default'] @@ -159,6 +153,7 @@ declare module '@vue/runtime-core' { RouterLink: typeof import('vue-router')['RouterLink'] RouterView: typeof import('vue-router')['RouterView'] RsaKeyPairGenerator: typeof import('./src/tools/rsa-key-pair-generator/rsa-key-pair-generator.vue')['default'] + SafelinkDecoder: typeof import('./src/tools/safelink-decoder/safelink-decoder.vue')['default'] SlugifyString: typeof import('./src/tools/slugify-string/slugify-string.vue')['default'] SpanCopyable: typeof import('./src/components/SpanCopyable.vue')['default'] SqlPrettify: typeof import('./src/tools/sql-prettify/sql-prettify.vue')['default'] @@ -178,6 +173,7 @@ declare module '@vue/runtime-core' { 'Tool.layout': typeof import('./src/layouts/tool.layout.vue')['default'] ToolCard: typeof import('./src/components/ToolCard.vue')['default'] UlidGenerator: typeof import('./src/tools/ulid-generator/ulid-generator.vue')['default'] + UnicodeFormatter: typeof import('./src/tools/unicode-formatter/unicode-formatter.vue')['default'] UrlEncoder: typeof import('./src/tools/url-encoder/url-encoder.vue')['default'] UrlParser: typeof import('./src/tools/url-parser/url-parser.vue')['default'] UserAgentParser: typeof import('./src/tools/user-agent-parser/user-agent-parser.vue')['default'] diff --git a/src/tools/index.ts b/src/tools/index.ts index aa861c93..249c05d0 100644 --- a/src/tools/index.ts +++ b/src/tools/index.ts @@ -6,6 +6,7 @@ import { tool as asciiTextDrawer } from './ascii-text-drawer'; import { tool as textToUnicode } from './text-to-unicode'; import { tool as safelinkDecoder } from './safelink-decoder'; +import { tool as unicodeFormatter } from './unicode-formatter'; import { tool as pdfSignatureChecker } from './pdf-signature-checker'; import { tool as numeronymGenerator } from './numeronym-generator'; import { tool as macAddressGenerator } from './mac-address-generator'; @@ -172,6 +173,7 @@ export const toolsByCategory: ToolCategory[] = [ textDiff, numeronymGenerator, asciiTextDrawer, + unicodeFormatter, ], }, { diff --git a/src/tools/unicode-formatter/index.ts b/src/tools/unicode-formatter/index.ts new file mode 100644 index 00000000..69f081ec --- /dev/null +++ b/src/tools/unicode-formatter/index.ts @@ -0,0 +1,12 @@ +import { Edit } from '@vicons/tabler'; +import { defineTool } from '../tool'; + +export const tool = defineTool({ + name: 'Unicode Formatter', + path: '/unicode-formatter', + description: 'Format text using Unicode fonts', + keywords: ['unicode', 'formatter', 'fonts'], + component: () => import('./unicode-formatter.vue'), + icon: Edit, + createdAt: new Date('2024-04-07'), +}); diff --git a/src/tools/unicode-formatter/unicode-fonts.json b/src/tools/unicode-formatter/unicode-fonts.json new file mode 100644 index 00000000..7efc8da4 --- /dev/null +++ b/src/tools/unicode-formatter/unicode-fonts.json @@ -0,0 +1,29 @@ +{ + "normal": "\"\\ !#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz{|}~", + "sans": "\"\\ !#$%&'()*+,-./๐Ÿข๐Ÿฃ๐Ÿค๐Ÿฅ๐Ÿฆ๐Ÿง๐Ÿจ๐Ÿฉ๐Ÿช๐Ÿซ:;<=>?@๐– ๐–ก๐–ข๐–ฃ๐–ค๐–ฅ๐–ฆ๐–ง๐–จ๐–ฉ๐–ช๐–ซ๐–ฌ๐–ญ๐–ฎ๐–ฏ๐–ฐ๐–ฑ๐–ฒ๐–ณ๐–ด๐–ต๐–ถ๐–ท๐–ธ๐–น[]^_`๐–บ๐–ป๐–ผ๐–ฝ๐–พ๐–ฟ๐—€๐—๐—‚๐—ƒ๐—„๐—…๐—†๐—‡๐—ˆ๐—‰๐—Š๐—‹๐—Œ๐—๐—Ž๐—๐—๐—‘๐—’๐—“{|}~", + "sansBold": "\"\\ !#$%&'()*+,-./๐Ÿฌ๐Ÿญ๐Ÿฎ๐Ÿฏ๐Ÿฐ๐Ÿฑ๐Ÿฒ๐Ÿณ๐Ÿด๐Ÿต:;<=>?@๐—”๐—•๐—–๐——๐—˜๐—™๐—š๐—›๐—œ๐—๐—ž๐—Ÿ๐— ๐—ก๐—ข๐—ฃ๐—ค๐—ฅ๐—ฆ๐—ง๐—จ๐—ฉ๐—ช๐—ซ๐—ฌ๐—ญ[]^_`๐—ฎ๐—ฏ๐—ฐ๐—ฑ๐—ฒ๐—ณ๐—ด๐—ต๐—ถ๐—ท๐—ธ๐—น๐—บ๐—ป๐—ผ๐—ฝ๐—พ๐—ฟ๐˜€๐˜๐˜‚๐˜ƒ๐˜„๐˜…๐˜†๐˜‡{|}~", + "sansItalic": "\"\\ !#$%&'()*+,-./0123456789:;<=>?@๐˜ˆ๐˜‰๐˜Š๐˜‹๐˜Œ๐˜๐˜Ž๐˜๐˜๐˜‘๐˜’๐˜“๐˜”๐˜•๐˜–๐˜—๐˜˜๐˜™๐˜š๐˜›๐˜œ๐˜๐˜ž๐˜Ÿ๐˜ ๐˜ก[]^_`๐˜ข๐˜ฃ๐˜ค๐˜ฅ๐˜ฆ๐˜ง๐˜จ๐˜ฉ๐˜ช๐˜ซ๐˜ฌ๐˜ญ๐˜ฎ๐˜ฏ๐˜ฐ๐˜ฑ๐˜ฒ๐˜ณ๐˜ด๐˜ต๐˜ถ๐˜ท๐˜ธ๐˜น๐˜บ๐˜ป{|}~", + "sansBoldItalic": "\"\\ !#$%&'()*+,-./0123456789:;<=>?@๐˜ผ๐˜ฝ๐˜พ๐˜ฟ๐™€๐™๐™‚๐™ƒ๐™„๐™…๐™†๐™‡๐™ˆ๐™‰๐™Š๐™‹๐™Œ๐™๐™Ž๐™๐™๐™‘๐™’๐™“๐™”๐™•[]^_`๐™–๐™—๐™˜๐™™๐™š๐™›๐™œ๐™๐™ž๐™Ÿ๐™ ๐™ก๐™ข๐™ฃ๐™ค๐™ฅ๐™ฆ๐™ง๐™จ๐™ฉ๐™ช๐™ซ๐™ฌ๐™ญ๐™ฎ๐™ฏ{|}~", + "monospace": "\"\\โ€‚!#$%&'()*+,-./๐Ÿถ๐Ÿท๐Ÿธ๐Ÿน๐Ÿบ๐Ÿป๐Ÿผ๐Ÿฝ๐Ÿพ๐Ÿฟ:;<=>?@๐™ฐ๐™ฑ๐™ฒ๐™ณ๐™ด๐™ต๐™ถ๐™ท๐™ธ๐™น๐™บ๐™ป๐™ผ๐™ฝ๐™พ๐™ฟ๐š€๐š๐š‚๐šƒ๐š„๐š…๐š†๐š‡๐šˆ๐š‰[]^_`๐šŠ๐š‹๐šŒ๐š๐šŽ๐š๐š๐š‘๐š’๐š“๐š”๐š•๐š–๐š—๐š˜๐š™๐šš๐š›๐šœ๐š๐šž๐šŸ๐š ๐šก๐šข๐šฃ{|}~", + "fullwidth": "\"๏ผผใ€€๏ผ๏ผƒ๏ผ„๏ผ…๏ผ†๏ผ‡๏ผˆ๏ผ‰๏ผŠ๏ผ‹๏ผŒ๏ผ๏ผŽ๏ผ๏ผ๏ผ‘๏ผ’๏ผ“๏ผ”๏ผ•๏ผ–๏ผ—๏ผ˜๏ผ™๏ผš๏ผ›<๏ผ>๏ผŸ๏ผ ๏ผก๏ผข๏ผฃ๏ผค๏ผฅ๏ผฆ๏ผง๏ผจ๏ผฉ๏ผช๏ผซ๏ผฌ๏ผญ๏ผฎ๏ผฏ๏ผฐ๏ผฑ๏ผฒ๏ผณ๏ผด๏ผต๏ผถ๏ผท๏ผธ๏ผน๏ผบ๏ผป๏ผฝ๏ผพ๏ผฟ๏ฝ€๏ฝ๏ฝ‚๏ฝƒ๏ฝ„๏ฝ…๏ฝ†๏ฝ‡๏ฝˆ๏ฝ‰๏ฝŠ๏ฝ‹๏ฝŒ๏ฝ๏ฝŽ๏ฝ๏ฝ๏ฝ‘๏ฝ’๏ฝ“๏ฝ”๏ฝ•๏ฝ–๏ฝ—๏ฝ˜๏ฝ™๏ฝš๏ฝ›๏ฝœ๏ฝ๏ฝž", + "fraktur": "\"\\ !#$%&'()*+,-./0123456789:;<=>?@๐”„๐”…โ„ญ๐”‡๐”ˆ๐”‰๐”Šโ„Œโ„‘๐”๐”Ž๐”๐”๐”‘๐”’๐”“๐””โ„œ๐”–๐”—๐”˜๐”™๐”š๐”›๐”œโ„จ[]^_`๐”ž๐”Ÿ๐” ๐”ก๐”ข๐”ฃ๐”ค๐”ฅ๐”ฆ๐”ง๐”จ๐”ฉ๐”ช๐”ซ๐”ฌ๐”ญ๐”ฎ๐”ฏ๐”ฐ๐”ฑ๐”ฒ๐”ณ๐”ด๐”ต๐”ถ๐”ท{|}~", + "boldFraktur": "\"\\ !#$%&'()*+,-./0123456789:;<=>?@๐•ฌ๐•ญ๐•ฎ๐•ฏ๐•ฐ๐•ฑ๐•ฒ๐•ณ๐•ด๐•ต๐•ถ๐•ท๐•ธ๐•น๐•บ๐•ป๐•ผ๐•ฝ๐•พ๐•ฟ๐–€๐–๐–‚๐–ƒ๐–„๐–…[]^_`๐–†๐–‡๐–ˆ๐–‰๐–Š๐–‹๐–Œ๐–๐–Ž๐–๐–๐–‘๐–’๐–“๐–”๐–•๐––๐–—๐–˜๐–™๐–š๐–›๐–œ๐–๐–ž๐–Ÿ{|}~", + "serifBold": "\"\\ !#$%&'()*+,-./๐ŸŽ๐Ÿ๐Ÿ๐Ÿ‘๐Ÿ’๐Ÿ“๐Ÿ”๐Ÿ•๐Ÿ–๐Ÿ—:;<=>?@๐€๐๐‚๐ƒ๐„๐…๐†๐‡๐ˆ๐‰๐Š๐‹๐Œ๐๐Ž๐๐๐‘๐’๐“๐”๐•๐–๐—๐˜๐™[]^_`๐š๐›๐œ๐๐ž๐Ÿ๐ ๐ก๐ข๐ฃ๐ค๐ฅ๐ฆ๐ง๐จ๐ฉ๐ช๐ซ๐ฌ๐ญ๐ฎ๐ฏ๐ฐ๐ฑ๐ฒ๐ณ{|}~", + "serifItalic": "\"\\ !#$%&'()*+,-./0123456789:;<=>?@๐ด๐ต๐ถ๐ท๐ธ๐น๐บ๐ป๐ผ๐ฝ๐พ๐ฟ๐‘€๐‘๐‘‚๐‘ƒ๐‘„๐‘…๐‘†๐‘‡๐‘ˆ๐‘‰๐‘Š๐‘‹๐‘Œ๐‘[]^_`๐‘Ž๐‘๐‘๐‘‘๐‘’๐‘“๐‘”โ„Ž๐‘–๐‘—๐‘˜๐‘™๐‘š๐‘›๐‘œ๐‘๐‘ž๐‘Ÿ๐‘ ๐‘ก๐‘ข๐‘ฃ๐‘ค๐‘ฅ๐‘ฆ๐‘ง{|}~", + "serifBoldItalic": "\"\\ !#$%&'()*+,-./0123456789:;<=>?@๐‘จ๐‘ฉ๐‘ช๐‘ซ๐‘ฌ๐‘ญ๐‘ฎ๐‘ฏ๐‘ฐ๐‘ฑ๐‘ฒ๐‘ณ๐‘ด๐‘ต๐‘ถ๐‘ท๐‘ธ๐‘น๐‘บ๐‘ป๐‘ผ๐‘ฝ๐‘พ๐‘ฟ๐’€๐’[]^_`๐’‚๐’ƒ๐’„๐’…๐’†๐’‡๐’ˆ๐’‰๐’Š๐’‹๐’Œ๐’๐’Ž๐’๐’๐’‘๐’’๐’“๐’”๐’•๐’–๐’—๐’˜๐’™๐’š๐’›{|}~", + "doubleStruck": "\"\\ !#$%&'()*+,-./๐Ÿ˜๐Ÿ™๐Ÿš๐Ÿ›๐Ÿœ๐Ÿ๐Ÿž๐ŸŸ๐Ÿ ๐Ÿก:;<=>?@๐”ธ๐”นโ„‚๐”ป๐”ผ๐”ฝ๐”พโ„๐•€๐•๐•‚๐•ƒ๐•„โ„•๐•†โ„™โ„šโ„๐•Š๐•‹๐•Œ๐•๐•Ž๐•๐•โ„ค[]^_`๐•’๐•“๐•”๐••๐•–๐•—๐•˜๐•™๐•š๐•›๐•œ๐•๐•ž๐•Ÿ๐• ๐•ก๐•ข๐•ฃ๐•ค๐•ฅ๐•ฆ๐•ง๐•จ๐•ฉ๐•ช๐•ซ{|}~", + "script": "\"\\ !#$%&'()*+,-./0123456789:;<=>?@๐’œโ„ฌ๐’ž๐’Ÿโ„ฐโ„ฑ๐’ขโ„‹โ„๐’ฅ๐’ฆโ„’โ„ณ๐’ฉ๐’ช๐’ซ๐’ฌโ„›๐’ฎ๐’ฏ๐’ฐ๐’ฑ๐’ฒ๐’ณ๐’ด๐’ต[]^_`๐’ถ๐’ท๐’ธ๐’นโ„ฏ๐’ปโ„Š๐’ฝ๐’พ๐’ฟ๐“€๐“๐“‚๐“ƒโ„ด๐“…๐“†๐“‡๐“ˆ๐“‰๐“Š๐“‹๐“Œ๐“๐“Ž๐“{|}~", + "boldScript": "\"\\ !#$%&'()*+,-./0123456789:;<=>?@๐“๐“‘๐“’๐““๐“”๐“•๐“–๐“—๐“˜๐“™๐“š๐“›๐“œ๐“๐“ž๐“Ÿ๐“ ๐“ก๐“ข๐“ฃ๐“ค๐“ฅ๐“ฆ๐“ง๐“จ๐“ฉ[]^_`๐“ช๐“ซ๐“ฌ๐“ญ๐“ฎ๐“ฏ๐“ฐ๐“ฑ๐“ฒ๐“ณ๐“ด๐“ต๐“ถ๐“ท๐“ธ๐“น๐“บ๐“ป๐“ผ๐“ฝ๐“พ๐“ฟ๐”€๐”๐”‚๐”ƒ{|}~", + "circled": "\"โฆธ !#$%&'()โŠ›โŠ•,โŠ–โจ€โŠ˜โ“ชโ‘ โ‘กโ‘ขโ‘ฃโ‘คโ‘ฅโ‘ฆโ‘งโ‘จ:;โง€โŠœโง?@โ’ถโ’ทโ’ธโ’นโ’บโ’ปโ’ผโ’ฝโ’พโ’ฟโ“€โ“โ“‚โ“ƒโ“„โ“…โ“†โ“‡โ“ˆโ“‰โ“Šโ“‹โ“Œโ“โ“Žโ“[]^_`โ“โ“‘โ“’โ““โ“”โ“•โ“–โ“—โ“˜โ“™โ“šโ“›โ“œโ“โ“žโ“Ÿโ“ โ“กโ“ขโ“ฃโ“คโ“ฅโ“ฆโ“งโ“จโ“ฉ{โฆถ}~", + "circledNegative": "\"\\ !#$%&'()*+,-./โ“ฟโถโทโธโนโบโปโผโฝโพ:;<=>?@๐Ÿ…๐Ÿ…‘๐Ÿ…’๐Ÿ…“๐Ÿ…”๐Ÿ…•๐Ÿ…–๐Ÿ…—๐Ÿ…˜๐Ÿ…™๐Ÿ…š๐Ÿ…›๐Ÿ…œ๐Ÿ…๐Ÿ…ž๐Ÿ…Ÿ๐Ÿ… ๐Ÿ…ก๐Ÿ…ข๐Ÿ…ฃ๐Ÿ…ค๐Ÿ…ฅ๐Ÿ…ฆ๐Ÿ…ง๐Ÿ…จ๐Ÿ…ฉ[]^_`๐Ÿ…๐Ÿ…‘๐Ÿ…’๐Ÿ…“๐Ÿ…”๐Ÿ…•๐Ÿ…–๐Ÿ…—๐Ÿ…˜๐Ÿ…™๐Ÿ…š๐Ÿ…›๐Ÿ…œ๐Ÿ…๐Ÿ…ž๐Ÿ…Ÿ๐Ÿ… ๐Ÿ…ก๐Ÿ…ข๐Ÿ…ฃ๐Ÿ…ค๐Ÿ…ฅ๐Ÿ…ฆ๐Ÿ…ง๐Ÿ…จ๐Ÿ…ฉ{|}~", + "squared": "\"\\ !#$%&'()*+,-./0123456789:;<=>?@๐Ÿ„ฐ๐Ÿ„ฑ๐Ÿ„ฒ๐Ÿ„ณ๐Ÿ„ด๐Ÿ„ต๐Ÿ„ถ๐Ÿ„ท๐Ÿ„ธ๐Ÿ„น๐Ÿ„บ๐Ÿ„ป๐Ÿ„ผ๐Ÿ„ฝ๐Ÿ„พ๐Ÿ„ฟ๐Ÿ…€๐Ÿ…๐Ÿ…‚๐Ÿ…ƒ๐Ÿ…„๐Ÿ……๐Ÿ…†๐Ÿ…‡๐Ÿ…ˆ๐Ÿ…‰[]^_`๐Ÿ„ฐ๐Ÿ„ฑ๐Ÿ„ฒ๐Ÿ„ณ๐Ÿ„ด๐Ÿ„ต๐Ÿ„ถ๐Ÿ„ท๐Ÿ„ธ๐Ÿ„น๐Ÿ„บ๐Ÿ„ป๐Ÿ„ผ๐Ÿ„ฝ๐Ÿ„พ๐Ÿ„ฟ๐Ÿ…€๐Ÿ…๐Ÿ…‚๐Ÿ…ƒ๐Ÿ…„๐Ÿ……๐Ÿ…†๐Ÿ…‡๐Ÿ…ˆ๐Ÿ…‰{|}~", + "squaredNegative": "\"โง… !#$%&'()โง†โŠž,โŠŸโŠกโง„0123456789:;<=>?@๐Ÿ…ฐ๐Ÿ…ฑ๐Ÿ…ฒ๐Ÿ…ณ๐Ÿ…ด๐Ÿ…ต๐Ÿ…ถ๐Ÿ…ท๐Ÿ…ธ๐Ÿ…น๐Ÿ…บ๐Ÿ…ป๐Ÿ…ผ๐Ÿ…ฝ๐Ÿ…พ๐Ÿ…ฟ๐Ÿ†€๐Ÿ†๐Ÿ†‚๐Ÿ†ƒ๐Ÿ†„๐Ÿ†…๐Ÿ††๐Ÿ†‡๐Ÿ†ˆ๐Ÿ†‰[]^_`๐Ÿ…ฐ๐Ÿ…ฑ๐Ÿ…ฒ๐Ÿ…ณ๐Ÿ…ด๐Ÿ…ต๐Ÿ…ถ๐Ÿ…ท๐Ÿ…ธ๐Ÿ…น๐Ÿ…บ๐Ÿ…ป๐Ÿ…ผ๐Ÿ…ฝ๐Ÿ…พ๐Ÿ…ฟ๐Ÿ†€๐Ÿ†๐Ÿ†‚๐Ÿ†ƒ๐Ÿ†„๐Ÿ†…๐Ÿ††๐Ÿ†‡๐Ÿ†ˆ๐Ÿ†‰{|}~", + "parenthesized": "\"\\ !#$%&'()*+,-./0โ‘ดโ‘ตโ‘ถโ‘ทโ‘ธโ‘นโ‘บโ‘ปโ‘ผ:;<=>?@โ’œโ’โ’žโ’Ÿโ’ โ’กโ’ขโ’ฃโ’คโ’ฅโ’ฆโ’งโ’จโ’ฉโ’ชโ’ซโ’ฌโ’ญโ’ฎโ’ฏโ’ฐโ’ฑโ’ฒโ’ณโ’ดโ’ต[]^_`โ’œโ’โ’žโ’Ÿโ’ โ’กโ’ขโ’ฃโ’คโ’ฅโ’ฆโ’งโ’จโ’ฉโ’ชโ’ซโ’ฌโ’ญโ’ฎโ’ฏโ’ฐโ’ฑโ’ฒโ’ณโ’ดโ’ต{|}~", + "smallCaps": "\"\\ !#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`แด€ส™แด„แด…แด‡๊œฐษขสœษชแดŠแด‹สŸแดษดแดแดฉ๊žฏส€๊œฑแด›แดœแด แดกxสแดข{|}~", + "subscript": "\"\\ !#$%&'โ‚โ‚Ž*โ‚Š,โ‚‹./โ‚€โ‚โ‚‚โ‚ƒโ‚„โ‚…โ‚†โ‚‡โ‚ˆโ‚‰:;<โ‚Œ>?@แด€ส™แด„แด…แด‡๊œฐษขสœษชแดŠแด‹สŸแดษดแดแด˜๐Ÿ‡ถส€๊œฑแด›แดœแด แดกxสแดข[]^_`โ‚แตฆ๐’ธ๐’นโ‚‘๐’ป๐“ฐโ‚•แตขโฑผโ‚–โ‚—โ‚˜โ‚™โ‚’โ‚šแตฉแตฃโ‚›โ‚œแตคแตฅ๐“Œโ‚“แตง๐“{|}~", + "superscript": "\"\\ !#$%&'โฝโพ*โบ,โป./โฐยนยฒยณโดโตโถโทโธโน:;<โผ>?@แดฌแดฎแถœแดฐแดฑแถ แดณแดดแดตแดถแดทแดธแดนแดบแดผแดพแต แดฟหขแต€แตโฑฝแต‚หฃสธแถป[]^_`แตƒแต‡แถœแตˆแต‰แถ แตสฐโฑสฒแตหกแตโฟแต’แต–แต สณหขแต—แต˜แต›สทหฃสธแถป{|}~", + "inverted": "โ€ž\\ ยก#$%โ…‹,)(*+โ€˜-ห™/0ฦ–ี‡ฦแ”ญฯ›9๐˜“86:;<=>ยฟ@โˆ€๊“ญโ†ƒ๊“ทฦŽโ„ฒโ…HIลฟ๊“˜โ…‚WNOิ€แฟธ๊“คSโŠฅโˆฉ๊“ฅMXโ…„Z][^โ€พ`ษqษ”pวษŸฦƒษฅฤฑษพสžืŸษฏuodbษนsส‡nสŒสxสŽz}|{~", + "mirrored": "\"/ !#$%&')(*+,-.\\0฿ฯ‚ฦ฿‚เคŸแƒ›ูข8เญง:;<=>โธฎ@A๊“ญโ†ƒ๊“ทฦŽ๊Ÿปำ˜HIแ‚ฑ๊“˜โ…ƒMะ˜O๊Ÿผฯ˜ะฏ๊™„TUVWXYZ][^_`ษ’dโ†„bษ˜ส‡ฯฑสœiฤฏสžlmแดŽoqpแด™๊™…ษˆฯ…vwxฮณz}|{~", + "rotatedLeft": "=/ !#$%&-โโœ*+`ว€โˆ™\\โดฐโ†ฝเดต๐ˆแ“เท„เฎฎฮ“๊แ“‚โ ’;ห…๐„ฅโˆงแฃ‡@แ—‰฿˜๐ˆฑโŒ“ัˆ๐ˆฏแ˜ŽโŒถ๐„ฉโฅŸ๐ˆŽโจผโˆ‘Zโดฐแ“‡โตšแ“šแ”•โŠขโŠƒ๐ˆทแ•’ร—โคš๐‡™โŽตโŽดโ€น|`ฦกแ“„๐ˆฑแ“€ัˆ๐ˆฏแƒ—๐ˆฆ๐„ฉแ“œ๐ˆŽโจผแ—ดโŠ‚โดฐแ“‡แ“‚แ“šแ”•๐€โŠƒ๐ˆทะ—ร—โคš๐‡™โŸ_โžเฒฝ", + "rotatedRight": "=/ !#$%&-โœโ*+`ว€โˆ™\\โดฐโ‡€แ˜šฯ‰๐ˆฆเท„ใฎโจผ๊แ“„โ ’;โˆง๐„ฅห…?@แ—†ฯ–แด’แ—œแŒ โ•–แ˜โŒถ๐„ฉแ“šโŒคโŒแ•’Zโดฐแ“€แ“„แ““แ”•โŠฃโŠ‚<แ“ฌร—โค™๐‡™โŽดโŽตโ€บ|`โŒ•แ“‚แด’เฏจแŒ โ•–เฎฎแ“๐„ฉแ“šโŒคโŒแดŸแดโดฐแ“€แ“„แ““แ”•๐€โŠ‚<แ“ฌร—โค™๐‡™โž_โŸเฒฝ" + } \ No newline at end of file diff --git a/src/tools/unicode-formatter/unicode-formatter.service.ts b/src/tools/unicode-formatter/unicode-formatter.service.ts new file mode 100644 index 00000000..ef40c355 --- /dev/null +++ b/src/tools/unicode-formatter/unicode-formatter.service.ts @@ -0,0 +1,90 @@ +// prettier-ignore +import fonts from './unicode-fonts.json'; + +export type AllFontNames = keyof typeof fonts; +export interface AllOptions { + remove?: string + append?: string + reverse?: boolean + clear?: boolean +}; + +// list of font characters for checking if character is formatted +const allCharacters = new Set(Object.values(fonts).join('')); + +// check if text is already formatted with a certain font +function alreadyFormatted(text: string, font: AllFontNames) { + const fontCharacters = new Set(fonts[font]); + // flag as already formatted if all characters are in font or not in any other font + return Array.from(text).every(char => fontCharacters.has(char) || !allCharacters.has(char)); +} + +// check if text is already formatted with a certain font +function alreadyAppended(text: string, append: string) { + // check if at least half the characters are the append character + return Array.from(text).filter(char => char === append).length >= text.length / 2; +} + +// format text into selected font +function formatText(text: string, font: AllFontNames | undefined, options?: AllOptions) { + // set font to normal if already formatted with selected font + if (font && fonts[font] && alreadyFormatted(text, font)) { + font = 'normal'; + } + // remove and don't append if character is already appended + if (options?.append) { + options.remove = options.append; + options.append = !alreadyAppended(text, options.append) ? options.append : ''; + } + // Array.from() splits the string by symbol and not by code points + let newText = Array.from(text); + // exchange font symbols + if (font && fonts[font]) { + const targetFont = Array.from(fonts[font]); + const charLists = Object.values(fonts); + // map characters to new font + newText = newText.map((char) => { + let index = -1; + // find the index of the character in some font + const found = charLists.some((charList) => { + index = Array.from(charList).indexOf(char); + return index > -1; + }); + // if found, replace with the corresponding character in the target font + // if not found, keep the character the same + return found ? targetFont[index] : char; + }); + } + // reverse text if reverse option is set + newText = options?.reverse ? newText.reverse() : newText; + // remove appended symbol of specific type from the end + newText = options?.remove + ? newText.map(char => char.replace(new RegExp(`${options.remove}$`, 'u'), '')) + : newText; + // append symbol (underline, strikethrough, etc.) to end of each character if append is set + newText = options?.append ? newText.map(char => char + options.append) : newText; + // remove appended symbols (underline, strikethrough, etc.) if using eraser + // \u035f = Underline, \u0333 = Double Underline, \u0335 = Short Strikethrough \u0336 = Strikethrough + newText = options?.clear ? newText.map(char => char.replace(/\u035F|\u0333|\u0335|\u0336/gu, '')) : newText; + // set textarea content and select text around the replacement + return newText.join(''); +} + +// format selected text +export function formatSelection(textArea: HTMLTextAreaElement, font: AllFontNames | undefined, options?: AllOptions) { + const selectionStart = textArea.selectionStart; + const selectionEnd = textArea.selectionEnd; + const oldText = textArea.value; + + const regexSpaces = /^(\s*)(\S+)(\s*)$/g; + const [_, spaceBefore, selection, spaceAfter] = regexSpaces.exec(oldText.substring(selectionStart, selectionEnd) || '') || []; + + const prefix = oldText.substring(0, selectionStart); + const newSelection = formatText(selection, font, options); + const suffix = oldText.substring(selectionEnd); + textArea.value = `${prefix}${spaceBefore}${newSelection}${spaceAfter}${suffix}`; + + textArea.setSelectionRange(selectionStart, selectionStart + (spaceBefore?.length || 0) + newSelection.length + (spaceAfter?.length || 0)); + + textArea.focus(); +} diff --git a/src/tools/unicode-formatter/unicode-formatter.vue b/src/tools/unicode-formatter/unicode-formatter.vue new file mode 100644 index 00000000..26ef20f0 --- /dev/null +++ b/src/tools/unicode-formatter/unicode-formatter.vue @@ -0,0 +1,179 @@ + + +