Compare commits

...

6 Commits

Author SHA1 Message Date
sharevb
69d8932f88
Merge 2a088ba7d7 into e876d03608 2024-05-13 16:23:43 +02:00
Corentin Thomasset
e876d03608
chore(version): release 2024.05.13-a0bc346 2024-05-13 10:54:18 +02:00
Corentin Thomasset
81cf6b5483
docs(changelog): update changelog for 2024.05.13-a0bc346 2024-05-13 10:54:18 +02:00
Corentin THOMASSET
a0bc3468b2
chore(issues): prevent empty issues (#1078) 2024-05-13 08:44:04 +00:00
Corentin THOMASSET
5a7b0f9636
chore(issues): removed old issue templates (#1077) 2024-05-13 08:11:47 +00:00
sharevb
2a088ba7d7 feat(new tool): Unicode Formatter
Unicode formatter using https://github.com/DenverCoder1/unicode-formatter
Fix #951
2024-04-28 11:59:34 +02:00
13 changed files with 368 additions and 56 deletions

1
.github/ISSUE_TEMPLATE/config.yml vendored Normal file
View File

@ -0,0 +1 @@
blank_issues_enabled: false

View File

@ -1,5 +1,5 @@
name: 🚀 New feature proposal
description: Propose a new feature to be added to IT-Tools.
description: Propose a new feature/enhancement or tool idea for IT-Tools
labels: ['enhancement', 'triage']
body:

View File

@ -1,19 +0,0 @@
---
name: New tool request
about: Suggest a new tool idea
title: '[NEW TOOL]'
labels: new tool
assignees: CorentinTh
---
**What tool do you want?**
Example: a token generator
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Is their example of this tool in the wild?**
Provide link to already existing tool or npm packages if any exists
**Additional context**
Add any other context about the feature request here.

View File

@ -1,13 +0,0 @@
---
name: Other request
about: Any request that does not concern a tool creation, a new feature request on a tool or a bug
title: '[OTHER] '
labels:
assignees: CorentinTh
---
**Describe the solution you'd like**
A clear and concise description of what you want.
**Additional context**
Add any other context about the feature request here.

View File

@ -1,13 +0,0 @@
---
name: Tool improvement
about: Improvement on an existing tool
title: '[TOOL IMPROVEMENT]'
labels: enhancement
assignees: CorentinTh
---
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Additional context**
Add any other context about the feature request here.

View File

@ -2,7 +2,7 @@
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
## Version 2024.05.10-33e5294
## Version 2024.05.13-a0bc346
### Features
- **i18n**: added German translation (#1038) (2c2fb21)
@ -33,12 +33,20 @@ All notable changes to this project will be documented in this file. See [standa
- **i18n**: added locales per tool (#861) (95698cb)
### Chores
- **issues**: prevent empty issues (#1078) (a0bc346)
- **issues**: removed old issue templates (#1077) (5a7b0f9)
- **node**: upgraded node version in CI workflows (b59942a)
- **version**: release 2024.05.10-33e5294 (38d5687)
- **issues**: improved issues template (2852c30)
- **issues**: improved bug issue template (#1046) (a799234)
### Documentation
- **changelog**: update changelog for 2024.05.10-33e5294 (9dfd347)
## Version 2023.12.21-5ed3693
### Features
- **i18n**: improve chinese i18n (#757) (2e56641)
- **i18n**: add tooltip and favoriteButton i18n (#756) (a1037cf)
- **i18n**: add Chinese translation base (#718) (8f99eb6)
@ -46,6 +54,7 @@ All notable changes to this project will be documented in this file. See [standa
- **new tool**: numeronym generator (#729) (e07e2ae)
### Bug fixes
- **jwt-parser**: jwt claim array support (#799) (5ed3693)
- **camera-recorder**: stop camera on navigation (#782) (80e46c9)
- **doc**: updated create new tool command in readme (#762) (7a70dbb)
@ -54,6 +63,7 @@ All notable changes to this project will be documented in this file. See [standa
- **eta**: corrected example (#737) (821cbea)
### Refactoring
- **about, i18n**: improved i18n dx with markdown (#753) (bd3edcb)
- **token, i18n**: complete fr translation (#752) (de1ee69)
- **uuid generator**: uuid version picker (#751) (38586ca)
@ -63,6 +73,7 @@ All notable changes to this project will be documented in this file. See [standa
- **bcrypt**: fix input label align (#721) (093ff31)
### Chores
- **deps**: switched from oui to oui-data for mac address lookup (#693) (0fe9a20)
- **deps**: update unocss monorepo to ^0.57.0 (#638) (2e396d8)
- **docker**: added armv7 plateform for docker releases (#722) (fe1de8c)
@ -70,19 +81,23 @@ All notable changes to this project will be documented in this file. See [standa
## Version 2023.11.02-7d94e11
### Features
- **i18n**: language selector (#710) (e86fd96)
### Bug fixes
- **dockerfile**: revert replacement of nginx image with non-privileged one (#716) (7d94e11)
- **encryption**: alert on decryption error (#711) (02b0d0d)
### Refactoring
- **math-evaluator**: improved description (e87f4b1)
- **math-evaluator**: improved search and UX (#713) (58de897)
## Version 2023.11.01-e164afb
### Features
- **command-palette**: clear prompt on palette close (#708) (d013696)
- **command-palette**: added about page in command palette (99b1eb9)
- **new tool**: random MAC address generator (#657) (cc3425d)
@ -101,11 +116,13 @@ All notable changes to this project will be documented in this file. See [standa
- **new tool**: text diff and comparator (#588) (81bfe57)
### Bug fixes
- **deps**: fix issue on slugify (#593) (#673) (720201a)
- **deps**: update dependency monaco-editor to ^0.43.0 (#620) (e371ef7)
- **deps**: update dependency sql-formatter to v13 (#606) (c7d4562)
### Refactoring
- **ui**: better ui demo preview menu (#664) (015c673)
- **color-converter**: improved color-converter UX (#701) (abb8335)
- **docker**: improved docker config (#700) (020e9cb)
@ -122,6 +139,7 @@ All notable changes to this project will be documented in this file. See [standa
- **bcrypt**: fix typo (#604) (e18bae1)
### Chores
- **deps**: clean unused dependencies (#709) (e164afb)
- **deps**: update docker/setup-qemu-action action to v3 (#627) (4365226)
- **deps**: update docker/setup-buildx-action action to v3 (#626) (57ecda1)
@ -136,19 +154,23 @@ All notable changes to this project will be documented in this file. See [standa
- **deps**: update dependency typescript to ~5.2.0 (#587) (f3e14fc)
### Doc
- **readme**: added contributors list (#622) (557b304)
- **hosting**: added cloudron in the other hosting solutions section (#589) (06c3547)
## Version 2023.08.21-6f93cba
### Features
- **copy**: support legacy copy to clipboard for older browser (#581) (6f93cba)
- **new tool**: string obfuscator (#575) (c58d6e3)
### Bug fixes
- **deps**: update dependency sql-formatter to v12 (#520) (2bcb77a)
### Chores
- **deps**: switched to fucking typescript v5 (#501) (76b2761)
- **deps**: update dependency @antfu/eslint-config to ^0.40.0 (#552) (6ff9a01)
- **deps**: update dependency prettier to v3 (#564) (a2b9b15)
@ -158,6 +180,7 @@ All notable changes to this project will be documented in this file. See [standa
## Version 2023.08.16-9bd4ad4
### Features
- **Case Converter**: Add lowercase and uppercase (#534) (7b6232a)
- **new tool**: emoji picker (#551) (93f7cf0)
- **ui**: added c-select in the ui lib (#550) (dfa1ba8)
@ -178,6 +201,7 @@ All notable changes to this project will be documented in this file. See [standa
- **base64-string-converter**: switch to encode and decode url safe base64 strings (#392) (0b20f1c)
### Bug fixes
- **deps**: update dependency uuid to v9 (#566) (5e12991)
- **deps**: update dependency mathjs to v11 (#519) (7924456)
- **deps**: update dependency @vueuse/router to v10 (#516) (ea0f27c)
@ -197,6 +221,7 @@ All notable changes to this project will be documented in this file. See [standa
- **ipv4-converter**: removed readonly on input (7aed9c5)
### Refactoring
- **navbar**: consistent spacing in navbar buttons (#507) (30f88fc)
- **ui**: remove n-text (#506) (72c98a3)
- **ui**: replaced some n-input to c-input (#505) (05ea545)
@ -209,6 +234,7 @@ All notable changes to this project will be documented in this file. See [standa
- **ui**: replaced some n-input with c-input-text (f7fc779)
### Chores
- **deps**: update dependency vitest to ^0.34.0 (#562) (9bd4ad4)
- **deps**: update dependency node to v18.17.1 (#560) (65a9474)
- **deps**: update dependency unocss to ^0.55.0 (#561) (85cc7a8)
@ -249,47 +275,58 @@ All notable changes to this project will be documented in this file. See [standa
- **lint**: switched to a better lint config (33c9b66)
### Refacor
- **transformers**: use monospace font for JSON and SQL text areas (#476) (ba4876d)
### Documentation
- **ide**: updated vscode extensions settings (#472) (847323c)
### Chors
- **deps**: updated vueuse dependency version (8515c24)
## Version 2023.05.14-77f2efc
### Features
- **list-converter**: a small converter who deals with column based data and do some stuff with it (#387) (83a7b3b)
- **new tool**: phone parser and normalizer (ce3150c)
### Bug fixes
- **phone-parser**: use default country code (a43c546)
- **home**: prevent weird blue border on card (3f6c8f0)
### Refactoring
- **ui**: replaced some n-input with c-input-text (77f2efc)
### Chores
- **issues**: updated new tool request issue template (edae4c6)
### Ui-lib
- **new-component**: added text input component in the c-lib (aad8d84)
- **button**: size variants (401f13f)
## Version 2023.04.23-92bd835
### Features
- **ui-lib**: demo pages for c-lib components (92bd835)
- **new-tool**: diff of two json objects (362f2fa)
- **ipv4-range-expander**: expands a given IPv4 start and end address to a valid IPv4 subnet (#366) (df989e2)
- **date converter**: auto focus main input (6d22025)
### Bug fixes
- **ts**: cleaned legacy typechecking warning (e88c1d5)
- **mac-address-lookup**: added copy handler on button click (c311e38)
### Refactoring
- **ui-lib**: prevent c-button to shrink (61ece23)
- **ui**: replaced naive ui cards with custom ones (f080933)
- **clean**: removed unused lodash import (bb32513)
@ -299,48 +336,60 @@ All notable changes to this project will be documented in this file. See [standa
## Version 2023.04.14-dbad773
### Features
- **new-tool**: http status codes (8355bd2)
### Refactoring
- **uuid-generator**: prevent NaN in quantity (6fb4994)
### Chores
- **release**: create a github release on new version (dbad773)
- **version**: reset CHANGELOG content to support new format (85cb0ff)
## Version 2023.04.14-f9b77b7
### Features
- **new-tool**: http status codes (8355bd2)
### Refactoring
- **uuid-generator**: prevent NaN in quantity (6fb4994)
### Chores
- **release**: create a github release on new version (f9b77b7)
- **version**: reset CHANGELOG content to support new format (85cb0ff)
## Version 2023.04.14-2f0d239
### Features
- **new-tool**: http status codes (8355bd2)
### Refactoring
- **uuid-generator**: prevent NaN in quantity (6fb4994)
### Chores
- **release**: create a github release on new version (2f0d239)
- **version**: reset CHANGELOG content to support new format (85cb0ff)
## Version 2023.04.14-474cae4
### Features
- **new-tool**: http status codes (8355bd2)
### Refactoring
- **uuid-generator**: prevent NaN in quantity (6fb4994)
### Chores
- **release**: create a github release on new version (474cae4)
- **version**: reset CHANGELOG content to support new format (85cb0ff)

11
components.d.ts vendored
View File

@ -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']
@ -179,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']

View File

@ -1,6 +1,6 @@
{
"name": "it-tools",
"version": "2024.5.10-33e5294",
"version": "2024.5.13-a0bc346",
"description": "Collection of handy online tools for developers, with great UX. ",
"keywords": [
"productivity",

View File

@ -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,
],
},
{

View File

@ -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'),
});

View File

@ -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ⴰᓀᓄᓓᔕ⊣⊂<ᓬ×⤙𝇙⎴⎵›|`⌕ᓂᴒ௨ጠ╖மፓ𝄩ᓚ⌤⌐ᴟᴝⴰᓀᓄᓓᔕ𝀏⊂<ᓬ×⤙𝇙⏞_⏟ಽ"
}

View File

@ -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();
}

View File

@ -0,0 +1,179 @@
<script lang="ts" setup>
// import {AllFontNames,AllOptions, bold,italic,monospace,strikethrough,underline,superscript,subscript,formatSelections} from './unicod'
import { Copy } from '@vicons/tabler';
import type { AllFontNames, AllOptions } from './unicode-formatter.service';
import { formatSelection } from './unicode-formatter.service';
import { useCopy } from '@/composable/copy';
const textArea = ref<HTMLTextAreaElement>();
function formatTextAreaSelection(format: AllFontNames | undefined, options: AllOptions) {
if (!textArea.value) {
return;
}
formatSelection(textArea.value, format, options);
}
const formattedText = ref('Type your text here and 𝗳𝗼𝗿𝗺𝗮𝘁 it by highlighting the text you want to format and clicking one of the buttons above. Click "More fonts" to show more Unicode fonts. The eraser button will convert your selection back to normal text.');
const { copy: copyFormattedText } = useCopy({ source: formattedText, text: 'Formatted text copied to the clipboard' });
</script>
<template>
<!-- Google Fonts -->
<link rel="preconnect" href="https://fonts.gstatic.com">
<link href="https://fonts.googleapis.com/css2?family=Open+Sans&display=swap" rel="stylesheet">
<div
max-w-600
style="font-family: 'Open Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;"
>
<!-- First set of buttons -->
<n-form-item label="Fonts:" mb-3 mt-3 w-full>
<n-button title="Normal" @click="formatTextAreaSelection('normal', { clear: true })">
<!-- Eraser Icon -->
<svg stroke="currentColor" fill="currentColor" stroke-width="0" viewBox="0 0 24 24" height="1em" width="1em" xmlns="http://www.w3.org/2000/svg">
<path d="M2.586,15.408l4.299,4.299C7.072,19.895,7.326,20,7.592,20h0.001h2h0.4h9.6v-2h-6.958l7.222-7.222 c0.78-0.779,0.78-2.049,0-2.828L14.906,3c-0.779-0.779-2.049-0.779-2.828,0l-4.75,4.749l-4.754,4.843 C1.809,13.371,1.813,14.634,2.586,15.408z M13.492,4.414l4.95,4.95l-2.586,2.586L10.906,7L13.492,4.414z M8.749,9.156l0.743-0.742 l4.95,4.95l-4.557,4.557C9.86,17.946,9.838,17.973,9.816,18H9.593H8.006l-4.005-4.007L8.749,9.156z" />
</svg>
</n-button>
<n-button title="Bold" @click="formatTextAreaSelection('sansBold', { })">
𝗕
</n-button>
<n-button title="Italic" @click="formatTextAreaSelection('sansItalic', { })">
𝘐
</n-button>
<n-button title="Monospace" @click="formatTextAreaSelection('monospace', { })">
𝙼
</n-button>
<n-button style="text-decoration: underline" @click="formatTextAreaSelection(undefined, { append: '͟' })">
U
</n-button>
<n-button style="text-decoration: line-through" @click="formatTextAreaSelection(undefined, { append: '̶' })">
S
</n-button>
</n-form-item>
<!-- Collapsible section with more buttons -->
<details style="display:block" borders mb-3 w-full>
<summary>More fonts</summary>
<n-space mt-3 w-full>
<n-button title="Math Sans" @click="formatTextAreaSelection('sans', { })">
𝖬
</n-button>
<n-button title="Sans Bold italic" @click="formatTextAreaSelection('sansBoldItalic', { })">
𝘽𝙄
</n-button>
<n-button title="Serif bold" @click="formatTextAreaSelection('serifBold', { })">
𝐁
</n-button>
<n-button title="Serif italic" @click="formatTextAreaSelection('serifItalic', { })">
𝐼
</n-button>
<n-button title="Serif bold italic" @click="formatTextAreaSelection('serifBoldItalic', { })">
𝑩𝑰
</n-button>
<n-button title="Double Underline" @click="formatTextAreaSelection(undefined, { append: '̳' })">
U̳
</n-button>
<n-button title="Short Strikethrough" style="text-decoration: line-through" @click="formatTextAreaSelection(undefined, { append: '̵' })">
S̵
</n-button>
<n-button title="Math double-struck" @click="formatTextAreaSelection('doubleStruck', { })">
𝔻
</n-button>
<n-button title="Fullwidth" @click="formatTextAreaSelection('fullwidth', { })">
</n-button>
<n-button title="Math Fraktur" @click="formatTextAreaSelection('fraktur', { })">
𝔉
</n-button>
<n-button title="Math Fraktur bold" @click="formatTextAreaSelection('boldFraktur', { })">
𝕱
</n-button>
<n-button title="Script" @click="formatTextAreaSelection('script', { })">
𝒮
</n-button>
<n-button title="Bold script" @click="formatTextAreaSelection('boldScript', { })">
𝓢
</n-button>
<n-button title="Circled" @click="formatTextAreaSelection('circled', { })">
</n-button>
<n-button title="Circled negative" @click="formatTextAreaSelection('circledNegative', { })">
🅒
</n-button>
<n-button title="Squared" @click="formatTextAreaSelection('squared', { })">
🅂
</n-button>
<n-button title="Squared negative" @click="formatTextAreaSelection('squaredNegative', { })">
🆂
</n-button>
<n-button title="Parenthesized" @click="formatTextAreaSelection('parenthesized', { })">
</n-button>
<n-button title="Small caps" @click="formatTextAreaSelection('smallCaps', { })">
</n-button>
<n-button title="Subscript" @click="formatTextAreaSelection('subscript', { })">
ₛᵤᵦ
</n-button>
<n-button title="Superscript" @click="formatTextAreaSelection('superscript', { })">
ˢᵘᵖ
</n-button>
<n-button title="Inverted" @click="formatTextAreaSelection('inverted', { })">
</n-button>
<n-button title="Rotated Left" @click="formatTextAreaSelection('rotatedLeft', { })">
</n-button>
<n-button title="Rotated Right" @click="formatTextAreaSelection('rotatedRight', { })">
</n-button>
<n-button title="Mirrored" @click="formatTextAreaSelection('mirrored', { })">
Я
</n-button>
<n-button title="Reverse" @click="formatTextAreaSelection(undefined, { reverse: true })">
<!-- Left/Right Arrow Icon -->
<svg stroke="currentColor" fill="currentColor" stroke-width="0" viewBox="0 0 512 512" height="1em" width="1em" xmlns="http://www.w3.org/2000/svg">
<path d="M0 168v-16c0-13.255 10.745-24 24-24h360V80c0-21.367 25.899-32.042 40.971-16.971l80 80c9.372 9.373 9.372 24.569 0 33.941l-80 80C409.956 271.982 384 261.456 384 240v-48H24c-13.255 0-24-10.745-24-24zm488 152H128v-48c0-21.314-25.862-32.08-40.971-16.971l-80 80c-9.372 9.373-9.372 24.569 0 33.941l80 80C102.057 463.997 128 453.437 128 432v-48h360c13.255 0 24-10.745 24-24v-16c0-13.255-10.745-24-24-24z" />
</svg>
</n-button>
<n-button title="Inverted Reverse" @click="formatTextAreaSelection('inverted', { reverse: true })">
<!-- Left/Right Arrow Icon -->
<svg stroke="currentColor" fill="currentColor" stroke-width="0" viewBox="0 0 512 512" height="1em" width="1em" xmlns="http://www.w3.org/2000/svg">
<path d="M377.941 169.941V216H134.059v-46.059c0-21.382-25.851-32.09-40.971-16.971L7.029 239.029c-9.373 9.373-9.373 24.568 0 33.941l86.059 86.059c15.119 15.119 40.971 4.411 40.971-16.971V296h243.882v46.059c0 21.382 25.851 32.09 40.971 16.971l86.059-86.059c9.373-9.373 9.373-24.568 0-33.941l-86.059-86.059c-15.119-15.12-40.971-4.412-40.971 16.97z" />
</svg>
</n-button>
<n-button title="Rotated Right Reverse" @click="formatTextAreaSelection('rotatedRight', { reverse: true })">
<!-- Left/Right Arrow Icon -->
<svg stroke="currentColor" fill="currentColor" stroke-width="0" viewBox="0 0 512 512" height="1em" width="1em" xmlns="http://www.w3.org/2000/svg">
<path d="M377.941 169.941V216H134.059v-46.059c0-21.382-25.851-32.09-40.971-16.971L7.029 239.029c-9.373 9.373-9.373 24.568 0 33.941l86.059 86.059c15.119 15.119 40.971 4.411 40.971-16.971V296h243.882v46.059c0 21.382 25.851 32.09 40.971 16.971l86.059-86.059c9.373-9.373 9.373-24.568 0-33.941l-86.059-86.059c-15.119-15.12-40.971-4.412-40.971 16.97z" />
</svg>
</n-button>
<n-button title="Mirrored Reverse" @click="formatTextAreaSelection('mirrored', { reverse: true })">
Я
<!-- Left/Right Arrow Icon -->
<svg stroke="currentColor" fill="currentColor" stroke-width="0" viewBox="0 0 512 512" height="1em" width="1em" xmlns="http://www.w3.org/2000/svg">
<path d="M377.941 169.941V216H134.059v-46.059c0-21.382-25.851-32.09-40.971-16.971L7.029 239.029c-9.373 9.373-9.373 24.568 0 33.941l86.059 86.059c15.119 15.119 40.971 4.411 40.971-16.971V296h243.882v46.059c0 21.382 25.851 32.09 40.971 16.971l86.059-86.059c9.373-9.373 9.373-24.568 0-33.941l-86.059-86.059c-15.119-15.12-40.971-4.412-40.971 16.97z" />
</svg>
</n-button>
</n-space>
</details>
<textarea
ref="textArea" :value="formattedText" rows="12" mb-3 mt-3 w-full
spellcheck="false"
style="font-family: 'Open Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;"
/>
<div text-center>
<c-button @click="copyFormattedText()">
<n-icon size="22">
<Copy />
</n-icon>
</c-button>
</div>
</div>
</template>