From 3f6c8f0eddc51798d62c9011e5179f6cc497e88e Mon Sep 17 00:00:00 2001 From: Corentin Thomasset Date: Mon, 1 May 2023 13:44:30 +0200 Subject: [PATCH 001/246] fix(home): prevent weird blue border on card --- src/components/ToolCard.vue | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/ToolCard.vue b/src/components/ToolCard.vue index c0f85819..64dc113e 100644 --- a/src/components/ToolCard.vue +++ b/src/components/ToolCard.vue @@ -55,6 +55,7 @@ a { .tool-card { transition: border-color ease 0.5s; border-width: 2px !important; + color: transparent; &:hover { border-color: v-bind('appTheme.primary.colorHover'); From ce3150c65d14273539362f24afd43ee689cdb287 Mon Sep 17 00:00:00 2001 From: Corentin Thomasset Date: Mon, 1 May 2023 16:43:45 +0200 Subject: [PATCH 002/246] feat(new tool): phone parser and normalizer --- components.d.ts | 277 +++++++++--------- package.json | 2 + pnpm-lock.yaml | 14 + src/tools/index.ts | 5 + src/tools/phone-parser-and-formatter/index.ts | 25 ++ .../phone-parser-and-formatter.e2e.spec.ts | 11 + .../phone-parser-and-formatter.models.ts | 41 +++ .../phone-parser-and-formatter.vue | 107 +++++++ src/utils/boolean.test.ts | 9 +- src/utils/boolean.ts | 6 +- 10 files changed, 357 insertions(+), 140 deletions(-) create mode 100644 src/tools/phone-parser-and-formatter/index.ts create mode 100644 src/tools/phone-parser-and-formatter/phone-parser-and-formatter.e2e.spec.ts create mode 100644 src/tools/phone-parser-and-formatter/phone-parser-and-formatter.models.ts create mode 100644 src/tools/phone-parser-and-formatter/phone-parser-and-formatter.vue diff --git a/components.d.ts b/components.d.ts index 2750ce66..84e879c9 100644 --- a/components.d.ts +++ b/components.d.ts @@ -5,146 +5,147 @@ // Read more: https://github.com/vuejs/core/pull/3399 import '@vue/runtime-core' -export {} +export {}; declare module '@vue/runtime-core' { export interface GlobalComponents { - '404.page': typeof import('./src/pages/404.page.vue')['default'] - About: typeof import('./src/pages/About.vue')['default'] - App: typeof import('./src/App.vue')['default'] - 'Base.layout': typeof import('./src/layouts/base.layout.vue')['default'] - Base64FileConverter: typeof import('./src/tools/base64-file-converter/base64-file-converter.vue')['default'] - Base64StringConverter: typeof import('./src/tools/base64-string-converter/base64-string-converter.vue')['default'] - BasicAuthGenerator: typeof import('./src/tools/basic-auth-generator/basic-auth-generator.vue')['default'] - Bcrypt: typeof import('./src/tools/bcrypt/bcrypt.vue')['default'] - BenchmarkBuilder: typeof import('./src/tools/benchmark-builder/benchmark-builder.vue')['default'] - Bip39Generator: typeof import('./src/tools/bip39-generator/bip39-generator.vue')['default'] - CaseConverter: typeof import('./src/tools/case-converter/case-converter.vue')['default'] - CButton: typeof import('./src/ui/c-button/c-button.vue')['default'] - 'CButton.demo': typeof import('./src/ui/c-button/c-button.demo.vue')['default'] - CCard: typeof import('./src/ui/c-card/c-card.vue')['default'] - 'CCard.demo': typeof import('./src/ui/c-card/c-card.demo.vue')['default'] - ChmodCalculator: typeof import('./src/tools/chmod-calculator/chmod-calculator.vue')['default'] - Chronometer: typeof import('./src/tools/chronometer/chronometer.vue')['default'] - CLink: typeof import('./src/ui/c-link/c-link.vue')['default'] - 'CLink.demo': typeof import('./src/ui/c-link/c-link.demo.vue')['default'] - CollapsibleToolMenu: typeof import('./src/components/CollapsibleToolMenu.vue')['default'] - ColorConverter: typeof import('./src/tools/color-converter/color-converter.vue')['default'] - ColoredCard: typeof import('./src/components/ColoredCard.vue')['default'] - CopyableIpLike: typeof import('./src/tools/ipv4-subnet-calculator/copyable-ip-like.vue')['default'] - CrontabGenerator: typeof import('./src/tools/crontab-generator/crontab-generator.vue')['default'] - DateTimeConverter: typeof import('./src/tools/date-time-converter/date-time-converter.vue')['default'] - 'Demo.routes': typeof import('./src/ui/demo/demo.routes.vue')['default'] - DemoWrapper: typeof import('./src/ui/demo/demo-wrapper.vue')['default'] - DeviceInformation: typeof import('./src/tools/device-information/device-information.vue')['default'] - DiffViewer: typeof import('./src/tools/json-diff/diff-viewer/diff-viewer.vue')['default'] - DockerRunToDockerComposeConverter: typeof import('./src/tools/docker-run-to-docker-compose-converter/docker-run-to-docker-compose-converter.vue')['default'] - DynamicValues: typeof import('./src/tools/benchmark-builder/dynamic-values.vue')['default'] - Editor: typeof import('./src/tools/html-wysiwyg-editor/editor/editor.vue')['default'] - Encryption: typeof import('./src/tools/encryption/encryption.vue')['default'] - EtaCalculator: typeof import('./src/tools/eta-calculator/eta-calculator.vue')['default'] - FavoriteButton: typeof import('./src/components/FavoriteButton.vue')['default'] - FormatTransformer: typeof import('./src/components/FormatTransformer.vue')['default'] - GitMemo: typeof import('./src/tools/git-memo/git-memo.md')['default'] - HashText: typeof import('./src/tools/hash-text/hash-text.vue')['default'] - HmacGenerator: typeof import('./src/tools/hmac-generator/hmac-generator.vue')['default'] - 'Home.page': typeof import('./src/pages/Home.page.vue')['default'] - HtmlEntities: typeof import('./src/tools/html-entities/html-entities.vue')['default'] - HtmlWysiwygEditor: typeof import('./src/tools/html-wysiwyg-editor/html-wysiwyg-editor.vue')['default'] - HttpStatusCodes: typeof import('./src/tools/http-status-codes/http-status-codes.vue')['default'] - InputCopyable: typeof import('./src/components/InputCopyable.vue')['default'] - IntegerBaseConverter: typeof import('./src/tools/integer-base-converter/integer-base-converter.vue')['default'] - Ipv4AddressConverter: typeof import('./src/tools/ipv4-address-converter/ipv4-address-converter.vue')['default'] - 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'] - JsonDiff: typeof import('./src/tools/json-diff/json-diff.vue')['default'] - JsonMinify: typeof import('./src/tools/json-minify/json-minify.vue')['default'] - JsonToYaml: typeof import('./src/tools/json-to-yaml-converter/json-to-yaml.vue')['default'] - JsonViewer: typeof import('./src/tools/json-viewer/json-viewer.vue')['default'] - JwtParser: typeof import('./src/tools/jwt-parser/jwt-parser.vue')['default'] - KeycodeInfo: typeof import('./src/tools/keycode-info/keycode-info.vue')['default'] - LoremIpsumGenerator: typeof import('./src/tools/lorem-ipsum-generator/lorem-ipsum-generator.vue')['default'] - MacAddressLookup: typeof import('./src/tools/mac-address-lookup/mac-address-lookup.vue')['default'] - MathEvaluator: typeof import('./src/tools/math-evaluator/math-evaluator.vue')['default'] - MenuBar: typeof import('./src/tools/html-wysiwyg-editor/editor/menu-bar.vue')['default'] - MenuBarItem: typeof import('./src/tools/html-wysiwyg-editor/editor/menu-bar-item.vue')['default'] - MenuIconItem: typeof import('./src/components/MenuIconItem.vue')['default'] - 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'] - NAlert: typeof import('naive-ui')['NAlert'] - NAutoComplete: typeof import('naive-ui')['NAutoComplete'] - NavbarButtons: typeof import('./src/components/NavbarButtons.vue')['default'] - NButton: typeof import('naive-ui')['NButton'] - NCard: typeof import('naive-ui')['NCard'] - NCheckbox: typeof import('naive-ui')['NCheckbox'] - NCode: typeof import('naive-ui')['NCode'] - NCollapseTransition: typeof import('naive-ui')['NCollapseTransition'] - NColorPicker: typeof import('naive-ui')['NColorPicker'] - NConfigProvider: typeof import('naive-ui')['NConfigProvider'] - NDatePicker: typeof import('naive-ui')['NDatePicker'] - NDivider: typeof import('naive-ui')['NDivider'] - NDynamicInput: typeof import('naive-ui')['NDynamicInput'] - NEllipsis: typeof import('naive-ui')['NEllipsis'] - NForm: typeof import('naive-ui')['NForm'] - NFormItem: typeof import('naive-ui')['NFormItem'] - NGi: typeof import('naive-ui')['NGi'] - NGrid: typeof import('naive-ui')['NGrid'] - NH1: typeof import('naive-ui')['NH1'] - NH2: typeof import('naive-ui')['NH2'] - NH3: typeof import('naive-ui')['NH3'] - NIcon: typeof import('naive-ui')['NIcon'] - NImage: typeof import('naive-ui')['NImage'] - NInput: typeof import('naive-ui')['NInput'] - NInputGroup: typeof import('naive-ui')['NInputGroup'] - NInputGroupLabel: typeof import('naive-ui')['NInputGroupLabel'] - NInputNumber: typeof import('naive-ui')['NInputNumber'] - NLayout: typeof import('naive-ui')['NLayout'] - NLayoutSider: typeof import('naive-ui')['NLayoutSider'] - NMenu: typeof import('naive-ui')['NMenu'] - NP: typeof import('naive-ui')['NP'] - NPageHeader: typeof import('naive-ui')['NPageHeader'] - NProgress: typeof import('naive-ui')['NProgress'] - NScrollbar: typeof import('naive-ui')['NScrollbar'] - NSelect: typeof import('naive-ui')['NSelect'] - NSlider: typeof import('naive-ui')['NSlider'] - NSpace: typeof import('naive-ui')['NSpace'] - NStatistic: typeof import('naive-ui')['NStatistic'] - NSwitch: typeof import('naive-ui')['NSwitch'] - NTable: typeof import('naive-ui')['NTable'] - NTag: typeof import('naive-ui')['NTag'] - NText: typeof import('naive-ui')['NText'] - NTooltip: typeof import('naive-ui')['NTooltip'] - NUpload: typeof import('naive-ui')['NUpload'] - NUploadDragger: typeof import('naive-ui')['NUploadDragger'] - OtpCodeGeneratorAndValidator: typeof import('./src/tools/otp-code-generator-and-validator/otp-code-generator-and-validator.vue')['default'] - QrCodeGenerator: typeof import('./src/tools/qr-code-generator/qr-code-generator.vue')['default'] - RandomPortGenerator: typeof import('./src/tools/random-port-generator/random-port-generator.vue')['default'] - ResultRow: typeof import('./src/tools/ipv4-range-expander/result-row.vue')['default'] - RomanNumeralConverter: typeof import('./src/tools/roman-numeral-converter/roman-numeral-converter.vue')['default'] - 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'] - SearchBar: typeof import('./src/components/SearchBar.vue')['default'] - SearchBarItem: typeof import('./src/components/SearchBarItem.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'] - SvgPlaceholderGenerator: typeof import('./src/tools/svg-placeholder-generator/svg-placeholder-generator.vue')['default'] - TemperatureConverter: typeof import('./src/tools/temperature-converter/temperature-converter.vue')['default'] - TextareaCopyable: typeof import('./src/components/TextareaCopyable.vue')['default'] - TextStatistics: typeof import('./src/tools/text-statistics/text-statistics.vue')['default'] - TextToNatoAlphabet: typeof import('./src/tools/text-to-nato-alphabet/text-to-nato-alphabet.vue')['default'] - TokenDisplay: typeof import('./src/tools/otp-code-generator-and-validator/token-display.vue')['default'] - 'TokenGenerator.tool': typeof import('./src/tools/token-generator/token-generator.tool.vue')['default'] - 'Tool.layout': typeof import('./src/layouts/tool.layout.vue')['default'] - ToolCard: typeof import('./src/components/ToolCard.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'] - UserAgentResultCards: typeof import('./src/tools/user-agent-parser/user-agent-result-cards.vue')['default'] - UuidGenerator: typeof import('./src/tools/uuid-generator/uuid-generator.vue')['default'] - YamlToJson: typeof import('./src/tools/yaml-to-json-converter/yaml-to-json.vue')['default'] + '404.page': typeof import('./src/pages/404.page.vue')['default']; + About: typeof import('./src/pages/About.vue')['default']; + App: typeof import('./src/App.vue')['default']; + 'Base.layout': typeof import('./src/layouts/base.layout.vue')['default']; + Base64FileConverter: typeof import('./src/tools/base64-file-converter/base64-file-converter.vue')['default']; + Base64StringConverter: typeof import('./src/tools/base64-string-converter/base64-string-converter.vue')['default']; + BasicAuthGenerator: typeof import('./src/tools/basic-auth-generator/basic-auth-generator.vue')['default']; + Bcrypt: typeof import('./src/tools/bcrypt/bcrypt.vue')['default']; + BenchmarkBuilder: typeof import('./src/tools/benchmark-builder/benchmark-builder.vue')['default']; + Bip39Generator: typeof import('./src/tools/bip39-generator/bip39-generator.vue')['default']; + CaseConverter: typeof import('./src/tools/case-converter/case-converter.vue')['default']; + CButton: typeof import('./src/ui/c-button/c-button.vue')['default']; + 'CButton.demo': typeof import('./src/ui/c-button/c-button.demo.vue')['default']; + CCard: typeof import('./src/ui/c-card/c-card.vue')['default']; + 'CCard.demo': typeof import('./src/ui/c-card/c-card.demo.vue')['default']; + ChmodCalculator: typeof import('./src/tools/chmod-calculator/chmod-calculator.vue')['default']; + Chronometer: typeof import('./src/tools/chronometer/chronometer.vue')['default']; + CLink: typeof import('./src/ui/c-link/c-link.vue')['default']; + 'CLink.demo': typeof import('./src/ui/c-link/c-link.demo.vue')['default']; + CollapsibleToolMenu: typeof import('./src/components/CollapsibleToolMenu.vue')['default']; + ColorConverter: typeof import('./src/tools/color-converter/color-converter.vue')['default']; + ColoredCard: typeof import('./src/components/ColoredCard.vue')['default']; + CopyableIpLike: typeof import('./src/tools/ipv4-subnet-calculator/copyable-ip-like.vue')['default']; + CrontabGenerator: typeof import('./src/tools/crontab-generator/crontab-generator.vue')['default']; + DateTimeConverter: typeof import('./src/tools/date-time-converter/date-time-converter.vue')['default']; + 'Demo.routes': typeof import('./src/ui/demo/demo.routes.vue')['default']; + DemoWrapper: typeof import('./src/ui/demo/demo-wrapper.vue')['default']; + DeviceInformation: typeof import('./src/tools/device-information/device-information.vue')['default']; + DiffViewer: typeof import('./src/tools/json-diff/diff-viewer/diff-viewer.vue')['default']; + DockerRunToDockerComposeConverter: typeof import('./src/tools/docker-run-to-docker-compose-converter/docker-run-to-docker-compose-converter.vue')['default']; + DynamicValues: typeof import('./src/tools/benchmark-builder/dynamic-values.vue')['default']; + Editor: typeof import('./src/tools/html-wysiwyg-editor/editor/editor.vue')['default']; + Encryption: typeof import('./src/tools/encryption/encryption.vue')['default']; + EtaCalculator: typeof import('./src/tools/eta-calculator/eta-calculator.vue')['default']; + FavoriteButton: typeof import('./src/components/FavoriteButton.vue')['default']; + FormatTransformer: typeof import('./src/components/FormatTransformer.vue')['default']; + GitMemo: typeof import('./src/tools/git-memo/git-memo.md')['default']; + HashText: typeof import('./src/tools/hash-text/hash-text.vue')['default']; + HmacGenerator: typeof import('./src/tools/hmac-generator/hmac-generator.vue')['default']; + 'Home.page': typeof import('./src/pages/Home.page.vue')['default']; + HtmlEntities: typeof import('./src/tools/html-entities/html-entities.vue')['default']; + HtmlWysiwygEditor: typeof import('./src/tools/html-wysiwyg-editor/html-wysiwyg-editor.vue')['default']; + HttpStatusCodes: typeof import('./src/tools/http-status-codes/http-status-codes.vue')['default']; + InputCopyable: typeof import('./src/components/InputCopyable.vue')['default']; + IntegerBaseConverter: typeof import('./src/tools/integer-base-converter/integer-base-converter.vue')['default']; + Ipv4AddressConverter: typeof import('./src/tools/ipv4-address-converter/ipv4-address-converter.vue')['default']; + 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']; + JsonDiff: typeof import('./src/tools/json-diff/json-diff.vue')['default']; + JsonMinify: typeof import('./src/tools/json-minify/json-minify.vue')['default']; + JsonToYaml: typeof import('./src/tools/json-to-yaml-converter/json-to-yaml.vue')['default']; + JsonViewer: typeof import('./src/tools/json-viewer/json-viewer.vue')['default']; + JwtParser: typeof import('./src/tools/jwt-parser/jwt-parser.vue')['default']; + KeycodeInfo: typeof import('./src/tools/keycode-info/keycode-info.vue')['default']; + LoremIpsumGenerator: typeof import('./src/tools/lorem-ipsum-generator/lorem-ipsum-generator.vue')['default']; + MacAddressLookup: typeof import('./src/tools/mac-address-lookup/mac-address-lookup.vue')['default']; + MathEvaluator: typeof import('./src/tools/math-evaluator/math-evaluator.vue')['default']; + MenuBar: typeof import('./src/tools/html-wysiwyg-editor/editor/menu-bar.vue')['default']; + MenuBarItem: typeof import('./src/tools/html-wysiwyg-editor/editor/menu-bar-item.vue')['default']; + MenuIconItem: typeof import('./src/components/MenuIconItem.vue')['default']; + 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']; + NAlert: typeof import('naive-ui')['NAlert']; + NAutoComplete: typeof import('naive-ui')['NAutoComplete']; + NavbarButtons: typeof import('./src/components/NavbarButtons.vue')['default']; + NButton: typeof import('naive-ui')['NButton']; + NCard: typeof import('naive-ui')['NCard']; + NCheckbox: typeof import('naive-ui')['NCheckbox']; + NCode: typeof import('naive-ui')['NCode']; + NCollapseTransition: typeof import('naive-ui')['NCollapseTransition']; + NColorPicker: typeof import('naive-ui')['NColorPicker']; + NConfigProvider: typeof import('naive-ui')['NConfigProvider']; + NDatePicker: typeof import('naive-ui')['NDatePicker']; + NDivider: typeof import('naive-ui')['NDivider']; + NDynamicInput: typeof import('naive-ui')['NDynamicInput']; + NEllipsis: typeof import('naive-ui')['NEllipsis']; + NForm: typeof import('naive-ui')['NForm']; + NFormItem: typeof import('naive-ui')['NFormItem']; + NGi: typeof import('naive-ui')['NGi']; + NGrid: typeof import('naive-ui')['NGrid']; + NH1: typeof import('naive-ui')['NH1']; + NH2: typeof import('naive-ui')['NH2']; + NH3: typeof import('naive-ui')['NH3']; + NIcon: typeof import('naive-ui')['NIcon']; + NImage: typeof import('naive-ui')['NImage']; + NInput: typeof import('naive-ui')['NInput']; + NInputGroup: typeof import('naive-ui')['NInputGroup']; + NInputGroupLabel: typeof import('naive-ui')['NInputGroupLabel']; + NInputNumber: typeof import('naive-ui')['NInputNumber']; + NLayout: typeof import('naive-ui')['NLayout']; + NLayoutSider: typeof import('naive-ui')['NLayoutSider']; + NMenu: typeof import('naive-ui')['NMenu']; + NP: typeof import('naive-ui')['NP']; + NPageHeader: typeof import('naive-ui')['NPageHeader']; + NProgress: typeof import('naive-ui')['NProgress']; + NScrollbar: typeof import('naive-ui')['NScrollbar']; + NSelect: typeof import('naive-ui')['NSelect']; + NSlider: typeof import('naive-ui')['NSlider']; + NSpace: typeof import('naive-ui')['NSpace']; + NStatistic: typeof import('naive-ui')['NStatistic']; + NSwitch: typeof import('naive-ui')['NSwitch']; + NTable: typeof import('naive-ui')['NTable']; + NTag: typeof import('naive-ui')['NTag']; + NText: typeof import('naive-ui')['NText']; + NTooltip: typeof import('naive-ui')['NTooltip']; + NUpload: typeof import('naive-ui')['NUpload']; + NUploadDragger: typeof import('naive-ui')['NUploadDragger']; + OtpCodeGeneratorAndValidator: typeof import('./src/tools/otp-code-generator-and-validator/otp-code-generator-and-validator.vue')['default']; + PhoneParserAndFormatter: typeof import('./src/tools/phone-parser-and-formatter/phone-parser-and-formatter.vue')['default']; + QrCodeGenerator: typeof import('./src/tools/qr-code-generator/qr-code-generator.vue')['default']; + RandomPortGenerator: typeof import('./src/tools/random-port-generator/random-port-generator.vue')['default']; + ResultRow: typeof import('./src/tools/ipv4-range-expander/result-row.vue')['default']; + RomanNumeralConverter: typeof import('./src/tools/roman-numeral-converter/roman-numeral-converter.vue')['default']; + 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']; + SearchBar: typeof import('./src/components/SearchBar.vue')['default']; + SearchBarItem: typeof import('./src/components/SearchBarItem.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']; + SvgPlaceholderGenerator: typeof import('./src/tools/svg-placeholder-generator/svg-placeholder-generator.vue')['default']; + TemperatureConverter: typeof import('./src/tools/temperature-converter/temperature-converter.vue')['default']; + TextareaCopyable: typeof import('./src/components/TextareaCopyable.vue')['default']; + TextStatistics: typeof import('./src/tools/text-statistics/text-statistics.vue')['default']; + TextToNatoAlphabet: typeof import('./src/tools/text-to-nato-alphabet/text-to-nato-alphabet.vue')['default']; + TokenDisplay: typeof import('./src/tools/otp-code-generator-and-validator/token-display.vue')['default']; + 'TokenGenerator.tool': typeof import('./src/tools/token-generator/token-generator.tool.vue')['default']; + 'Tool.layout': typeof import('./src/layouts/tool.layout.vue')['default']; + ToolCard: typeof import('./src/components/ToolCard.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']; + UserAgentResultCards: typeof import('./src/tools/user-agent-parser/user-agent-result-cards.vue')['default']; + UuidGenerator: typeof import('./src/tools/uuid-generator/uuid-generator.vue')['default']; + YamlToJson: typeof import('./src/tools/yaml-to-json-converter/yaml-to-json.vue')['default']; } } diff --git a/package.json b/package.json index bed82dcf..6f5856b0 100644 --- a/package.json +++ b/package.json @@ -48,6 +48,7 @@ "change-case": "^4.1.2", "colord": "^2.9.3", "composerize-ts": "^0.6.2", + "country-code-lookup": "^0.0.23", "cron-validator": "^1.3.1", "cronstrue": "^2.26.0", "crypto-js": "^4.1.1", @@ -57,6 +58,7 @@ "highlight.js": "^11.7.0", "json5": "^2.2.3", "jwt-decode": "^3.1.2", + "libphonenumber-js": "^1.10.28", "lodash": "^4.17.21", "mathjs": "^10.6.4", "mime-types": "^2.1.35", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 1e1b8715..e5813b71 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -46,6 +46,9 @@ dependencies: composerize-ts: specifier: ^0.6.2 version: 0.6.2 + country-code-lookup: + specifier: ^0.0.23 + version: 0.0.23 cron-validator: specifier: ^1.3.1 version: 1.3.1 @@ -73,6 +76,9 @@ dependencies: jwt-decode: specifier: ^3.1.2 version: 3.1.2 + libphonenumber-js: + specifier: ^1.10.28 + version: 1.10.28 lodash: specifier: ^4.17.21 version: 4.17.21 @@ -3604,6 +3610,10 @@ packages: browserslist: 4.21.5 dev: true + /country-code-lookup@0.0.23: + resolution: {integrity: sha512-kxhIGcau9/X+tgPg9yO2q1OLu8jiYYsdwXuiXzHdsgNChd36xrJMlOba7ka9O1xShCVTiVQPQpq/tcuy4WiW+Q==} + dev: false + /country-data@0.0.31: resolution: {integrity: sha512-YqlY/i6ikZwoBFfdjK+hJTGaBdTgDpXLI15MCj2UsXZ2cPBb+Kx86AXmDH7PRGt0LUleck0cCgNdWeIhfbcxkQ==} dependencies: @@ -5665,6 +5675,10 @@ packages: type-check: 0.4.0 dev: true + /libphonenumber-js@1.10.28: + resolution: {integrity: sha512-1eAgjLrZA0+2Wgw4hs+4Q/kEBycxQo8ZLYnmOvZ3AlM8ImAVAJgDPlZtISLEzD1vunc2q8s2Pn7XwB7I8U3Kzw==} + dev: false + /linkify-it@3.0.3: resolution: {integrity: sha512-ynTsyrFSdE5oZ/O9GEf00kPngmOfVwazR5GKDq6EYfhlpFug3J2zybX56a2PRRpc9P+FuSoGNAwjlbDs9jJBPQ==} dependencies: diff --git a/src/tools/index.ts b/src/tools/index.ts index 73f08348..bc54b4d2 100644 --- a/src/tools/index.ts +++ b/src/tools/index.ts @@ -1,6 +1,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 phoneParserAndFormatter } from './phone-parser-and-formatter'; import { tool as jsonDiff } from './json-diff'; import { tool as ipv4RangeExpander } from './ipv4-range-expander'; import { tool as httpStatusCodes } from './http-status-codes'; @@ -128,6 +129,10 @@ export const toolsByCategory: ToolCategory[] = [ name: 'Text', components: [loremIpsumGenerator, textStatistics], }, + { + name: 'Data', + components: [phoneParserAndFormatter], + }, ]; export const tools = toolsByCategory.flatMap(({ components }) => components); diff --git a/src/tools/phone-parser-and-formatter/index.ts b/src/tools/phone-parser-and-formatter/index.ts new file mode 100644 index 00000000..5b19ae61 --- /dev/null +++ b/src/tools/phone-parser-and-formatter/index.ts @@ -0,0 +1,25 @@ +import { Phone } from '@vicons/tabler'; +import { defineTool } from '../tool'; + +export const tool = defineTool({ + name: 'Phone parser and formatter', + path: '/phone-parser-and-formatter', + description: + 'Parse, validate and format phone numbers. Get information about the phone number, like the country code, type, etc.', + keywords: [ + 'phone', + 'parser', + 'formatter', + 'validate', + 'format', + 'number', + 'telephone', + 'mobile', + 'cell', + 'international', + 'national', + ], + component: () => import('./phone-parser-and-formatter.vue'), + icon: Phone, + createdAt: new Date('2023-05-01'), +}); diff --git a/src/tools/phone-parser-and-formatter/phone-parser-and-formatter.e2e.spec.ts b/src/tools/phone-parser-and-formatter/phone-parser-and-formatter.e2e.spec.ts new file mode 100644 index 00000000..ddf55102 --- /dev/null +++ b/src/tools/phone-parser-and-formatter/phone-parser-and-formatter.e2e.spec.ts @@ -0,0 +1,11 @@ +import { test, expect } from '@playwright/test'; + +test.describe('Tool - Phone parser and formatter', () => { + test.beforeEach(async ({ page }) => { + await page.goto('/phone-parser-and-formatter'); + }); + + test('Has correct title', async ({ page }) => { + await expect(page).toHaveTitle('Phone parser and formatter - IT Tools'); + }); +}); diff --git a/src/tools/phone-parser-and-formatter/phone-parser-and-formatter.models.ts b/src/tools/phone-parser-and-formatter/phone-parser-and-formatter.models.ts new file mode 100644 index 00000000..1e2a483d --- /dev/null +++ b/src/tools/phone-parser-and-formatter/phone-parser-and-formatter.models.ts @@ -0,0 +1,41 @@ +import type { NumberType } from 'libphonenumber-js/types'; +import lookup from 'country-code-lookup'; + +export { formatTypeToHumanReadable, getFullCountryName, getDefaultCountryCode }; + +const typeToLabel: Record, string> = { + MOBILE: 'Mobile', + FIXED_LINE: 'Fixed line', + FIXED_LINE_OR_MOBILE: 'Fixed line or mobile', + PERSONAL_NUMBER: 'Personal number', + PREMIUM_RATE: 'Premium rate', + SHARED_COST: 'Shared cost', + TOLL_FREE: 'Toll free', + UAN: 'Universal access number', + VOICEMAIL: 'Voicemail', + VOIP: 'VoIP', + PAGER: 'Pager', +}; + +function formatTypeToHumanReadable(type: NumberType): string | undefined { + if (!type) return undefined; + + return typeToLabel[type]; +} + +function getFullCountryName(countryCode: string | undefined) { + if (!countryCode) return undefined; + + return lookup.byIso(countryCode)?.country; +} + +function getDefaultCountryCode({ + locale = window.navigator.language, + defaultCode = 'FR', +}: { locale?: string; defaultCode?: string } = {}): string { + const countryCode = locale.split('-')[1]?.toUpperCase(); + + if (!countryCode) return defaultCode; + + return lookup.byIso(countryCode)?.iso2 ?? defaultCode; +} diff --git a/src/tools/phone-parser-and-formatter/phone-parser-and-formatter.vue b/src/tools/phone-parser-and-formatter/phone-parser-and-formatter.vue new file mode 100644 index 00000000..d17356a9 --- /dev/null +++ b/src/tools/phone-parser-and-formatter/phone-parser-and-formatter.vue @@ -0,0 +1,107 @@ + + + + + diff --git a/src/utils/boolean.test.ts b/src/utils/boolean.test.ts index 57ca10a4..52bda9e2 100644 --- a/src/utils/boolean.test.ts +++ b/src/utils/boolean.test.ts @@ -1,6 +1,6 @@ import _ from 'lodash'; import { describe, expect, it } from 'vitest'; -import { isNotThrowing } from './boolean'; +import { booleanToHumanReadable, isNotThrowing } from './boolean'; describe('boolean utils', () => { describe('isNotThrowing', () => { @@ -13,4 +13,11 @@ describe('boolean utils', () => { ).to.eql(false); }); }); + + describe('booleanToHumanReadable', () => { + it('should return "Yes" if the value is true and "No" otherwise', () => { + expect(booleanToHumanReadable(true)).to.eql('Yes'); + expect(booleanToHumanReadable(false)).to.eql('No'); + }); + }); }); diff --git a/src/utils/boolean.ts b/src/utils/boolean.ts index 9e842ea8..cf10b377 100644 --- a/src/utils/boolean.ts +++ b/src/utils/boolean.ts @@ -1,4 +1,4 @@ -export { isNotThrowing }; +export { isNotThrowing, booleanToHumanReadable }; function isNotThrowing(cb: () => unknown): boolean { try { @@ -8,3 +8,7 @@ function isNotThrowing(cb: () => unknown): boolean { return false; } } + +function booleanToHumanReadable(value: boolean): string { + return value ? 'Yes' : 'No'; +} From 83a7b3bae98f7509171f00912076b9dabcb83d49 Mon Sep 17 00:00:00 2001 From: cgoIT Date: Sun, 7 May 2023 11:29:22 +0200 Subject: [PATCH 003/246] feat(list-converter): a small converter who deals with column based data and do some stuff with it (#387) * feat(list-converter): a small converter who deals with column based data and do some stuff with it * Update src/tools/list-converter/index.ts * Update src/tools/list-converter/index.ts * Update src/tools/list-converter/index.ts --------- Co-authored-by: Corentin THOMASSET fix(list-format): fix e2e --- components.d.ts | 280 +++++++++--------- src/tools/index.ts | 2 + src/tools/list-converter/index.ts | 13 + .../list-converter/list-converter.e2e.spec.ts | 39 +++ .../list-converter.models.test.ts | 76 +++++ .../list-converter/list-converter.models.ts | 27 ++ .../list-converter/list-converter.types.ts | 15 + src/tools/list-converter/list-converter.vue | 121 ++++++++ src/utils/array.ts | 7 + 9 files changed, 441 insertions(+), 139 deletions(-) create mode 100644 src/tools/list-converter/index.ts create mode 100644 src/tools/list-converter/list-converter.e2e.spec.ts create mode 100644 src/tools/list-converter/list-converter.models.test.ts create mode 100644 src/tools/list-converter/list-converter.models.ts create mode 100644 src/tools/list-converter/list-converter.types.ts create mode 100644 src/tools/list-converter/list-converter.vue create mode 100644 src/utils/array.ts diff --git a/components.d.ts b/components.d.ts index 84e879c9..78c2650c 100644 --- a/components.d.ts +++ b/components.d.ts @@ -5,147 +5,149 @@ // Read more: https://github.com/vuejs/core/pull/3399 import '@vue/runtime-core' -export {}; +export {} declare module '@vue/runtime-core' { export interface GlobalComponents { - '404.page': typeof import('./src/pages/404.page.vue')['default']; - About: typeof import('./src/pages/About.vue')['default']; - App: typeof import('./src/App.vue')['default']; - 'Base.layout': typeof import('./src/layouts/base.layout.vue')['default']; - Base64FileConverter: typeof import('./src/tools/base64-file-converter/base64-file-converter.vue')['default']; - Base64StringConverter: typeof import('./src/tools/base64-string-converter/base64-string-converter.vue')['default']; - BasicAuthGenerator: typeof import('./src/tools/basic-auth-generator/basic-auth-generator.vue')['default']; - Bcrypt: typeof import('./src/tools/bcrypt/bcrypt.vue')['default']; - BenchmarkBuilder: typeof import('./src/tools/benchmark-builder/benchmark-builder.vue')['default']; - Bip39Generator: typeof import('./src/tools/bip39-generator/bip39-generator.vue')['default']; - CaseConverter: typeof import('./src/tools/case-converter/case-converter.vue')['default']; - CButton: typeof import('./src/ui/c-button/c-button.vue')['default']; - 'CButton.demo': typeof import('./src/ui/c-button/c-button.demo.vue')['default']; - CCard: typeof import('./src/ui/c-card/c-card.vue')['default']; - 'CCard.demo': typeof import('./src/ui/c-card/c-card.demo.vue')['default']; - ChmodCalculator: typeof import('./src/tools/chmod-calculator/chmod-calculator.vue')['default']; - Chronometer: typeof import('./src/tools/chronometer/chronometer.vue')['default']; - CLink: typeof import('./src/ui/c-link/c-link.vue')['default']; - 'CLink.demo': typeof import('./src/ui/c-link/c-link.demo.vue')['default']; - CollapsibleToolMenu: typeof import('./src/components/CollapsibleToolMenu.vue')['default']; - ColorConverter: typeof import('./src/tools/color-converter/color-converter.vue')['default']; - ColoredCard: typeof import('./src/components/ColoredCard.vue')['default']; - CopyableIpLike: typeof import('./src/tools/ipv4-subnet-calculator/copyable-ip-like.vue')['default']; - CrontabGenerator: typeof import('./src/tools/crontab-generator/crontab-generator.vue')['default']; - DateTimeConverter: typeof import('./src/tools/date-time-converter/date-time-converter.vue')['default']; - 'Demo.routes': typeof import('./src/ui/demo/demo.routes.vue')['default']; - DemoWrapper: typeof import('./src/ui/demo/demo-wrapper.vue')['default']; - DeviceInformation: typeof import('./src/tools/device-information/device-information.vue')['default']; - DiffViewer: typeof import('./src/tools/json-diff/diff-viewer/diff-viewer.vue')['default']; - DockerRunToDockerComposeConverter: typeof import('./src/tools/docker-run-to-docker-compose-converter/docker-run-to-docker-compose-converter.vue')['default']; - DynamicValues: typeof import('./src/tools/benchmark-builder/dynamic-values.vue')['default']; - Editor: typeof import('./src/tools/html-wysiwyg-editor/editor/editor.vue')['default']; - Encryption: typeof import('./src/tools/encryption/encryption.vue')['default']; - EtaCalculator: typeof import('./src/tools/eta-calculator/eta-calculator.vue')['default']; - FavoriteButton: typeof import('./src/components/FavoriteButton.vue')['default']; - FormatTransformer: typeof import('./src/components/FormatTransformer.vue')['default']; - GitMemo: typeof import('./src/tools/git-memo/git-memo.md')['default']; - HashText: typeof import('./src/tools/hash-text/hash-text.vue')['default']; - HmacGenerator: typeof import('./src/tools/hmac-generator/hmac-generator.vue')['default']; - 'Home.page': typeof import('./src/pages/Home.page.vue')['default']; - HtmlEntities: typeof import('./src/tools/html-entities/html-entities.vue')['default']; - HtmlWysiwygEditor: typeof import('./src/tools/html-wysiwyg-editor/html-wysiwyg-editor.vue')['default']; - HttpStatusCodes: typeof import('./src/tools/http-status-codes/http-status-codes.vue')['default']; - InputCopyable: typeof import('./src/components/InputCopyable.vue')['default']; - IntegerBaseConverter: typeof import('./src/tools/integer-base-converter/integer-base-converter.vue')['default']; - Ipv4AddressConverter: typeof import('./src/tools/ipv4-address-converter/ipv4-address-converter.vue')['default']; - 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']; - JsonDiff: typeof import('./src/tools/json-diff/json-diff.vue')['default']; - JsonMinify: typeof import('./src/tools/json-minify/json-minify.vue')['default']; - JsonToYaml: typeof import('./src/tools/json-to-yaml-converter/json-to-yaml.vue')['default']; - JsonViewer: typeof import('./src/tools/json-viewer/json-viewer.vue')['default']; - JwtParser: typeof import('./src/tools/jwt-parser/jwt-parser.vue')['default']; - KeycodeInfo: typeof import('./src/tools/keycode-info/keycode-info.vue')['default']; - LoremIpsumGenerator: typeof import('./src/tools/lorem-ipsum-generator/lorem-ipsum-generator.vue')['default']; - MacAddressLookup: typeof import('./src/tools/mac-address-lookup/mac-address-lookup.vue')['default']; - MathEvaluator: typeof import('./src/tools/math-evaluator/math-evaluator.vue')['default']; - MenuBar: typeof import('./src/tools/html-wysiwyg-editor/editor/menu-bar.vue')['default']; - MenuBarItem: typeof import('./src/tools/html-wysiwyg-editor/editor/menu-bar-item.vue')['default']; - MenuIconItem: typeof import('./src/components/MenuIconItem.vue')['default']; - 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']; - NAlert: typeof import('naive-ui')['NAlert']; - NAutoComplete: typeof import('naive-ui')['NAutoComplete']; - NavbarButtons: typeof import('./src/components/NavbarButtons.vue')['default']; - NButton: typeof import('naive-ui')['NButton']; - NCard: typeof import('naive-ui')['NCard']; - NCheckbox: typeof import('naive-ui')['NCheckbox']; - NCode: typeof import('naive-ui')['NCode']; - NCollapseTransition: typeof import('naive-ui')['NCollapseTransition']; - NColorPicker: typeof import('naive-ui')['NColorPicker']; - NConfigProvider: typeof import('naive-ui')['NConfigProvider']; - NDatePicker: typeof import('naive-ui')['NDatePicker']; - NDivider: typeof import('naive-ui')['NDivider']; - NDynamicInput: typeof import('naive-ui')['NDynamicInput']; - NEllipsis: typeof import('naive-ui')['NEllipsis']; - NForm: typeof import('naive-ui')['NForm']; - NFormItem: typeof import('naive-ui')['NFormItem']; - NGi: typeof import('naive-ui')['NGi']; - NGrid: typeof import('naive-ui')['NGrid']; - NH1: typeof import('naive-ui')['NH1']; - NH2: typeof import('naive-ui')['NH2']; - NH3: typeof import('naive-ui')['NH3']; - NIcon: typeof import('naive-ui')['NIcon']; - NImage: typeof import('naive-ui')['NImage']; - NInput: typeof import('naive-ui')['NInput']; - NInputGroup: typeof import('naive-ui')['NInputGroup']; - NInputGroupLabel: typeof import('naive-ui')['NInputGroupLabel']; - NInputNumber: typeof import('naive-ui')['NInputNumber']; - NLayout: typeof import('naive-ui')['NLayout']; - NLayoutSider: typeof import('naive-ui')['NLayoutSider']; - NMenu: typeof import('naive-ui')['NMenu']; - NP: typeof import('naive-ui')['NP']; - NPageHeader: typeof import('naive-ui')['NPageHeader']; - NProgress: typeof import('naive-ui')['NProgress']; - NScrollbar: typeof import('naive-ui')['NScrollbar']; - NSelect: typeof import('naive-ui')['NSelect']; - NSlider: typeof import('naive-ui')['NSlider']; - NSpace: typeof import('naive-ui')['NSpace']; - NStatistic: typeof import('naive-ui')['NStatistic']; - NSwitch: typeof import('naive-ui')['NSwitch']; - NTable: typeof import('naive-ui')['NTable']; - NTag: typeof import('naive-ui')['NTag']; - NText: typeof import('naive-ui')['NText']; - NTooltip: typeof import('naive-ui')['NTooltip']; - NUpload: typeof import('naive-ui')['NUpload']; - NUploadDragger: typeof import('naive-ui')['NUploadDragger']; - OtpCodeGeneratorAndValidator: typeof import('./src/tools/otp-code-generator-and-validator/otp-code-generator-and-validator.vue')['default']; - PhoneParserAndFormatter: typeof import('./src/tools/phone-parser-and-formatter/phone-parser-and-formatter.vue')['default']; - QrCodeGenerator: typeof import('./src/tools/qr-code-generator/qr-code-generator.vue')['default']; - RandomPortGenerator: typeof import('./src/tools/random-port-generator/random-port-generator.vue')['default']; - ResultRow: typeof import('./src/tools/ipv4-range-expander/result-row.vue')['default']; - RomanNumeralConverter: typeof import('./src/tools/roman-numeral-converter/roman-numeral-converter.vue')['default']; - 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']; - SearchBar: typeof import('./src/components/SearchBar.vue')['default']; - SearchBarItem: typeof import('./src/components/SearchBarItem.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']; - SvgPlaceholderGenerator: typeof import('./src/tools/svg-placeholder-generator/svg-placeholder-generator.vue')['default']; - TemperatureConverter: typeof import('./src/tools/temperature-converter/temperature-converter.vue')['default']; - TextareaCopyable: typeof import('./src/components/TextareaCopyable.vue')['default']; - TextStatistics: typeof import('./src/tools/text-statistics/text-statistics.vue')['default']; - TextToNatoAlphabet: typeof import('./src/tools/text-to-nato-alphabet/text-to-nato-alphabet.vue')['default']; - TokenDisplay: typeof import('./src/tools/otp-code-generator-and-validator/token-display.vue')['default']; - 'TokenGenerator.tool': typeof import('./src/tools/token-generator/token-generator.tool.vue')['default']; - 'Tool.layout': typeof import('./src/layouts/tool.layout.vue')['default']; - ToolCard: typeof import('./src/components/ToolCard.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']; - UserAgentResultCards: typeof import('./src/tools/user-agent-parser/user-agent-result-cards.vue')['default']; - UuidGenerator: typeof import('./src/tools/uuid-generator/uuid-generator.vue')['default']; - YamlToJson: typeof import('./src/tools/yaml-to-json-converter/yaml-to-json.vue')['default']; + '404.page': typeof import('./src/pages/404.page.vue')['default'] + About: typeof import('./src/pages/About.vue')['default'] + App: typeof import('./src/App.vue')['default'] + 'Base.layout': typeof import('./src/layouts/base.layout.vue')['default'] + Base64FileConverter: typeof import('./src/tools/base64-file-converter/base64-file-converter.vue')['default'] + Base64StringConverter: typeof import('./src/tools/base64-string-converter/base64-string-converter.vue')['default'] + BasicAuthGenerator: typeof import('./src/tools/basic-auth-generator/basic-auth-generator.vue')['default'] + Bcrypt: typeof import('./src/tools/bcrypt/bcrypt.vue')['default'] + BenchmarkBuilder: typeof import('./src/tools/benchmark-builder/benchmark-builder.vue')['default'] + Bip39Generator: typeof import('./src/tools/bip39-generator/bip39-generator.vue')['default'] + CaseConverter: typeof import('./src/tools/case-converter/case-converter.vue')['default'] + CButton: typeof import('./src/ui/c-button/c-button.vue')['default'] + 'CButton.demo': typeof import('./src/ui/c-button/c-button.demo.vue')['default'] + CCard: typeof import('./src/ui/c-card/c-card.vue')['default'] + 'CCard.demo': typeof import('./src/ui/c-card/c-card.demo.vue')['default'] + ChmodCalculator: typeof import('./src/tools/chmod-calculator/chmod-calculator.vue')['default'] + Chronometer: typeof import('./src/tools/chronometer/chronometer.vue')['default'] + CLink: typeof import('./src/ui/c-link/c-link.vue')['default'] + 'CLink.demo': typeof import('./src/ui/c-link/c-link.demo.vue')['default'] + CollapsibleToolMenu: typeof import('./src/components/CollapsibleToolMenu.vue')['default'] + ColorConverter: typeof import('./src/tools/color-converter/color-converter.vue')['default'] + ColoredCard: typeof import('./src/components/ColoredCard.vue')['default'] + CopyableIpLike: typeof import('./src/tools/ipv4-subnet-calculator/copyable-ip-like.vue')['default'] + CrontabGenerator: typeof import('./src/tools/crontab-generator/crontab-generator.vue')['default'] + DateTimeConverter: typeof import('./src/tools/date-time-converter/date-time-converter.vue')['default'] + 'Demo.routes': typeof import('./src/ui/demo/demo.routes.vue')['default'] + DemoWrapper: typeof import('./src/ui/demo/demo-wrapper.vue')['default'] + DeviceInformation: typeof import('./src/tools/device-information/device-information.vue')['default'] + DiffViewer: typeof import('./src/tools/json-diff/diff-viewer/diff-viewer.vue')['default'] + DockerRunToDockerComposeConverter: typeof import('./src/tools/docker-run-to-docker-compose-converter/docker-run-to-docker-compose-converter.vue')['default'] + DynamicValues: typeof import('./src/tools/benchmark-builder/dynamic-values.vue')['default'] + Editor: typeof import('./src/tools/html-wysiwyg-editor/editor/editor.vue')['default'] + Encryption: typeof import('./src/tools/encryption/encryption.vue')['default'] + EtaCalculator: typeof import('./src/tools/eta-calculator/eta-calculator.vue')['default'] + FavoriteButton: typeof import('./src/components/FavoriteButton.vue')['default'] + FormatTransformer: typeof import('./src/components/FormatTransformer.vue')['default'] + GitMemo: typeof import('./src/tools/git-memo/git-memo.md')['default'] + HashText: typeof import('./src/tools/hash-text/hash-text.vue')['default'] + HmacGenerator: typeof import('./src/tools/hmac-generator/hmac-generator.vue')['default'] + 'Home.page': typeof import('./src/pages/Home.page.vue')['default'] + HtmlEntities: typeof import('./src/tools/html-entities/html-entities.vue')['default'] + HtmlWysiwygEditor: typeof import('./src/tools/html-wysiwyg-editor/html-wysiwyg-editor.vue')['default'] + HttpStatusCodes: typeof import('./src/tools/http-status-codes/http-status-codes.vue')['default'] + InputCopyable: typeof import('./src/components/InputCopyable.vue')['default'] + IntegerBaseConverter: typeof import('./src/tools/integer-base-converter/integer-base-converter.vue')['default'] + Ipv4AddressConverter: typeof import('./src/tools/ipv4-address-converter/ipv4-address-converter.vue')['default'] + 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'] + JsonDiff: typeof import('./src/tools/json-diff/json-diff.vue')['default'] + JsonMinify: typeof import('./src/tools/json-minify/json-minify.vue')['default'] + JsonToYaml: typeof import('./src/tools/json-to-yaml-converter/json-to-yaml.vue')['default'] + JsonViewer: typeof import('./src/tools/json-viewer/json-viewer.vue')['default'] + JwtParser: typeof import('./src/tools/jwt-parser/jwt-parser.vue')['default'] + KeycodeInfo: typeof import('./src/tools/keycode-info/keycode-info.vue')['default'] + ListConverter: typeof import('./src/tools/list-converter/list-converter.vue')['default'] + LoremIpsumGenerator: typeof import('./src/tools/lorem-ipsum-generator/lorem-ipsum-generator.vue')['default'] + MacAddressLookup: typeof import('./src/tools/mac-address-lookup/mac-address-lookup.vue')['default'] + MathEvaluator: typeof import('./src/tools/math-evaluator/math-evaluator.vue')['default'] + MenuBar: typeof import('./src/tools/html-wysiwyg-editor/editor/menu-bar.vue')['default'] + MenuBarItem: typeof import('./src/tools/html-wysiwyg-editor/editor/menu-bar-item.vue')['default'] + MenuIconItem: typeof import('./src/components/MenuIconItem.vue')['default'] + 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'] + NAlert: typeof import('naive-ui')['NAlert'] + NAutoComplete: typeof import('naive-ui')['NAutoComplete'] + NavbarButtons: typeof import('./src/components/NavbarButtons.vue')['default'] + NButton: typeof import('naive-ui')['NButton'] + NCard: typeof import('naive-ui')['NCard'] + NCheckbox: typeof import('naive-ui')['NCheckbox'] + NCode: typeof import('naive-ui')['NCode'] + NCollapseTransition: typeof import('naive-ui')['NCollapseTransition'] + NColorPicker: typeof import('naive-ui')['NColorPicker'] + NConfigProvider: typeof import('naive-ui')['NConfigProvider'] + NDatePicker: typeof import('naive-ui')['NDatePicker'] + NDivider: typeof import('naive-ui')['NDivider'] + NDynamicInput: typeof import('naive-ui')['NDynamicInput'] + NEllipsis: typeof import('naive-ui')['NEllipsis'] + NForm: typeof import('naive-ui')['NForm'] + NFormItem: typeof import('naive-ui')['NFormItem'] + NFormItemGi: typeof import('naive-ui')['NFormItemGi'] + NGi: typeof import('naive-ui')['NGi'] + NGrid: typeof import('naive-ui')['NGrid'] + NH1: typeof import('naive-ui')['NH1'] + NH2: typeof import('naive-ui')['NH2'] + NH3: typeof import('naive-ui')['NH3'] + NIcon: typeof import('naive-ui')['NIcon'] + NImage: typeof import('naive-ui')['NImage'] + NInput: typeof import('naive-ui')['NInput'] + NInputGroup: typeof import('naive-ui')['NInputGroup'] + NInputGroupLabel: typeof import('naive-ui')['NInputGroupLabel'] + NInputNumber: typeof import('naive-ui')['NInputNumber'] + NLayout: typeof import('naive-ui')['NLayout'] + NLayoutSider: typeof import('naive-ui')['NLayoutSider'] + NMenu: typeof import('naive-ui')['NMenu'] + NP: typeof import('naive-ui')['NP'] + NPageHeader: typeof import('naive-ui')['NPageHeader'] + NProgress: typeof import('naive-ui')['NProgress'] + NScrollbar: typeof import('naive-ui')['NScrollbar'] + NSelect: typeof import('naive-ui')['NSelect'] + NSlider: typeof import('naive-ui')['NSlider'] + NSpace: typeof import('naive-ui')['NSpace'] + NStatistic: typeof import('naive-ui')['NStatistic'] + NSwitch: typeof import('naive-ui')['NSwitch'] + NTable: typeof import('naive-ui')['NTable'] + NTag: typeof import('naive-ui')['NTag'] + NText: typeof import('naive-ui')['NText'] + NTooltip: typeof import('naive-ui')['NTooltip'] + NUpload: typeof import('naive-ui')['NUpload'] + NUploadDragger: typeof import('naive-ui')['NUploadDragger'] + OtpCodeGeneratorAndValidator: typeof import('./src/tools/otp-code-generator-and-validator/otp-code-generator-and-validator.vue')['default'] + PhoneParserAndFormatter: typeof import('./src/tools/phone-parser-and-formatter/phone-parser-and-formatter.vue')['default'] + QrCodeGenerator: typeof import('./src/tools/qr-code-generator/qr-code-generator.vue')['default'] + RandomPortGenerator: typeof import('./src/tools/random-port-generator/random-port-generator.vue')['default'] + ResultRow: typeof import('./src/tools/ipv4-range-expander/result-row.vue')['default'] + RomanNumeralConverter: typeof import('./src/tools/roman-numeral-converter/roman-numeral-converter.vue')['default'] + 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'] + SearchBar: typeof import('./src/components/SearchBar.vue')['default'] + SearchBarItem: typeof import('./src/components/SearchBarItem.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'] + SvgPlaceholderGenerator: typeof import('./src/tools/svg-placeholder-generator/svg-placeholder-generator.vue')['default'] + TemperatureConverter: typeof import('./src/tools/temperature-converter/temperature-converter.vue')['default'] + TextareaCopyable: typeof import('./src/components/TextareaCopyable.vue')['default'] + TextStatistics: typeof import('./src/tools/text-statistics/text-statistics.vue')['default'] + TextToNatoAlphabet: typeof import('./src/tools/text-to-nato-alphabet/text-to-nato-alphabet.vue')['default'] + TokenDisplay: typeof import('./src/tools/otp-code-generator-and-validator/token-display.vue')['default'] + 'TokenGenerator.tool': typeof import('./src/tools/token-generator/token-generator.tool.vue')['default'] + 'Tool.layout': typeof import('./src/layouts/tool.layout.vue')['default'] + ToolCard: typeof import('./src/components/ToolCard.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'] + UserAgentResultCards: typeof import('./src/tools/user-agent-parser/user-agent-result-cards.vue')['default'] + UuidGenerator: typeof import('./src/tools/uuid-generator/uuid-generator.vue')['default'] + YamlToJson: typeof import('./src/tools/yaml-to-json-converter/yaml-to-json.vue')['default'] } } diff --git a/src/tools/index.ts b/src/tools/index.ts index bc54b4d2..f5aacc4d 100644 --- a/src/tools/index.ts +++ b/src/tools/index.ts @@ -1,6 +1,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 listConverter } from './list-converter'; import { tool as phoneParserAndFormatter } from './phone-parser-and-formatter'; import { tool as jsonDiff } from './json-diff'; import { tool as ipv4RangeExpander } from './ipv4-range-expander'; @@ -74,6 +75,7 @@ export const toolsByCategory: ToolCategory[] = [ textToNatoAlphabet, yamlToJson, jsonToYaml, + listConverter, ], }, { diff --git a/src/tools/list-converter/index.ts b/src/tools/list-converter/index.ts new file mode 100644 index 00000000..cf9fbd39 --- /dev/null +++ b/src/tools/list-converter/index.ts @@ -0,0 +1,13 @@ +import { List } from '@vicons/tabler'; +import { defineTool } from '../tool'; + +export const tool = defineTool({ + name: 'List converter', + path: '/list-converter', + description: + 'This tool can process column-based data and apply various changes (transpose, add prefix and suffix, reverse list, sort list, lowercase values, truncate values) to each row.', + keywords: ['list', 'converter', 'sort', 'reverse', 'prefix', 'suffix', 'lowercase', 'truncate'], + component: () => import('./list-converter.vue'), + icon: List, + createdAt: new Date('2023-05-07'), +}); diff --git a/src/tools/list-converter/list-converter.e2e.spec.ts b/src/tools/list-converter/list-converter.e2e.spec.ts new file mode 100644 index 00000000..1634a11c --- /dev/null +++ b/src/tools/list-converter/list-converter.e2e.spec.ts @@ -0,0 +1,39 @@ +import { test, expect } from '@playwright/test'; + +test.describe('Tool - List converter', () => { + test.beforeEach(async ({ page }) => { + await page.goto('/list-converter'); + }); + + test('Has correct title', async ({ page }) => { + await expect(page).toHaveTitle('List converter - IT Tools'); + }); + + test('Simple list should be converted with default settings', async ({ page }) => { + await page.getByTestId('input').fill(`1 + 2 + 3 + 4 + 5`); + + const result = await page.getByTestId('area-content').innerText(); + + expect(result.trim()).toEqual('1, 2, 3, 4, 5'); + }); + + test('Duplicates should be removed, list should be sorted and prefix and suffix list items', async ({ page }) => { + await page.getByTestId('input').fill(`1 + 2 + 2 + 4 + 4 + 3 + 5`); + await page.getByTestId('removeDuplicates').check(); + await page.getByTestId('itemPrefix').locator('input').fill("'"); + await page.getByTestId('itemSuffix').locator('input').fill("'"); + + const result = await page.getByTestId('area-content').innerText(); + expect(result.trim()).toEqual("'1', '2', '4', '3', '5'"); + }); +}); diff --git a/src/tools/list-converter/list-converter.models.test.ts b/src/tools/list-converter/list-converter.models.test.ts new file mode 100644 index 00000000..944f0f3b --- /dev/null +++ b/src/tools/list-converter/list-converter.models.test.ts @@ -0,0 +1,76 @@ +import { expect, describe, it } from 'vitest'; +import { convert } from './list-converter.models'; +import type { ConvertOptions } from './list-converter.types'; + +describe('list-converter', () => { + describe('convert', () => { + it('should convert a given list', () => { + const options: ConvertOptions = { + separator: ', ', + trimItems: true, + removeDuplicates: true, + itemPrefix: '"', + itemSuffix: '"', + listPrefix: '', + listSuffix: '', + reverseList: false, + sortList: null, + lowerCase: false, + keepLineBreaks: false, + }; + const input = ` + 1 + 2 + + 3 + 3 + 4 + `; + expect(convert(input, options)).toEqual('"1", "2", "3", "4"'); + }); + + it('should return an empty value for an empty input', () => { + const options: ConvertOptions = { + separator: ', ', + trimItems: true, + removeDuplicates: true, + itemPrefix: '', + itemSuffix: '', + listPrefix: '', + listSuffix: '', + reverseList: false, + sortList: null, + lowerCase: false, + keepLineBreaks: false, + }; + expect(convert('', options)).toEqual(''); + }); + + it('should keep line breaks', () => { + const options: ConvertOptions = { + separator: '', + trimItems: true, + itemPrefix: '
  • ', + itemSuffix: '
  • ', + listPrefix: '
      ', + listSuffix: '
    ', + keepLineBreaks: true, + lowerCase: false, + removeDuplicates: false, + reverseList: false, + sortList: null, + }; + const input = ` + 1 + 2 + 3 + `; + const expected = `
      +
    • 1
    • +
    • 2
    • +
    • 3
    • +
    `; + expect(convert(input, options)).toEqual(expected); + }); + }); +}); diff --git a/src/tools/list-converter/list-converter.models.ts b/src/tools/list-converter/list-converter.models.ts new file mode 100644 index 00000000..1df9b38a --- /dev/null +++ b/src/tools/list-converter/list-converter.models.ts @@ -0,0 +1,27 @@ +import _ from 'lodash'; +import { byOrder } from '@/utils/array'; +import type { ConvertOptions } from './list-converter.types'; + +export { convert }; + +const whenever = + (condition: boolean, fn: (value: T) => R) => + (value: T) => + condition ? fn(value) : value; + +function convert(list: string, options: ConvertOptions): string { + const lineBreak = options.keepLineBreaks ? '\n' : ''; + + return _.chain(list) + .thru(whenever(options.lowerCase, (text) => text.toLowerCase())) + .split('\n') + .thru(whenever(options.removeDuplicates, _.uniq)) + .thru(whenever(options.reverseList, _.reverse)) + .thru(whenever(!_.isNull(options.sortList), (parts) => parts.sort(byOrder({ order: options.sortList })))) + .map(whenever(options.trimItems, _.trim)) + .without('') + .map((p) => options.itemPrefix + p + options.itemSuffix) + .join(options.separator + lineBreak) + .thru((text) => [options.listPrefix, text, options.listSuffix].join(lineBreak)) + .value(); +} diff --git a/src/tools/list-converter/list-converter.types.ts b/src/tools/list-converter/list-converter.types.ts new file mode 100644 index 00000000..cfcaeade --- /dev/null +++ b/src/tools/list-converter/list-converter.types.ts @@ -0,0 +1,15 @@ +export type SortOrder = 'asc' | 'desc' | null; + +export type ConvertOptions = { + lowerCase: boolean; + trimItems: boolean; + itemPrefix: string; + itemSuffix: string; + listPrefix: string; + listSuffix: string; + reverseList: boolean; + sortList: SortOrder; + removeDuplicates: boolean; + separator: string; + keepLineBreaks: boolean; +}; diff --git a/src/tools/list-converter/list-converter.vue b/src/tools/list-converter/list-converter.vue new file mode 100644 index 00000000..ae0b50ec --- /dev/null +++ b/src/tools/list-converter/list-converter.vue @@ -0,0 +1,121 @@ + + + + + diff --git a/src/utils/array.ts b/src/utils/array.ts new file mode 100644 index 00000000..15b3506d --- /dev/null +++ b/src/utils/array.ts @@ -0,0 +1,7 @@ +export { byOrder }; + +function byOrder({ order }: { order: 'asc' | 'desc' | null | undefined }) { + return (a: string, b: string) => { + return order === 'asc' ? a.localeCompare(b) : b.localeCompare(a); + }; +} From a43c546e3454438f2660555b49459eb4a63e630c Mon Sep 17 00:00:00 2001 From: Corentin Thomasset Date: Sun, 7 May 2023 13:04:55 +0200 Subject: [PATCH 004/246] fix(phone-parser): use default country code --- .../phone-parser-and-formatter.models.ts | 6 +++--- .../phone-parser-and-formatter.vue | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/tools/phone-parser-and-formatter/phone-parser-and-formatter.models.ts b/src/tools/phone-parser-and-formatter/phone-parser-and-formatter.models.ts index 1e2a483d..e8bbb177 100644 --- a/src/tools/phone-parser-and-formatter/phone-parser-and-formatter.models.ts +++ b/src/tools/phone-parser-and-formatter/phone-parser-and-formatter.models.ts @@ -1,4 +1,4 @@ -import type { NumberType } from 'libphonenumber-js/types'; +import type { CountryCode, NumberType } from 'libphonenumber-js/types'; import lookup from 'country-code-lookup'; export { formatTypeToHumanReadable, getFullCountryName, getDefaultCountryCode }; @@ -32,10 +32,10 @@ function getFullCountryName(countryCode: string | undefined) { function getDefaultCountryCode({ locale = window.navigator.language, defaultCode = 'FR', -}: { locale?: string; defaultCode?: string } = {}): string { +}: { locale?: string; defaultCode?: CountryCode } = {}): CountryCode { const countryCode = locale.split('-')[1]?.toUpperCase(); if (!countryCode) return defaultCode; - return lookup.byIso(countryCode)?.iso2 ?? defaultCode; + return (lookup.byIso(countryCode)?.iso2 ?? defaultCode) as CountryCode; } diff --git a/src/tools/phone-parser-and-formatter/phone-parser-and-formatter.vue b/src/tools/phone-parser-and-formatter/phone-parser-and-formatter.vue index d17356a9..dad4ddc3 100644 --- a/src/tools/phone-parser-and-formatter/phone-parser-and-formatter.vue +++ b/src/tools/phone-parser-and-formatter/phone-parser-and-formatter.vue @@ -50,7 +50,7 @@ const validation = useValidation({ const parsedDetails = computed(() => { if (!validation.isValid) return undefined; - const parsed = withDefaultOnError(() => parsePhoneNumber(rawPhone.value, 'FR'), undefined); + const parsed = withDefaultOnError(() => parsePhoneNumber(rawPhone.value, defaultCountryCode.value), undefined); if (!parsed) return undefined; From edae4c6915efc83997ccbad3299251209ca2bebc Mon Sep 17 00:00:00 2001 From: Corentin THOMASSET Date: Sat, 13 May 2023 22:09:36 +0200 Subject: [PATCH 005/246] chore(issues): updated new tool request issue template --- .github/ISSUE_TEMPLATE/new-tool-request.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/new-tool-request.md b/.github/ISSUE_TEMPLATE/new-tool-request.md index 58775d1a..a67a9cd0 100644 --- a/.github/ISSUE_TEMPLATE/new-tool-request.md +++ b/.github/ISSUE_TEMPLATE/new-tool-request.md @@ -6,8 +6,8 @@ labels: new tool assignees: CorentinTh --- -**Which tool is impacted?** -Example: the token generator +**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. From 401f13f7e305d60097db2334642e423c41d8897d Mon Sep 17 00:00:00 2001 From: Corentin Thomasset Date: Sun, 7 May 2023 23:29:55 +0200 Subject: [PATCH 006/246] ui-lib(button): size variants --- src/ui/c-button/c-button.demo.vue | 41 ++++++++++++++++++++----------- src/ui/c-button/c-button.theme.ts | 15 +++++++++++ src/ui/c-button/c-button.vue | 15 +++++++---- 3 files changed, 51 insertions(+), 20 deletions(-) diff --git a/src/ui/c-button/c-button.demo.vue b/src/ui/c-button/c-button.demo.vue index 988659f5..4e9aa1ab 100644 --- a/src/ui/c-button/c-button.demo.vue +++ b/src/ui/c-button/c-button.demo.vue @@ -2,28 +2,39 @@

    {{ _.capitalize(buttonVariant) }}

    - - Button - +
    + + Button + - - A - + + A + +
    diff --git a/src/ui/c-button/c-button.theme.ts b/src/ui/c-button/c-button.theme.ts index 87ad89f3..e96ac56b 100644 --- a/src/ui/c-button/c-button.theme.ts +++ b/src/ui/c-button/c-button.theme.ts @@ -27,6 +27,21 @@ const createTheme = ({ style }: { style: 'light' | 'dark' }) => { const theme = appThemes[style]; return { + size: { + small: { + width: '28px', + fontSize: '12px', + }, + medium: { + width: '34px', + fontSize: '14px', + }, + large: { + width: '40px', + fontSize: '16px', + }, + }, + basic: { default: createState({ textColor: theme.text.baseColor, diff --git a/src/ui/c-button/c-button.vue b/src/ui/c-button/c-button.vue index 2cbc4fd4..c17b0781 100644 --- a/src/ui/c-button/c-button.vue +++ b/src/ui/c-button/c-button.vue @@ -25,6 +25,7 @@ const props = withDefaults( circle?: boolean; href?: string; to?: RouteLocationRaw; + size?: 'small' | 'medium' | 'large'; }>(), { type: 'default', @@ -34,9 +35,10 @@ const props = withDefaults( circle: false, href: undefined, to: undefined, + size: 'medium', }, ); -const { variant, disabled, round, circle, href, type, to } = toRefs(props); +const { variant, disabled, round, circle, href, type, to, size: sizeName } = toRefs(props); const emits = defineEmits(['click']); @@ -58,18 +60,20 @@ const tag = computed(() => { return 'button'; }); const appTheme = useAppTheme(); + +const size = computed(() => theme.value.size[sizeName.value]); diff --git a/src/ui/demo/demo-wrapper.vue b/src/ui/demo/demo-wrapper.vue index cc16a00f..8d4bae00 100644 --- a/src/ui/demo/demo-wrapper.vue +++ b/src/ui/demo/demo-wrapper.vue @@ -18,6 +18,8 @@
    +

    {{ componentName }}

    +
    @@ -25,9 +27,12 @@ diff --git a/src/ui/demo/demo.routes.ts b/src/ui/demo/demo.routes.ts index 0e9a9e4e..9ae1e77f 100644 --- a/src/ui/demo/demo.routes.ts +++ b/src/ui/demo/demo.routes.ts @@ -6,8 +6,6 @@ export const demoRoutes = Object.keys(demoPages).map((path) => { const [, , fileName] = path.split('/'); const name = fileName.split('.').shift(); - console.log(path); - return { path: name, name, diff --git a/src/utils/random.ts b/src/utils/random.ts index 6df941db..3a13be50 100644 --- a/src/utils/random.ts +++ b/src/utils/random.ts @@ -18,4 +18,14 @@ const shuffleArray = (array: T[]): T[] => shuffleArrayMutate([...array]); const shuffleString = (str: string, delimiter = ''): string => shuffleArrayMutate(str.split(delimiter)).join(delimiter); -export { randFromArray, randIntFromInterval, random, shuffleArray, shuffleArrayMutate, shuffleString }; +const generateRandomId = () => `id-${random().toString(36).substring(2, 12)}`; + +export { + randFromArray, + randIntFromInterval, + random, + shuffleArray, + shuffleArrayMutate, + shuffleString, + generateRandomId, +}; diff --git a/tsconfig.app.json b/tsconfig.app.json index 45ddfca0..ceea5615 100644 --- a/tsconfig.app.json +++ b/tsconfig.app.json @@ -9,6 +9,6 @@ "paths": { "@/*": ["./src/*"] }, - "types": ["naive-ui/volar"] + "types": ["naive-ui/volar", "unplugin-icons/types/vue"] } } diff --git a/vite.config.ts b/vite.config.ts index 0112ebd2..bca5bf6c 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -10,6 +10,9 @@ import AutoImport from 'unplugin-auto-import/vite'; import Components from 'unplugin-vue-components/vite'; import { NaiveUiResolver } from 'unplugin-vue-components/resolvers'; import Unocss from 'unocss/vite'; +import { configDefaults } from 'vitest/config'; +import Icons from 'unplugin-icons/vite'; +import IconsResolver from 'unplugin-icons/resolver'; // https://vitejs.dev/config/ export default defineConfig({ @@ -28,7 +31,7 @@ export default defineConfig({ enabled: true, }, }), - + Icons({ compiler: 'vue3' }), vue({ include: [/\.vue$/, /\.md$/], }), @@ -76,7 +79,7 @@ export default defineConfig({ dirs: ['src/'], extensions: ['vue', 'md'], include: [/\.vue$/, /\.vue\?vue/, /\.md$/], - resolvers: [NaiveUiResolver()], + resolvers: [NaiveUiResolver(), IconsResolver({ prefix: 'icon' })], }), Unocss(), ], @@ -88,4 +91,7 @@ export default defineConfig({ define: { 'import.meta.env.PACKAGE_VERSION': JSON.stringify(process.env.npm_package_version), }, + test: { + exclude: [...configDefaults.exclude, '**/*.e2e.spec.ts'], + }, }); diff --git a/vitest.config.ts b/vitest.config.ts deleted file mode 100644 index 1c0d1e52..00000000 --- a/vitest.config.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { configDefaults, defineConfig } from 'vitest/config'; -import path from 'path'; - -export default defineConfig({ - resolve: { - alias: { - '@': path.resolve(__dirname, './src'), - }, - }, - test: { - exclude: [...configDefaults.exclude, '**/*.e2e.spec.ts'], - }, -}); From 77f2efc0b92847c3b1198446f4b520ecb2263164 Mon Sep 17 00:00:00 2001 From: Corentin Thomasset Date: Sun, 14 May 2023 21:26:18 +0200 Subject: [PATCH 008/246] refactor(ui): replaced some n-input with c-input-text --- auto-imports.d.ts | 72 ++++++- components.d.ts | 5 + src/components/FormatTransformer.vue | 4 +- src/components/InputCopyable.vue | 15 +- .../base64-string-converter.vue | 2 +- .../basic-auth-generator.vue | 22 +-- src/tools/bcrypt/bcrypt.vue | 49 ++--- .../benchmark-builder/benchmark-builder.vue | 18 +- src/tools/bip39-generator/bip39-generator.vue | 13 +- src/tools/case-converter/case-converter.vue | 12 +- src/tools/chronometer/chronometer.vue | 4 +- src/tools/color-converter/color-converter.vue | 34 ++-- .../crontab-generator/crontab-generator.vue | 49 ++--- .../date-time-converter.vue | 27 +-- src/tools/encryption/encryption.vue | 18 +- .../integer-base-converter.vue | 93 ++++----- .../ipv4-address-converter.vue | 25 ++- .../ipv4-range-expander.vue | 4 +- .../ipv4-subnet-calculator.vue | 26 +-- .../ipv6-ula-generator/ipv6-ula-generator.vue | 50 ++--- src/tools/json-diff/json-diff.vue | 8 +- .../list-converter/list-converter.e2e.spec.ts | 4 +- src/tools/list-converter/list-converter.vue | 56 +++--- .../mac-address-lookup/mac-address-lookup.vue | 2 +- .../meta-tag-generator/meta-tag-generator.vue | 2 +- .../otp-code-generator-and-validator.vue | 122 ++++++------ .../phone-parser-and-formatter.vue | 11 +- .../roman-numeral-converter.vue | 11 +- .../rsa-key-pair-generator.vue | 2 +- .../svg-placeholder-generator.vue | 12 +- .../text-to-nato-alphabet.vue | 10 +- src/tools/url-parser/url-parser.vue | 70 ++++--- src/ui/c-button/c-button.demo.vue | 14 +- src/ui/c-button/c-button.theme.ts | 16 +- src/ui/c-button/c-button.vue | 2 +- src/ui/c-input-text/c-input-text.demo.vue | 45 ++++- src/ui/c-input-text/c-input-text.test.ts | 79 +++++++- src/ui/c-input-text/c-input-text.vue | 176 ++++++++++++++---- src/ui/theme/themes.ts | 2 + 39 files changed, 738 insertions(+), 448 deletions(-) diff --git a/auto-imports.d.ts b/auto-imports.d.ts index 2850890b..9dccb44a 100644 --- a/auto-imports.d.ts +++ b/auto-imports.d.ts @@ -19,7 +19,9 @@ declare global { const createGlobalState: typeof import('@vueuse/core')['createGlobalState'] const createInjectionState: typeof import('@vueuse/core')['createInjectionState'] const createReactiveFn: typeof import('@vueuse/core')['createReactiveFn'] + const createReusableTemplate: typeof import('@vueuse/core')['createReusableTemplate'] const createSharedComposable: typeof import('@vueuse/core')['createSharedComposable'] + const createTemplatePromise: typeof import('@vueuse/core')['createTemplatePromise'] const createUnrefFn: typeof import('@vueuse/core')['createUnrefFn'] const customRef: typeof import('vue')['customRef'] const debouncedRef: typeof import('@vueuse/core')['debouncedRef'] @@ -39,9 +41,6 @@ declare global { const isReactive: typeof import('vue')['isReactive'] const isReadonly: typeof import('vue')['isReadonly'] const isRef: typeof import('vue')['isRef'] - const logicAnd: typeof import('@vueuse/core')['logicAnd'] - const logicNot: typeof import('@vueuse/core')['logicNot'] - const logicOr: typeof import('@vueuse/core')['logicOr'] const makeDestructurable: typeof import('@vueuse/core')['makeDestructurable'] const markRaw: typeof import('vue')['markRaw'] const nextTick: typeof import('vue')['nextTick'] @@ -92,8 +91,9 @@ declare global { const throttledWatch: typeof import('@vueuse/core')['throttledWatch'] const toRaw: typeof import('vue')['toRaw'] const toReactive: typeof import('@vueuse/core')['toReactive'] - const toRef: typeof import('vue')['toRef'] + const toRef: typeof import('@vueuse/core')['toRef'] const toRefs: typeof import('vue')['toRefs'] + const toValue: typeof import('@vueuse/core')['toValue'] const triggerRef: typeof import('vue')['triggerRef'] const tryOnBeforeMount: typeof import('@vueuse/core')['tryOnBeforeMount'] const tryOnBeforeUnmount: typeof import('@vueuse/core')['tryOnBeforeUnmount'] @@ -104,6 +104,19 @@ declare global { const unrefElement: typeof import('@vueuse/core')['unrefElement'] const until: typeof import('@vueuse/core')['until'] const useActiveElement: typeof import('@vueuse/core')['useActiveElement'] + const useAnimate: typeof import('@vueuse/core')['useAnimate'] + const useArrayDifference: typeof import('@vueuse/core')['useArrayDifference'] + const useArrayEvery: typeof import('@vueuse/core')['useArrayEvery'] + const useArrayFilter: typeof import('@vueuse/core')['useArrayFilter'] + const useArrayFind: typeof import('@vueuse/core')['useArrayFind'] + const useArrayFindIndex: typeof import('@vueuse/core')['useArrayFindIndex'] + const useArrayFindLast: typeof import('@vueuse/core')['useArrayFindLast'] + const useArrayIncludes: typeof import('@vueuse/core')['useArrayIncludes'] + const useArrayJoin: typeof import('@vueuse/core')['useArrayJoin'] + const useArrayMap: typeof import('@vueuse/core')['useArrayMap'] + const useArrayReduce: typeof import('@vueuse/core')['useArrayReduce'] + const useArraySome: typeof import('@vueuse/core')['useArraySome'] + const useArrayUnique: typeof import('@vueuse/core')['useArrayUnique'] const useAsyncQueue: typeof import('@vueuse/core')['useAsyncQueue'] const useAsyncState: typeof import('@vueuse/core')['useAsyncState'] const useAttrs: typeof import('vue')['useAttrs'] @@ -114,8 +127,8 @@ declare global { const useBroadcastChannel: typeof import('@vueuse/core')['useBroadcastChannel'] const useBrowserLocation: typeof import('@vueuse/core')['useBrowserLocation'] const useCached: typeof import('@vueuse/core')['useCached'] - const useClamp: typeof import('@vueuse/core')['useClamp'] const useClipboard: typeof import('@vueuse/core')['useClipboard'] + const useCloned: typeof import('@vueuse/core')['useCloned'] const useColorMode: typeof import('@vueuse/core')['useColorMode'] const useConfirmDialog: typeof import('@vueuse/core')['useConfirmDialog'] const useCounter: typeof import('@vueuse/core')['useCounter'] @@ -189,12 +202,18 @@ declare global { const useOnline: typeof import('@vueuse/core')['useOnline'] const usePageLeave: typeof import('@vueuse/core')['usePageLeave'] const useParallax: typeof import('@vueuse/core')['useParallax'] + const useParentElement: typeof import('@vueuse/core')['useParentElement'] + const usePerformanceObserver: typeof import('@vueuse/core')['usePerformanceObserver'] const usePermission: typeof import('@vueuse/core')['usePermission'] const usePointer: typeof import('@vueuse/core')['usePointer'] + const usePointerLock: typeof import('@vueuse/core')['usePointerLock'] const usePointerSwipe: typeof import('@vueuse/core')['usePointerSwipe'] const usePreferredColorScheme: typeof import('@vueuse/core')['usePreferredColorScheme'] + const usePreferredContrast: typeof import('@vueuse/core')['usePreferredContrast'] const usePreferredDark: typeof import('@vueuse/core')['usePreferredDark'] const usePreferredLanguages: typeof import('@vueuse/core')['usePreferredLanguages'] + const usePreferredReducedMotion: typeof import('@vueuse/core')['usePreferredReducedMotion'] + const usePrevious: typeof import('@vueuse/core')['usePrevious'] const useRafFn: typeof import('@vueuse/core')['useRafFn'] const useRefHistory: typeof import('@vueuse/core')['useRefHistory'] const useResizeObserver: typeof import('@vueuse/core')['useResizeObserver'] @@ -208,14 +227,17 @@ declare global { const useSessionStorage: typeof import('@vueuse/core')['useSessionStorage'] const useShare: typeof import('@vueuse/core')['useShare'] const useSlots: typeof import('vue')['useSlots'] + const useSorted: typeof import('@vueuse/core')['useSorted'] const useSpeechRecognition: typeof import('@vueuse/core')['useSpeechRecognition'] const useSpeechSynthesis: typeof import('@vueuse/core')['useSpeechSynthesis'] const useStepper: typeof import('@vueuse/core')['useStepper'] const useStorage: typeof import('@vueuse/core')['useStorage'] const useStorageAsync: typeof import('@vueuse/core')['useStorageAsync'] const useStyleTag: typeof import('@vueuse/core')['useStyleTag'] + const useSupported: typeof import('@vueuse/core')['useSupported'] const useSwipe: typeof import('@vueuse/core')['useSwipe'] const useTemplateRefsList: typeof import('@vueuse/core')['useTemplateRefsList'] + const useTextDirection: typeof import('@vueuse/core')['useTextDirection'] const useTextSelection: typeof import('@vueuse/core')['useTextSelection'] const useTextareaAutosize: typeof import('@vueuse/core')['useTextareaAutosize'] const useThrottle: typeof import('@vueuse/core')['useThrottle'] @@ -227,6 +249,8 @@ declare global { const useTimeoutPoll: typeof import('@vueuse/core')['useTimeoutPoll'] const useTimestamp: typeof import('@vueuse/core')['useTimestamp'] const useTitle: typeof import('@vueuse/core')['useTitle'] + const useToNumber: typeof import('@vueuse/core')['useToNumber'] + const useToString: typeof import('@vueuse/core')['useToString'] const useToggle: typeof import('@vueuse/core')['useToggle'] const useTransition: typeof import('@vueuse/core')['useTransition'] const useUrlSearchParams: typeof import('@vueuse/core')['useUrlSearchParams'] @@ -247,8 +271,10 @@ declare global { const watchArray: typeof import('@vueuse/core')['watchArray'] const watchAtMost: typeof import('@vueuse/core')['watchAtMost'] const watchDebounced: typeof import('@vueuse/core')['watchDebounced'] + const watchDeep: typeof import('@vueuse/core')['watchDeep'] const watchEffect: typeof import('vue')['watchEffect'] const watchIgnorable: typeof import('@vueuse/core')['watchIgnorable'] + const watchImmediate: typeof import('@vueuse/core')['watchImmediate'] const watchOnce: typeof import('@vueuse/core')['watchOnce'] const watchPausable: typeof import('@vueuse/core')['watchPausable'] const watchPostEffect: typeof import('vue')['watchPostEffect'] @@ -282,7 +308,9 @@ declare module 'vue' { readonly createGlobalState: UnwrapRef readonly createInjectionState: UnwrapRef readonly createReactiveFn: UnwrapRef + readonly createReusableTemplate: UnwrapRef readonly createSharedComposable: UnwrapRef + readonly createTemplatePromise: UnwrapRef readonly createUnrefFn: UnwrapRef readonly customRef: UnwrapRef readonly debouncedRef: UnwrapRef @@ -302,9 +330,6 @@ declare module 'vue' { readonly isReactive: UnwrapRef readonly isReadonly: UnwrapRef readonly isRef: UnwrapRef - readonly logicAnd: UnwrapRef - readonly logicNot: UnwrapRef - readonly logicOr: UnwrapRef readonly makeDestructurable: UnwrapRef readonly markRaw: UnwrapRef readonly nextTick: UnwrapRef @@ -355,8 +380,9 @@ declare module 'vue' { readonly throttledWatch: UnwrapRef readonly toRaw: UnwrapRef readonly toReactive: UnwrapRef - readonly toRef: UnwrapRef + readonly toRef: UnwrapRef readonly toRefs: UnwrapRef + readonly toValue: UnwrapRef readonly triggerRef: UnwrapRef readonly tryOnBeforeMount: UnwrapRef readonly tryOnBeforeUnmount: UnwrapRef @@ -367,6 +393,19 @@ declare module 'vue' { readonly unrefElement: UnwrapRef readonly until: UnwrapRef readonly useActiveElement: UnwrapRef + readonly useAnimate: UnwrapRef + readonly useArrayDifference: UnwrapRef + readonly useArrayEvery: UnwrapRef + readonly useArrayFilter: UnwrapRef + readonly useArrayFind: UnwrapRef + readonly useArrayFindIndex: UnwrapRef + readonly useArrayFindLast: UnwrapRef + readonly useArrayIncludes: UnwrapRef + readonly useArrayJoin: UnwrapRef + readonly useArrayMap: UnwrapRef + readonly useArrayReduce: UnwrapRef + readonly useArraySome: UnwrapRef + readonly useArrayUnique: UnwrapRef readonly useAsyncQueue: UnwrapRef readonly useAsyncState: UnwrapRef readonly useAttrs: UnwrapRef @@ -377,8 +416,8 @@ declare module 'vue' { readonly useBroadcastChannel: UnwrapRef readonly useBrowserLocation: UnwrapRef readonly useCached: UnwrapRef - readonly useClamp: UnwrapRef readonly useClipboard: UnwrapRef + readonly useCloned: UnwrapRef readonly useColorMode: UnwrapRef readonly useConfirmDialog: UnwrapRef readonly useCounter: UnwrapRef @@ -452,12 +491,18 @@ declare module 'vue' { readonly useOnline: UnwrapRef readonly usePageLeave: UnwrapRef readonly useParallax: UnwrapRef + readonly useParentElement: UnwrapRef + readonly usePerformanceObserver: UnwrapRef readonly usePermission: UnwrapRef readonly usePointer: UnwrapRef + readonly usePointerLock: UnwrapRef readonly usePointerSwipe: UnwrapRef readonly usePreferredColorScheme: UnwrapRef + readonly usePreferredContrast: UnwrapRef readonly usePreferredDark: UnwrapRef readonly usePreferredLanguages: UnwrapRef + readonly usePreferredReducedMotion: UnwrapRef + readonly usePrevious: UnwrapRef readonly useRafFn: UnwrapRef readonly useRefHistory: UnwrapRef readonly useResizeObserver: UnwrapRef @@ -471,14 +516,17 @@ declare module 'vue' { readonly useSessionStorage: UnwrapRef readonly useShare: UnwrapRef readonly useSlots: UnwrapRef + readonly useSorted: UnwrapRef readonly useSpeechRecognition: UnwrapRef readonly useSpeechSynthesis: UnwrapRef readonly useStepper: UnwrapRef readonly useStorage: UnwrapRef readonly useStorageAsync: UnwrapRef readonly useStyleTag: UnwrapRef + readonly useSupported: UnwrapRef readonly useSwipe: UnwrapRef readonly useTemplateRefsList: UnwrapRef + readonly useTextDirection: UnwrapRef readonly useTextSelection: UnwrapRef readonly useTextareaAutosize: UnwrapRef readonly useThrottle: UnwrapRef @@ -490,6 +538,8 @@ declare module 'vue' { readonly useTimeoutPoll: UnwrapRef readonly useTimestamp: UnwrapRef readonly useTitle: UnwrapRef + readonly useToNumber: UnwrapRef + readonly useToString: UnwrapRef readonly useToggle: UnwrapRef readonly useTransition: UnwrapRef readonly useUrlSearchParams: UnwrapRef @@ -510,8 +560,10 @@ declare module 'vue' { readonly watchArray: UnwrapRef readonly watchAtMost: UnwrapRef readonly watchDebounced: UnwrapRef + readonly watchDeep: UnwrapRef readonly watchEffect: UnwrapRef readonly watchIgnorable: UnwrapRef + readonly watchImmediate: UnwrapRef readonly watchOnce: UnwrapRef readonly watchPausable: UnwrapRef readonly watchPostEffect: UnwrapRef diff --git a/components.d.ts b/components.d.ts index 65c82baa..40b805a9 100644 --- a/components.d.ts +++ b/components.d.ts @@ -56,7 +56,12 @@ declare module '@vue/runtime-core' { HtmlEntities: typeof import('./src/tools/html-entities/html-entities.vue')['default'] HtmlWysiwygEditor: typeof import('./src/tools/html-wysiwyg-editor/html-wysiwyg-editor.vue')['default'] HttpStatusCodes: typeof import('./src/tools/http-status-codes/http-status-codes.vue')['default'] + IconMdiArrowRightBottom: typeof import('~icons/mdi/arrow-right-bottom')['default'] IconMdiClose: typeof import('~icons/mdi/close')['default'] + IconMdiContentCopy: typeof import('~icons/mdi/content-copy')['default'] + IconMdiEye: typeof import('~icons/mdi/eye')['default'] + IconMdiEyeOff: typeof import('~icons/mdi/eye-off')['default'] + IconMdiRefresh: typeof import('~icons/mdi/refresh')['default'] InputCopyable: typeof import('./src/components/InputCopyable.vue')['default'] IntegerBaseConverter: typeof import('./src/tools/integer-base-converter/integer-base-converter.vue')['default'] Ipv4AddressConverter: typeof import('./src/tools/ipv4-address-converter/ipv4-address-converter.vue')['default'] diff --git a/src/components/FormatTransformer.vue b/src/components/FormatTransformer.vue index dea5d56a..d1876328 100644 --- a/src/components/FormatTransformer.vue +++ b/src/components/FormatTransformer.vue @@ -1,5 +1,5 @@