diff --git a/.idea/workspace.xml b/.idea/workspace.xml
index 6179760..02eecf5 100644
--- a/.idea/workspace.xml
+++ b/.idea/workspace.xml
@@ -4,8 +4,12 @@
-
+
+
+
+
+
@@ -22,7 +26,7 @@
@@ -199,56 +203,56 @@
- {
- "keyToString": {
- "ASKED_ADD_EXTERNAL_FILES": "true",
- "ASKED_SHARE_PROJECT_CONFIGURATION_FILES": "true",
- "Docker.Dockerfile build.executor": "Run",
- "Docker.Dockerfile.executor": "Run",
- "Playwright.Create transparent PNG.should make png color transparent.executor": "Run",
- "Playwright.JoinText Component.executor": "Run",
- "Playwright.JoinText Component.should merge text pieces with specified join character.executor": "Run",
- "RunOnceActivity.OpenProjectViewOnStart": "true",
- "RunOnceActivity.ShowReadmeOnStart": "true",
- "RunOnceActivity.git.unshallow": "true",
- "Vitest.compute function (1).executor": "Run",
- "Vitest.compute function.executor": "Run",
- "Vitest.mergeText.executor": "Run",
- "Vitest.mergeText.should merge lines and preserve blank lines when deleteBlankLines is false.executor": "Run",
- "Vitest.mergeText.should merge lines, preserve blank lines and trailing spaces when both deleteBlankLines and deleteTrailingSpaces are false.executor": "Run",
- "Vitest.parsePageRanges.executor": "Run",
- "Vitest.removeDuplicateLines function.executor": "Run",
- "Vitest.removeDuplicateLines function.newlines option.executor": "Run",
- "Vitest.removeDuplicateLines function.newlines option.should filter newlines when newlines is set to filter.executor": "Run",
- "Vitest.replaceText function (regexp mode).should return the original text when passed an invalid regexp.executor": "Run",
- "Vitest.replaceText function.executor": "Run",
- "Vitest.timeBetweenDates.executor": "Run",
- "git-widget-placeholder": "#131 on fork/ARRY7686/main",
- "ignore.virus.scanning.warn.message": "true",
- "kotlin-language-version-configured": "true",
- "last_opened_file_path": "C:/Users/Ibrahima/IdeaProjects/omni-tools/src",
- "node.js.detected.package.eslint": "true",
- "node.js.detected.package.tslint": "true",
- "node.js.selected.package.eslint": "(autodetect)",
- "node.js.selected.package.tslint": "(autodetect)",
- "nodejs_package_manager_path": "npm",
- "npm.build.executor": "Run",
- "npm.dev.executor": "Run",
- "npm.lint.executor": "Run",
- "npm.prebuild.executor": "Run",
- "npm.script:create:tool.executor": "Run",
- "npm.test.executor": "Run",
- "npm.test:e2e.executor": "Run",
- "npm.test:e2e:run.executor": "Run",
- "prettierjs.PrettierConfiguration.Package": "C:\\Users\\Ibrahima\\IdeaProjects\\omni-tools\\node_modules\\prettier",
- "project.structure.last.edited": "Problems",
- "project.structure.proportion": "0.0",
- "project.structure.side.proportion": "0.2",
- "settings.editor.selected.configurable": "refactai_advanced_settings",
- "ts.external.directory.path": "C:\\Users\\Ibrahima\\IdeaProjects\\omni-tools\\node_modules\\typescript\\lib",
- "vue.rearranger.settings.migration": "true"
+
+}]]>
@@ -902,7 +906,6 @@
-
@@ -927,7 +930,8 @@
-
+
+
diff --git a/package-lock.json b/package-lock.json
index 9f5b3c2..e501cc8 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -41,6 +41,7 @@
"pdf-lib": "^1.17.1",
"pdfjs-dist": "^5.2.133",
"playwright": "^1.45.0",
+ "qrcode": "^1.5.4",
"rc-slider": "^11.1.8",
"react": "^18.3.1",
"react-dom": "^18.3.1",
@@ -61,6 +62,7 @@
"@types/color": "^3.0.6",
"@types/color-rgba": "^2.1.2",
"@types/node": "^20.12.12",
+ "@types/qrcode": "^1.5.5",
"@types/react": "^18.3.3",
"@types/react-dom": "^18.3.0",
"@types/react-helmet": "^6.1.11",
@@ -3369,6 +3371,16 @@
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.12.tgz",
"integrity": "sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q=="
},
+ "node_modules/@types/qrcode": {
+ "version": "1.5.5",
+ "resolved": "https://registry.npmjs.org/@types/qrcode/-/qrcode-1.5.5.tgz",
+ "integrity": "sha512-CdfBi/e3Qk+3Z/fXYShipBT13OJ2fDO2Q2w5CIP5anLTLIndQG9z6P1cnm+8zCWSpm5dnxMFd/uREtb0EXuQzg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/node": "*"
+ }
+ },
"node_modules/@types/react": {
"version": "18.3.3",
"resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.3.tgz",
@@ -3867,7 +3879,6 @@
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
- "dev": true,
"engines": {
"node": ">=8"
}
@@ -3876,7 +3887,6 @@
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "dev": true,
"dependencies": {
"color-convert": "^2.0.1"
},
@@ -4375,6 +4385,15 @@
"node": ">=6"
}
},
+ "node_modules/camelcase": {
+ "version": "5.3.1",
+ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
+ "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
"node_modules/camelcase-css": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz",
@@ -4921,6 +4940,15 @@
}
}
},
+ "node_modules/decamelize": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
+ "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/deep-eql": {
"version": "4.1.4",
"resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.4.tgz",
@@ -5045,6 +5073,12 @@
"node": "^14.15.0 || ^16.10.0 || >=18.0.0"
}
},
+ "node_modules/dijkstrajs": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/dijkstrajs/-/dijkstrajs-1.0.3.tgz",
+ "integrity": "sha512-qiSlmBq9+BCdCA/L46dw8Uy93mloxsPSbwnm5yrKn2vMPiy8KyAskTF6zuV/j5BMsmOGZDPs7KjU+mjb670kfA==",
+ "license": "MIT"
+ },
"node_modules/dir-glob": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
@@ -6105,7 +6139,6 @@
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
"integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
- "dev": true,
"engines": {
"node": "6.* || 8.* || >= 10.*"
}
@@ -6848,7 +6881,6 @@
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
- "dev": true,
"engines": {
"node": ">=8"
}
@@ -8478,6 +8510,15 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/p-try": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
+ "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
"node_modules/package-json-from-dist": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.0.tgz",
@@ -8546,7 +8587,6 @@
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
"integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
- "dev": true,
"engines": {
"node": ">=8"
}
@@ -9129,6 +9169,170 @@
"node": ">=6"
}
},
+ "node_modules/qrcode": {
+ "version": "1.5.4",
+ "resolved": "https://registry.npmjs.org/qrcode/-/qrcode-1.5.4.tgz",
+ "integrity": "sha512-1ca71Zgiu6ORjHqFBDpnSMTR2ReToX4l1Au1VFLyVeBTFavzQnv5JxMFr3ukHVKpSrSA2MCk0lNJSykjUfz7Zg==",
+ "license": "MIT",
+ "dependencies": {
+ "dijkstrajs": "^1.0.1",
+ "pngjs": "^5.0.0",
+ "yargs": "^15.3.1"
+ },
+ "bin": {
+ "qrcode": "bin/qrcode"
+ },
+ "engines": {
+ "node": ">=10.13.0"
+ }
+ },
+ "node_modules/qrcode/node_modules/cliui": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz",
+ "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==",
+ "license": "ISC",
+ "dependencies": {
+ "string-width": "^4.2.0",
+ "strip-ansi": "^6.0.0",
+ "wrap-ansi": "^6.2.0"
+ }
+ },
+ "node_modules/qrcode/node_modules/emoji-regex": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+ "license": "MIT"
+ },
+ "node_modules/qrcode/node_modules/find-up": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
+ "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
+ "license": "MIT",
+ "dependencies": {
+ "locate-path": "^5.0.0",
+ "path-exists": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/qrcode/node_modules/locate-path": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
+ "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
+ "license": "MIT",
+ "dependencies": {
+ "p-locate": "^4.1.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/qrcode/node_modules/p-limit": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
+ "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
+ "license": "MIT",
+ "dependencies": {
+ "p-try": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/qrcode/node_modules/p-locate": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
+ "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
+ "license": "MIT",
+ "dependencies": {
+ "p-limit": "^2.2.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/qrcode/node_modules/pngjs": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-5.0.0.tgz",
+ "integrity": "sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=10.13.0"
+ }
+ },
+ "node_modules/qrcode/node_modules/string-width": {
+ "version": "4.2.3",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+ "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+ "license": "MIT",
+ "dependencies": {
+ "emoji-regex": "^8.0.0",
+ "is-fullwidth-code-point": "^3.0.0",
+ "strip-ansi": "^6.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/qrcode/node_modules/wrap-ansi": {
+ "version": "6.2.0",
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz",
+ "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==",
+ "license": "MIT",
+ "dependencies": {
+ "ansi-styles": "^4.0.0",
+ "string-width": "^4.1.0",
+ "strip-ansi": "^6.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/qrcode/node_modules/y18n": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz",
+ "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==",
+ "license": "ISC"
+ },
+ "node_modules/qrcode/node_modules/yargs": {
+ "version": "15.4.1",
+ "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz",
+ "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==",
+ "license": "MIT",
+ "dependencies": {
+ "cliui": "^6.0.0",
+ "decamelize": "^1.2.0",
+ "find-up": "^4.1.0",
+ "get-caller-file": "^2.0.1",
+ "require-directory": "^2.1.1",
+ "require-main-filename": "^2.0.0",
+ "set-blocking": "^2.0.0",
+ "string-width": "^4.2.0",
+ "which-module": "^2.0.0",
+ "y18n": "^4.0.0",
+ "yargs-parser": "^18.1.2"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/qrcode/node_modules/yargs-parser": {
+ "version": "18.1.3",
+ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz",
+ "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==",
+ "license": "ISC",
+ "dependencies": {
+ "camelcase": "^5.0.0",
+ "decamelize": "^1.2.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
"node_modules/queue-microtask": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
@@ -9412,7 +9616,6 @@
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
"integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
- "dev": true,
"engines": {
"node": ">=0.10.0"
}
@@ -9426,6 +9629,12 @@
"node": ">=0.10.0"
}
},
+ "node_modules/require-main-filename": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz",
+ "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==",
+ "license": "ISC"
+ },
"node_modules/resolve": {
"version": "2.0.0-next.5",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.5.tgz",
@@ -9666,6 +9875,12 @@
"node": ">=10"
}
},
+ "node_modules/set-blocking": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
+ "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==",
+ "license": "ISC"
+ },
"node_modules/set-function-length": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz",
@@ -10197,7 +10412,6 @@
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
- "dev": true,
"dependencies": {
"ansi-regex": "^5.0.1"
},
@@ -11203,6 +11417,12 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/which-module": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz",
+ "integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==",
+ "license": "ISC"
+ },
"node_modules/which-typed-array": {
"version": "1.1.15",
"resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.15.tgz",
diff --git a/package.json b/package.json
index 7e43cbe..ed7ebcf 100644
--- a/package.json
+++ b/package.json
@@ -58,6 +58,7 @@
"pdf-lib": "^1.17.1",
"pdfjs-dist": "^5.2.133",
"playwright": "^1.45.0",
+ "qrcode": "^1.5.4",
"rc-slider": "^11.1.8",
"react": "^18.3.1",
"react-dom": "^18.3.1",
@@ -78,6 +79,7 @@
"@types/color": "^3.0.6",
"@types/color-rgba": "^2.1.2",
"@types/node": "^20.12.12",
+ "@types/qrcode": "^1.5.5",
"@types/react": "^18.3.3",
"@types/react-dom": "^18.3.0",
"@types/react-helmet": "^6.1.11",
diff --git a/src/components/options/ColorSelector.tsx b/src/components/options/ColorSelector.tsx
index a89ea1d..a24cf40 100644
--- a/src/components/options/ColorSelector.tsx
+++ b/src/components/options/ColorSelector.tsx
@@ -39,7 +39,7 @@ const ColorSelector: React.FC = ({
{
+ switch (values.qrCodeType) {
+ case 'URL':
+ return values.url;
+
+ case 'Text':
+ return values.text;
+
+ case 'Email': {
+ let emailData = `mailto:${values.emailAddress}`;
+ if (values.emailSubject || values.emailBody) {
+ emailData += '?';
+ if (values.emailSubject) {
+ emailData += `subject=${encodeURIComponent(values.emailSubject)}`;
+ }
+ if (values.emailBody) {
+ emailData += `${
+ values.emailSubject ? '&' : ''
+ }body=${encodeURIComponent(values.emailBody)}`;
+ }
+ }
+ return emailData;
+ }
+ case 'Phone':
+ return `tel:${values.phoneNumber}`;
+
+ case 'SMS':
+ return `sms:${values.smsNumber}${
+ values.smsMessage
+ ? `?body=${encodeURIComponent(values.smsMessage)}`
+ : ''
+ }`;
+
+ case 'WiFi': {
+ const encryption =
+ values.wifiEncryption === 'None' ? 'nopass' : values.wifiEncryption;
+ return `WIFI:T:${encryption};S:${values.wifiSsid};P:${values.wifiPassword};;`;
+ }
+ case 'vCard':
+ return `BEGIN:VCARD
+VERSION:3.0
+N:${values.vCardName}
+FN:${values.vCardName}
+ORG:${values.vCardCompany}
+TITLE:${values.vCardTitle}
+TEL:${values.vCardPhone}
+EMAIL:${values.vCardEmail}
+ADR:${values.vCardAddress}
+URL:${values.vCardWebsite}
+END:VCARD`;
+
+ default:
+ return '';
+ }
+};
+
+const validationSchema = Yup.object().shape({
+ qrCodeType: Yup.string().required('QR code type is required'),
+ size: Yup.number()
+ .min(100, 'Size must be at least 100px')
+ .max(1000, 'Size must be at most 1000px')
+ .required('Size is required'),
+ bgColor: Yup.string().required('Background color is required'),
+ fgColor: Yup.string().required('Foreground color is required'),
+
+ // URL
+ url: Yup.string().when('qrCodeType', {
+ is: 'URL',
+ then: (schema) =>
+ schema.url('Please enter a valid URL').required('URL is required')
+ }),
+
+ // Text
+ text: Yup.string().when('qrCodeType', {
+ is: 'Text',
+ then: (schema) => schema.required('Text is required')
+ }),
+
+ // Email
+ emailAddress: Yup.string().when('qrCodeType', {
+ is: 'Email',
+ then: (schema) =>
+ schema
+ .email('Please enter a valid email address')
+ .required('Email address is required')
+ }),
+
+ // Phone
+ phoneNumber: Yup.string().when('qrCodeType', {
+ is: 'Phone',
+ then: (schema) => schema.required('Phone number is required')
+ }),
+
+ // SMS
+ smsNumber: Yup.string().when('qrCodeType', {
+ is: 'SMS',
+ then: (schema) => schema.required('Phone number is required')
+ }),
+
+ // WiFi
+ wifiSsid: Yup.string().when('qrCodeType', {
+ is: 'WiFi',
+ then: (schema) => schema.required('SSID is required')
+ }),
+
+ // vCard
+ vCardName: Yup.string().when('qrCodeType', {
+ is: 'vCard',
+ then: (schema) => schema.required('Name is required')
+ })
+});
+
+export default function QRCodeGenerator({ title }: ToolComponentProps) {
+ const [result, setResult] = useState(null);
+ const getGroups: GetGroupsType = ({
+ values,
+ updateField
+ }) => {
+ return [
+ {
+ title: 'QR Code Type',
+ component: (
+
+
+ updateField('qrCodeType', e.target.value as QRCodeType)
+ }
+ label="Select QR Code Type"
+ margin="normal"
+ >
+
+
+
+
+
+
+
+
+
+ )
+ },
+ {
+ title: 'QR Code Settings',
+ component: (
+
+ updateField('size', val)}
+ description="Size in pixels (100-1000)"
+ inputProps={{
+ type: 'number',
+ min: 100,
+ max: 1000
+ }}
+ />
+ updateField('bgColor', val)}
+ />
+ updateField('fgColor', val)}
+ />
+
+ )
+ },
+ // Dynamic form fields based on QR code type
+ {
+ title: `${values.qrCodeType} Details`,
+ component: (
+
+ {values.qrCodeType === 'URL' && (
+ updateField('url', val)}
+ description="Enter the URL"
+ inputProps={{
+ placeholder: 'https://example.com'
+ }}
+ />
+ )}
+
+ {values.qrCodeType === 'Text' && (
+ updateField('text', val)}
+ description="Enter the text"
+ multiline
+ rows={4}
+ inputProps={{
+ placeholder: 'Enter your text here'
+ }}
+ />
+ )}
+
+ {values.qrCodeType === 'Email' && (
+ <>
+ updateField('emailAddress', val)}
+ description="Email Address"
+ inputProps={{
+ placeholder: 'example@example.com',
+ type: 'email'
+ }}
+ />
+ updateField('emailSubject', val)}
+ description="Email Subject (optional)"
+ inputProps={{
+ placeholder: 'Subject line'
+ }}
+ />
+ updateField('emailBody', val)}
+ description="Email Body (optional)"
+ multiline
+ rows={4}
+ inputProps={{
+ placeholder: 'Body text'
+ }}
+ />
+ >
+ )}
+
+ {values.qrCodeType === 'Phone' && (
+ updateField('phoneNumber', val)}
+ description="Phone Number"
+ inputProps={{
+ placeholder: '+1234567890',
+ type: 'tel'
+ }}
+ />
+ )}
+
+ {values.qrCodeType === 'SMS' && (
+ <>
+ updateField('smsNumber', val)}
+ description="Phone Number"
+ inputProps={{
+ placeholder: '+1234567890',
+ type: 'tel'
+ }}
+ />
+ updateField('smsMessage', val)}
+ description="Message (optional)"
+ multiline
+ rows={4}
+ inputProps={{
+ placeholder: 'Your message here'
+ }}
+ />
+ >
+ )}
+
+ {values.qrCodeType === 'WiFi' && (
+ <>
+ updateField('wifiSsid', val)}
+ description="Network Name (SSID)"
+ inputProps={{
+ placeholder: 'Network name'
+ }}
+ />
+ updateField('wifiPassword', val)}
+ description="Password"
+ inputProps={{
+ placeholder: 'Password',
+ type: 'password'
+ }}
+ />
+
+ updateField(
+ 'wifiEncryption',
+ e.target.value as WifiEncryptionType
+ )
+ }
+ label="Encryption Type"
+ margin="normal"
+ >
+
+
+
+
+ >
+ )}
+
+ {values.qrCodeType === 'vCard' && (
+ <>
+ updateField('vCardName', val)}
+ description="Full Name"
+ inputProps={{
+ placeholder: 'John Doe'
+ }}
+ />
+ updateField('vCardEmail', val)}
+ description="Email"
+ inputProps={{
+ placeholder: 'john@example.com',
+ type: 'email'
+ }}
+ />
+ updateField('vCardPhone', val)}
+ description="Phone"
+ inputProps={{
+ placeholder: '+1234567890',
+ type: 'tel'
+ }}
+ />
+ updateField('vCardAddress', val)}
+ description="Address"
+ inputProps={{
+ placeholder: '123 Main St, City, Country'
+ }}
+ />
+ updateField('vCardCompany', val)}
+ description="Company (optional)"
+ inputProps={{
+ placeholder: 'Company name'
+ }}
+ />
+ updateField('vCardTitle', val)}
+ description="Job Title (optional)"
+ inputProps={{
+ placeholder: 'Software Developer'
+ }}
+ />
+ updateField('vCardWebsite', val)}
+ description="Website (optional)"
+ inputProps={{
+ placeholder: 'https://example.com'
+ }}
+ />
+ >
+ )}
+
+ )
+ }
+ ];
+ };
+
+ const compute = async (options: InitialValuesType) => {
+ const qrValue = formatQRCodeData(options);
+ if (!qrValue) return;
+ const canvas = document.createElement('canvas');
+ QRCode.toDataURL(
+ canvas,
+ qrValue,
+ {
+ color: {
+ dark: options.fgColor,
+ light: options.bgColor
+ },
+ width: Number(options.size) || 200
+ },
+ async (error, url) => {
+ const res = await fetch(url);
+ const blob = await res.blob();
+ const file = new File([blob], 'Qr code.png', { type: 'image/png' });
+ setResult(file);
+ }
+ );
+ };
+ const debouncedCompute = useCallback(debounce(compute, 1000), []);
+
+ return (
+
+ }
+ toolInfo={{
+ title: 'QR Code Generator',
+ description:
+ 'Generate QR codes for different data types: URL, Text, Email, Phone, SMS, WiFi, vCard, and more. Customize the size and colors to create the perfect QR code for your needs.'
+ }}
+ />
+ );
+}
diff --git a/src/pages/tools/image/generic/qr-code/meta.ts b/src/pages/tools/image/generic/qr-code/meta.ts
new file mode 100644
index 0000000..302e526
--- /dev/null
+++ b/src/pages/tools/image/generic/qr-code/meta.ts
@@ -0,0 +1,25 @@
+import { defineTool } from '@tools/defineTool';
+import { lazy } from 'react';
+
+export const tool = defineTool('image-generic', {
+ name: 'QR Code Generator',
+ path: 'qr-code',
+ icon: 'mdi:qrcode', // Iconify icon as a string
+ description:
+ 'Generate QR codes for different data types: URL, Text, Email, Phone, SMS, WiFi, vCard, and more.',
+ shortDescription: 'Create customized QR codes for various data formats.',
+ keywords: [
+ 'qr code',
+ 'qrcode',
+ 'generator',
+ 'url',
+ 'text',
+ 'email',
+ 'phone',
+ 'sms',
+ 'wifi',
+ 'vcard',
+ 'contact'
+ ],
+ component: lazy(() => import('./index'))
+});
diff --git a/src/pages/tools/image/generic/qr-code/types.ts b/src/pages/tools/image/generic/qr-code/types.ts
new file mode 100644
index 0000000..c2f98be
--- /dev/null
+++ b/src/pages/tools/image/generic/qr-code/types.ts
@@ -0,0 +1,51 @@
+export type QRCodeType =
+ | 'URL'
+ | 'Text'
+ | 'Email'
+ | 'Phone'
+ | 'SMS'
+ | 'WiFi'
+ | 'vCard';
+
+export type WifiEncryptionType = 'WPA/WPA2' | 'WEP' | 'None';
+
+export interface InitialValuesType {
+ qrCodeType: QRCodeType;
+
+ // Common settings
+ size: string;
+ bgColor: string;
+ fgColor: string;
+
+ // URL
+ url: string;
+
+ // Text
+ text: string;
+
+ // Email
+ emailAddress: string;
+ emailSubject: string;
+ emailBody: string;
+
+ // Phone
+ phoneNumber: string;
+
+ // SMS
+ smsNumber: string;
+ smsMessage: string;
+
+ // WiFi
+ wifiSsid: string;
+ wifiPassword: string;
+ wifiEncryption: WifiEncryptionType;
+
+ // vCard
+ vCardName: string;
+ vCardEmail: string;
+ vCardPhone: string;
+ vCardAddress: string;
+ vCardCompany: string;
+ vCardTitle: string;
+ vCardWebsite: string;
+}