mirror of
https://github.com/danielvici/tool-website.git
synced 2026-01-16 19:41:26 +00:00
files formatted; add: qrcode generator
This commit is contained in:
7
.prettierrc.json
Normal file
7
.prettierrc.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"singleQuote": true,
|
||||
"trailingComma": "es5",
|
||||
"printWidth": 80,
|
||||
"tabWidth": 2,
|
||||
"semi": true
|
||||
}
|
||||
314
package-lock.json
generated
314
package-lock.json
generated
@@ -15,8 +15,9 @@
|
||||
"@angular/platform-browser": "^20.3.0",
|
||||
"@angular/router": "^20.3.0",
|
||||
"@tailwindcss/postcss": "^4.1.17",
|
||||
"@vercel/speed-insights": "^1.2.0",
|
||||
"postcss": "^8.5.6",
|
||||
"prettier": "^3.6.2",
|
||||
"qrcode": "^1.5.4",
|
||||
"rxjs": "~7.8.0",
|
||||
"tailwindcss": "^4.1.17",
|
||||
"tslib": "^2.3.0",
|
||||
@@ -27,12 +28,14 @@
|
||||
"@angular/cli": "^20.3.1",
|
||||
"@angular/compiler-cli": "^20.3.0",
|
||||
"@types/jasmine": "~5.1.0",
|
||||
"@types/qrcode": "^1.5.6",
|
||||
"jasmine-core": "~5.9.0",
|
||||
"karma": "~6.4.0",
|
||||
"karma-chrome-launcher": "~3.2.0",
|
||||
"karma-coverage": "~2.2.0",
|
||||
"karma-jasmine": "~5.1.0",
|
||||
"karma-jasmine-html-reporter": "~2.1.0",
|
||||
"prettier": "^3.6.2",
|
||||
"typescript": "~5.9.2"
|
||||
}
|
||||
},
|
||||
@@ -2576,9 +2579,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@npmcli/package-json/node_modules/glob": {
|
||||
"version": "10.4.5",
|
||||
"resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz",
|
||||
"integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==",
|
||||
"version": "10.5.0",
|
||||
"resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz",
|
||||
"integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
@@ -3829,6 +3832,51 @@
|
||||
"undici-types": "~7.16.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/qrcode": {
|
||||
"version": "1.5.6",
|
||||
"resolved": "https://registry.npmjs.org/@types/qrcode/-/qrcode-1.5.6.tgz",
|
||||
"integrity": "sha512-te7NQcV2BOvdj2b1hCAHzAoMNuj65kNBMz0KBaxM6c3VGBOhU0dURQKOtH8CFNI/dsKkwlv32p26qYQTWoB5bw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@vercel/speed-insights": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@vercel/speed-insights/-/speed-insights-1.2.0.tgz",
|
||||
"integrity": "sha512-y9GVzrUJ2xmgtQlzFP2KhVRoCglwfRQgjyfY607aU0hh0Un6d0OUyrJkjuAlsV18qR4zfoFPs/BiIj9YDS6Wzw==",
|
||||
"hasInstallScript": true,
|
||||
"license": "Apache-2.0",
|
||||
"peerDependencies": {
|
||||
"@sveltejs/kit": "^1 || ^2",
|
||||
"next": ">= 13",
|
||||
"react": "^18 || ^19 || ^19.0.0-rc",
|
||||
"svelte": ">= 4",
|
||||
"vue": "^3",
|
||||
"vue-router": "^4"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@sveltejs/kit": {
|
||||
"optional": true
|
||||
},
|
||||
"next": {
|
||||
"optional": true
|
||||
},
|
||||
"react": {
|
||||
"optional": true
|
||||
},
|
||||
"svelte": {
|
||||
"optional": true
|
||||
},
|
||||
"vue": {
|
||||
"optional": true
|
||||
},
|
||||
"vue-router": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@vitejs/plugin-basic-ssl": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@vitejs/plugin-basic-ssl/-/plugin-basic-ssl-2.1.0.tgz",
|
||||
@@ -4234,9 +4282,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/cacache/node_modules/glob": {
|
||||
"version": "10.4.5",
|
||||
"resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz",
|
||||
"integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==",
|
||||
"version": "10.5.0",
|
||||
"resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz",
|
||||
"integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
@@ -4335,6 +4383,15 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"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/caniuse-lite": {
|
||||
"version": "1.0.30001754",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001754.tgz",
|
||||
@@ -4495,7 +4552,6 @@
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
||||
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"color-name": "~1.1.4"
|
||||
@@ -4508,7 +4564,6 @@
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
|
||||
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/colorette": {
|
||||
@@ -4754,6 +4809,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/depd": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
|
||||
@@ -4791,6 +4855,12 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"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/dom-serialize": {
|
||||
"version": "2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/dom-serialize/-/dom-serialize-2.2.1.tgz",
|
||||
@@ -5394,6 +5464,19 @@
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"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/flatted": {
|
||||
"version": "3.3.3",
|
||||
"resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz",
|
||||
@@ -5533,7 +5616,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,
|
||||
"license": "ISC",
|
||||
"engines": {
|
||||
"node": "6.* || 8.* || >= 10.*"
|
||||
@@ -7080,6 +7162,18 @@
|
||||
"@lmdb/lmdb-win32-x64": "3.4.2"
|
||||
}
|
||||
},
|
||||
"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/lodash": {
|
||||
"version": "4.17.21",
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
||||
@@ -8089,6 +8183,33 @@
|
||||
"license": "MIT",
|
||||
"optional": true
|
||||
},
|
||||
"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/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/p-map": {
|
||||
"version": "7.0.4",
|
||||
"resolved": "https://registry.npmjs.org/p-map/-/p-map-7.0.4.tgz",
|
||||
@@ -8102,6 +8223,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.1",
|
||||
"resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz",
|
||||
@@ -8254,6 +8384,15 @@
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/path-exists": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
|
||||
"integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/path-is-absolute": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
|
||||
@@ -8358,6 +8497,15 @@
|
||||
"node": ">=16.20.0"
|
||||
}
|
||||
},
|
||||
"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/postcss": {
|
||||
"version": "8.5.6",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz",
|
||||
@@ -8397,6 +8545,7 @@
|
||||
"version": "3.6.2",
|
||||
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.6.2.tgz",
|
||||
"integrity": "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"prettier": "bin/prettier.cjs"
|
||||
@@ -8463,6 +8612,125 @@
|
||||
"node": ">=0.9"
|
||||
}
|
||||
},
|
||||
"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/ansi-regex": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
|
||||
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"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/is-fullwidth-code-point": {
|
||||
"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==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"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/strip-ansi": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
|
||||
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ansi-regex": "^5.0.1"
|
||||
},
|
||||
"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/qs": {
|
||||
"version": "6.14.0",
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz",
|
||||
@@ -8530,7 +8798,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,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
@@ -8546,6 +8813,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/requires-port": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
|
||||
@@ -8812,6 +9085,12 @@
|
||||
"node": ">= 18"
|
||||
}
|
||||
},
|
||||
"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/setprototypeof": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
|
||||
@@ -9951,11 +10230,16 @@
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"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/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==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ansi-styles": "^4.0.0",
|
||||
@@ -10060,7 +10344,6 @@
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
|
||||
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
@@ -10070,7 +10353,6 @@
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
|
||||
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"color-convert": "^2.0.1"
|
||||
@@ -10086,14 +10368,12 @@
|
||||
"version": "8.0.0",
|
||||
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
|
||||
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/wrap-ansi/node_modules/is-fullwidth-code-point": {
|
||||
"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,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
@@ -10103,7 +10383,6 @@
|
||||
"version": "4.2.3",
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
|
||||
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"emoji-regex": "^8.0.0",
|
||||
@@ -10118,7 +10397,6 @@
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
|
||||
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ansi-regex": "^5.0.1"
|
||||
|
||||
@@ -29,8 +29,9 @@
|
||||
"@angular/platform-browser": "^20.3.0",
|
||||
"@angular/router": "^20.3.0",
|
||||
"@tailwindcss/postcss": "^4.1.17",
|
||||
"@vercel/speed-insights": "^1.2.0",
|
||||
"postcss": "^8.5.6",
|
||||
"prettier": "^3.6.2",
|
||||
"qrcode": "^1.5.4",
|
||||
"rxjs": "~7.8.0",
|
||||
"tailwindcss": "^4.1.17",
|
||||
"tslib": "^2.3.0",
|
||||
@@ -41,12 +42,14 @@
|
||||
"@angular/cli": "^20.3.1",
|
||||
"@angular/compiler-cli": "^20.3.0",
|
||||
"@types/jasmine": "~5.1.0",
|
||||
"@types/qrcode": "^1.5.6",
|
||||
"jasmine-core": "~5.9.0",
|
||||
"karma": "~6.4.0",
|
||||
"karma-chrome-launcher": "~3.2.0",
|
||||
"karma-coverage": "~2.2.0",
|
||||
"karma-jasmine": "~5.1.0",
|
||||
"karma-jasmine-html-reporter": "~2.1.0",
|
||||
"prettier": "^3.6.2",
|
||||
"typescript": "~5.9.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<app-navbar class="fixed top-0 left-0 w-screen h-16 z-[999]"></app-navbar>
|
||||
|
||||
<div class="p-8 pt-24 h-screen text-white bg-black-eerie mx-auto flex justify-center-safe" >
|
||||
<!-- pt-16 bg-black-eerie h-screen flex justify-center-safe mx-auto " -->
|
||||
<div class="p-8 pt-24 min-h-screen text-white bg-zinc-900 mx-auto flex justify-center-safe">
|
||||
<!-- pt-16 bg-black-eerie h-screen flex justify-center-safe mx-auto " -->
|
||||
<router-outlet></router-outlet>
|
||||
</div>
|
||||
|
||||
@@ -1,23 +1,28 @@
|
||||
import { Routes } from '@angular/router';
|
||||
import { Startpage } from './sites/startpage/startpage';
|
||||
import {TestIt} from './sites/test-it/test-it';
|
||||
import {GeneratorPassword} from './sites/generator/password/generator-password.component';
|
||||
import { TestIt } from './sites/test-it/test-it';
|
||||
import { GeneratorPassword } from './sites/generator/password/generator-password.component';
|
||||
import { GeneratorQrcode } from './sites/generator/qrcode/generator-qrcode';
|
||||
|
||||
export const routes: Routes = [
|
||||
{
|
||||
path:'test',
|
||||
path: 'test',
|
||||
component: TestIt,
|
||||
},
|
||||
{
|
||||
path: '',
|
||||
component: Startpage,
|
||||
},
|
||||
}, // GENERATORS
|
||||
{
|
||||
path: 'generator/password',
|
||||
component: GeneratorPassword,
|
||||
},
|
||||
{
|
||||
path: 'generator/qrcode',
|
||||
component: GeneratorQrcode,
|
||||
},
|
||||
{
|
||||
path: '**',
|
||||
redirectTo: '',
|
||||
}
|
||||
},
|
||||
];
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
@if (enabled()) {
|
||||
<div
|
||||
class="h-full
|
||||
hover:cursor-pointer flex flex-col p-6 rounded-lg border border-gray-700 bg-zinc-800 transition-colors duration-200 hover:border-blue-500"
|
||||
[routerLink]="destination()">
|
||||
class="h-full hover:cursor-pointer flex flex-col p-6 rounded-lg border border-gray-700 bg-zinc-800 transition-colors duration-200 hover:border-blue-500"
|
||||
[routerLink]="destination()"
|
||||
>
|
||||
<app-custom-title
|
||||
[text]="title()"
|
||||
[textSizeInPx]="titleSizeInPx()"
|
||||
@@ -10,6 +10,6 @@
|
||||
fontWeight="bold"
|
||||
class="mb-2"
|
||||
></app-custom-title>
|
||||
<span [ngStyle]="{'color': descriptionColor()}">{{ description() }}</span>
|
||||
<span [ngStyle]="{ color: descriptionColor() }">{{ description() }}</span>
|
||||
</div>
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Component, input } from '@angular/core';
|
||||
import { CustomTitle } from '../custom-title/custom-title';
|
||||
import {RouterLink} from '@angular/router';
|
||||
import {NgStyle} from '@angular/common';
|
||||
import { RouterLink } from '@angular/router';
|
||||
import { NgStyle } from '@angular/common';
|
||||
|
||||
@Component({
|
||||
selector: 'app-custom-card',
|
||||
@@ -10,7 +10,6 @@ import {NgStyle} from '@angular/common';
|
||||
styleUrl: './custom-card.css',
|
||||
})
|
||||
export class CustomCard {
|
||||
|
||||
title = input.required<string>();
|
||||
titleSizeInPx = input<number>(20);
|
||||
titleColor = input<string>();
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
<div>
|
||||
<div class="prose prose-invert max-w-none mb-6 text-gray-300 space-y-1">
|
||||
<p>{{descriptionText()}}</p>
|
||||
<p>{{ descriptionText() }}</p>
|
||||
@if (additionalListEnabled()) {
|
||||
<ul class="list-disc pl-6 text-gray-300 space-y-1">
|
||||
@for (item of additionalListText(); track $index) {
|
||||
<li>{{item}}</li>
|
||||
<li>{{ item }}</li>
|
||||
}
|
||||
</ul>
|
||||
}
|
||||
|
||||
@@ -8,9 +8,8 @@ describe('CustomDescription', () => {
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [CustomDescription]
|
||||
})
|
||||
.compileComponents();
|
||||
imports: [CustomDescription],
|
||||
}).compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(CustomDescription);
|
||||
component = fixture.componentInstance;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {Component, input} from '@angular/core';
|
||||
import { Component, input } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-custom-description',
|
||||
@@ -9,5 +9,5 @@ import {Component, input} from '@angular/core';
|
||||
export class CustomDescription {
|
||||
descriptionText = input.required<string>();
|
||||
additionalListEnabled = input<boolean>(false);
|
||||
additionalListText =input<string[]>();
|
||||
additionalListText = input<string[]>();
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
<a
|
||||
[ngStyle]="{
|
||||
'font-size': textSizeInPx() + 'px',
|
||||
color: textColor(),
|
||||
'font-weight': fontWeight()}"
|
||||
>{{ text() }}</a>
|
||||
'font-size': textSizeInPx() + 'px',
|
||||
color: textColor(),
|
||||
'font-weight': fontWeight(),
|
||||
}"
|
||||
>{{ text() }}</a
|
||||
>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Component, input } from '@angular/core';
|
||||
import {NgClass, NgStyle} from '@angular/common';
|
||||
import { NgClass, NgStyle } from '@angular/common';
|
||||
|
||||
@Component({
|
||||
selector: 'app-custom-title',
|
||||
@@ -11,5 +11,5 @@ export class CustomTitle {
|
||||
text = input.required<string>();
|
||||
textSizeInPx = input<number>(16);
|
||||
textColor = input<string>();
|
||||
fontWeight = input<string>("normal");
|
||||
fontWeight = input<string>('normal');
|
||||
}
|
||||
|
||||
@@ -1,62 +1,105 @@
|
||||
<div>
|
||||
<div class="mb-8">
|
||||
<app-custom-title text="Password Generator" [textSizeInPx]="36" fontWeight="bold"></app-custom-title>
|
||||
<app-custom-title
|
||||
text="Password Generator"
|
||||
[textSizeInPx]="36"
|
||||
fontWeight="bold"
|
||||
></app-custom-title>
|
||||
</div>
|
||||
<div class="bg-zinc-800 rounded-lg shadow-md p-6">
|
||||
<app-custom-description
|
||||
descriptionText="Generate secure passwords with customizable options. For maximum security, it's recommend to:"
|
||||
[additionalListEnabled]="true" [additionalListText]="[
|
||||
'Use at least 16 characters for sensitive accounts',
|
||||
'Include a mix of letters, numbers, and special characters',
|
||||
'Use different passwords for each account']"></app-custom-description>
|
||||
[additionalListEnabled]="true"
|
||||
[additionalListText]="[
|
||||
'Use at least 16 characters for sensitive accounts',
|
||||
'Include a mix of letters, numbers, and special characters',
|
||||
'Use different passwords for each account',
|
||||
]"
|
||||
></app-custom-description>
|
||||
<div>
|
||||
<div [formGroup]="passwordGenerator" class="relative mb-6">
|
||||
<div class="flex flex-col">
|
||||
<label class="mb-2">Password Length: <span class="ml-2 font-bold text-xl">{{ passwordGenerator.value.length }}</span></label>
|
||||
<input type="range" min="4" max="64" formControlName="length" class="w-full border bg-white transition-[color,box-shadow]"> <!--class="w-full mt-2 mb-4 bg-blue-500 h-2 appearance-none" -->
|
||||
<label class="mb-2"
|
||||
>Password Length:
|
||||
<span class="ml-2 font-bold text-xl">{{ passwordGenerator.value.length }}</span></label
|
||||
>
|
||||
<input
|
||||
type="range"
|
||||
min="4"
|
||||
max="64"
|
||||
formControlName="length"
|
||||
class="w-full border bg-white transition-[color,box-shadow]"
|
||||
/>
|
||||
<!--class="w-full mt-2 mb-4 bg-blue-500 h-2 appearance-none" -->
|
||||
</div>
|
||||
<div> <!-- strength description -->
|
||||
<p class="text-sm mt-2" [class]="getStrengthDescription(passwordGenerator.value.length).color">
|
||||
<div>
|
||||
<!-- strength description -->
|
||||
<p
|
||||
class="text-sm mt-2"
|
||||
[class]="getStrengthDescription(passwordGenerator.value.length).color"
|
||||
>
|
||||
@if (getStrengthDescription(passwordGenerator.value.length)) {
|
||||
{{getStrengthDescription(passwordGenerator.value.length).text}}*
|
||||
{{ getStrengthDescription(passwordGenerator.value.length).text }}*
|
||||
}
|
||||
</p>
|
||||
</div>
|
||||
<div class="flex flex-wrap gap-4 my-4">
|
||||
<!-- CHECKBOXES -->
|
||||
<div>
|
||||
<label class="flex items-center"><input type="checkbox" formControlName="includeLetters"
|
||||
class="rounded border-gray-600 bg-zinc-700 text-blue-500 mr-2 focus:ring-blue-500 focus:ring-offset-zinc-800">Letters</label>
|
||||
<label class="flex items-center"
|
||||
><input
|
||||
type="checkbox"
|
||||
formControlName="includeLetters"
|
||||
class="rounded border-gray-600 bg-zinc-700 text-blue-500 mr-2 focus:ring-blue-500 focus:ring-offset-zinc-800"
|
||||
/>Letters</label
|
||||
>
|
||||
</div>
|
||||
<div>
|
||||
<label class="flex items-center"><input type="checkbox" formControlName="includeNumbers"
|
||||
class="rounded border-gray-600 bg-zinc-700 text-blue-500 mr-2 focus:ring-blue-500 focus:ring-offset-zinc-800">Numbers</label>
|
||||
<label class="flex items-center"
|
||||
><input
|
||||
type="checkbox"
|
||||
formControlName="includeNumbers"
|
||||
class="rounded border-gray-600 bg-zinc-700 text-blue-500 mr-2 focus:ring-blue-500 focus:ring-offset-zinc-800"
|
||||
/>Numbers</label
|
||||
>
|
||||
</div>
|
||||
<div>
|
||||
<label class="flex items-center"><input type="checkbox" formControlName="includeSymbols"
|
||||
class="rounded border-gray-600 bg-zinc-700 text-blue-500 mr-2 focus:ring-blue-500 focus:ring-offset-zinc-800">Special Characters</label>
|
||||
<label class="flex items-center"
|
||||
><input
|
||||
type="checkbox"
|
||||
formControlName="includeSymbols"
|
||||
class="rounded border-gray-600 bg-zinc-700 text-blue-500 mr-2 focus:ring-blue-500 focus:ring-offset-zinc-800"
|
||||
/>Special Characters</label
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<p class="text-sm my-2">*Based on the length of the password</p>
|
||||
<div>
|
||||
<!-- SUBMIT -->
|
||||
<button (click)="generatePassword()"
|
||||
class="active:top-1 cursor-pointer w-full bg-blue-500 text-white py-2 px-4 rounded-md hover:bg-blue-600 transition-colors">Generate
|
||||
Password</button>
|
||||
<button
|
||||
(click)="generatePassword()"
|
||||
class="active:top-1 cursor-pointer w-full bg-blue-500 text-white py-2 px-4 rounded-md hover:bg-blue-600 transition-colors"
|
||||
>
|
||||
Generate Password
|
||||
</button>
|
||||
</div>
|
||||
@if (generated) {
|
||||
<div class="mt-4">
|
||||
<label class="block text-sm font-medium text-gray-300 mb-2">Generated Password:</label>
|
||||
<div class="flex">
|
||||
<div class="flex-1 bg-zinc-700 text-white rounded-l-md border border-gray-600 p-2">{{generatedPassword}}
|
||||
<div class="mt-4">
|
||||
<label class="block text-sm font-medium text-gray-300 mb-2">Generated Password:</label>
|
||||
<div class="flex">
|
||||
<div class="flex-1 bg-zinc-700 text-white rounded-l-md border border-gray-600 p-2">
|
||||
{{ generatedPassword }}
|
||||
</div>
|
||||
<button
|
||||
class="cursor-pointer bg-zinc-700 px-4 rounded-r-md border-t border-r border-b border-gray-600 text-gray-300 hover:bg-zinc-600 transition-colors"
|
||||
(click)="copyPassword()"
|
||||
>
|
||||
Copy
|
||||
</button>
|
||||
</div>
|
||||
<button
|
||||
class="cursor-pointer bg-zinc-700 px-4 rounded-r-md border-t border-r border-b border-gray-600 text-gray-300 hover:bg-zinc-600 transition-colors"
|
||||
(click)="copyPassword()">Copy</button>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -8,9 +8,8 @@ describe('Password', () => {
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [GeneratorPassword]
|
||||
})
|
||||
.compileComponents();
|
||||
imports: [GeneratorPassword],
|
||||
}).compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(GeneratorPassword);
|
||||
component = fixture.componentInstance;
|
||||
|
||||
@@ -1,34 +1,26 @@
|
||||
import { Component } from '@angular/core';
|
||||
import {CustomTitle} from '../../../components/custom-title/custom-title';
|
||||
import {FormBuilder, FormsModule, ReactiveFormsModule} from '@angular/forms';
|
||||
import {CustomDescription} from '../../../components/custom-description/custom-description';
|
||||
import { CustomTitle } from '../../../components/custom-title/custom-title';
|
||||
import { FormBuilder, FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||
import { CustomDescription } from '../../../components/custom-description/custom-description';
|
||||
|
||||
@Component({
|
||||
selector: 'app-password',
|
||||
imports: [
|
||||
CustomTitle,
|
||||
CustomDescription,
|
||||
ReactiveFormsModule,
|
||||
],
|
||||
imports: [CustomTitle, CustomDescription, ReactiveFormsModule],
|
||||
templateUrl: './generator-password.component.html',
|
||||
styleUrl: './generator-password.component.css',
|
||||
})
|
||||
export class GeneratorPassword {
|
||||
|
||||
passwordGenerator!: any;
|
||||
generatedPassword: string = '';
|
||||
generated: boolean = false;
|
||||
|
||||
|
||||
|
||||
constructor(private fb:FormBuilder) {
|
||||
|
||||
constructor(private fb: FormBuilder) {
|
||||
this.passwordGenerator = this.fb.group({
|
||||
length: [16],
|
||||
includeLetters: [true],
|
||||
includeNumbers: [true],
|
||||
includeSymbols: [true]
|
||||
})
|
||||
includeSymbols: [true],
|
||||
});
|
||||
}
|
||||
|
||||
generatePassword() {
|
||||
@@ -38,10 +30,10 @@ export class GeneratorPassword {
|
||||
let includeNumbers = this.passwordGenerator.value.includeNumbers;
|
||||
let includeSymbols = this.passwordGenerator.value.includeSymbols;
|
||||
|
||||
if(!includeLetters && !includeNumbers && !includeSymbols) {
|
||||
if (!includeLetters && !includeNumbers && !includeSymbols) {
|
||||
this.passwordGenerator.value.includeLetters = true;
|
||||
includeLetters = true;
|
||||
console.log(this.passwordGenerator.value)
|
||||
console.log(this.passwordGenerator.value);
|
||||
}
|
||||
|
||||
const uppercaseChars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
|
||||
@@ -55,7 +47,7 @@ export class GeneratorPassword {
|
||||
if (includeSymbols) allChars += symbolChars;
|
||||
|
||||
for (let i = 0; i < length; i++) {
|
||||
this.generatedPassword += allChars[Math.floor(Math.random() * allChars.length)]
|
||||
this.generatedPassword += allChars[Math.floor(Math.random() * allChars.length)];
|
||||
}
|
||||
|
||||
this.generated = true;
|
||||
@@ -66,9 +58,9 @@ export class GeneratorPassword {
|
||||
}
|
||||
|
||||
public getStrengthDescription = (len: number) => {
|
||||
if (len < 10) return { text: 'Very Weak', color: 'text-red-500' }
|
||||
if (len < 15) return { text: 'Weak', color: 'text-orange-500' }
|
||||
if (len < 20) return { text: 'Strong', color: 'text-green-500' }
|
||||
return { text: 'Very Strong', color: 'text-emerald-500' }
|
||||
}
|
||||
if (len < 10) return { text: 'Very Weak', color: 'text-red-500' };
|
||||
if (len < 15) return { text: 'Weak', color: 'text-orange-500' };
|
||||
if (len < 20) return { text: 'Strong', color: 'text-green-500' };
|
||||
return { text: 'Very Strong', color: 'text-emerald-500' };
|
||||
};
|
||||
}
|
||||
|
||||
0
src/app/sites/generator/qrcode/generator-qrcode.css
Normal file
0
src/app/sites/generator/qrcode/generator-qrcode.css
Normal file
64
src/app/sites/generator/qrcode/generator-qrcode.html
Normal file
64
src/app/sites/generator/qrcode/generator-qrcode.html
Normal file
@@ -0,0 +1,64 @@
|
||||
<div class="p-8 text-white">
|
||||
<div class="mx-auto">
|
||||
<div class="mb-8">
|
||||
<app-custom-title
|
||||
text="QR Code Generator"
|
||||
[textSizeInPx]="36"
|
||||
fontWeight="bold"
|
||||
></app-custom-title>
|
||||
</div>
|
||||
|
||||
<div class="bg-zinc-800 rounded-lg shadow-md p-6 max-w-2xl mx-auto">
|
||||
|
||||
<div>
|
||||
<app-custom-description
|
||||
descriptionText="Generate QR codes for text, URLs, or any other content. Customize the size and colors, then download the QR code as a PNG image."
|
||||
></app-custom-description>
|
||||
</div>
|
||||
|
||||
<div [formGroup]="qrCodeDetailsForm" class="space-y-6">
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-300 mb-2">Text or URL</label>
|
||||
<input type="text" placeholder="Enter text or URL" formControlName="text"
|
||||
class="w-full bg-zinc-700 text-white rounded-md border border-gray-600 p-2" />
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-300 mb-2">
|
||||
Size: {{ qrCodeDetailsForm.value.size }}x{{ qrCodeDetailsForm.value.size }} pixels
|
||||
</label>
|
||||
<input type="range" min="100" max="800" step="100" formControlName="size" class="w-full" />
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-2 gap-4">
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-300 mb-2">QR Code Color</label>
|
||||
<input type="color" formControlName="darkColor"
|
||||
class="w-full h-10 rounded-md cursor-pointer bg-zinc-700 p-1" />
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-300 mb-2">Background Color</label>
|
||||
<input type="color" formControlName="lightColor"
|
||||
class="w-full h-10 rounded-md cursor-pointer bg-zinc-700 p-1" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button type="button" (click)="generateQR()"
|
||||
class="w-full bg-blue-500 text-white py-2 px-4 rounded-md hover:bg-blue-600 transition-colors">
|
||||
Generate QR Code
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="flex justify-center mt-6 flex-col items-center space-y-4">
|
||||
<canvas #canvas class="hidden" #ziel></canvas>
|
||||
@if (qrDataUrl) {
|
||||
<img [src]="qrDataUrl" alt="Generated QR Code" class="mx-auto border-4 border-white rounded-lg max-w-[500px] max-h-[500px]" />
|
||||
<button (click)="downloadQR()"
|
||||
class="w-full bg-green-500 text-white py-2 px-4 rounded-md hover:bg-green-600 transition-colors">
|
||||
Download QR Code
|
||||
</button>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
22
src/app/sites/generator/qrcode/generator-qrcode.spec.ts
Normal file
22
src/app/sites/generator/qrcode/generator-qrcode.spec.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { GeneratorQrcode } from './generator-qrcode';
|
||||
|
||||
describe('GeneratorQrcode', () => {
|
||||
let component: GeneratorQrcode;
|
||||
let fixture: ComponentFixture<GeneratorQrcode>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [GeneratorQrcode],
|
||||
}).compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(GeneratorQrcode);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
61
src/app/sites/generator/qrcode/generator-qrcode.ts
Normal file
61
src/app/sites/generator/qrcode/generator-qrcode.ts
Normal file
@@ -0,0 +1,61 @@
|
||||
import { Component, ViewChild, ElementRef } from '@angular/core';
|
||||
import { FormBuilder, ReactiveFormsModule, Validators } from '@angular/forms';
|
||||
import QRCode from 'qrcode';
|
||||
import { CustomTitle } from "../../../components/custom-title/custom-title";
|
||||
import { CustomDescription } from "../../../components/custom-description/custom-description";
|
||||
|
||||
@Component({
|
||||
selector: 'app-generator-qrcode',
|
||||
templateUrl: './generator-qrcode.html',
|
||||
styleUrls: ['./generator-qrcode.css'],
|
||||
imports: [ReactiveFormsModule, CustomTitle, CustomDescription],
|
||||
})
|
||||
export class GeneratorQrcode {
|
||||
qrDataUrl: string | null = null;
|
||||
qrCodeDetailsForm: any;
|
||||
|
||||
@ViewChild('canvas', { static: false }) canvasRef!: ElementRef<HTMLCanvasElement>;
|
||||
|
||||
@ViewChild('ziel') zielRef!: ElementRef;
|
||||
|
||||
constructor(private fb: FormBuilder) {
|
||||
this.qrCodeDetailsForm = this.fb.group({
|
||||
text: ['', Validators.required],
|
||||
size: [300, Validators.required],
|
||||
darkColor: ['#000000', Validators.required],
|
||||
lightColor: ['#FFFFFF', Validators.required],
|
||||
});
|
||||
}
|
||||
|
||||
async generateQR(): Promise<void> {
|
||||
if (!this.qrCodeDetailsForm.valid) return;
|
||||
const canvas = this.canvasRef?.nativeElement;
|
||||
if (!canvas) return;
|
||||
|
||||
try {
|
||||
await QRCode.toCanvas(canvas, this.qrCodeDetailsForm.value.text, {
|
||||
width: this.qrCodeDetailsForm.value.size,
|
||||
margin: 2,
|
||||
color: {
|
||||
dark: this.qrCodeDetailsForm.value.darkColor,
|
||||
light: this.qrCodeDetailsForm.value.lightColor,
|
||||
},
|
||||
});
|
||||
this.qrDataUrl = canvas.toDataURL('image/png');
|
||||
this.zielRef.nativeElement.scrollIntoView({ behavior: 'smooth' });
|
||||
|
||||
} catch (err) {
|
||||
console.error('Error generating QR code:', err);
|
||||
}
|
||||
}
|
||||
|
||||
downloadQR(): void {
|
||||
if (!this.qrDataUrl) return;
|
||||
const link = document.createElement('a');
|
||||
link.download = 'qrcode.png';
|
||||
link.href = this.qrDataUrl;
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
document.body.removeChild(link);
|
||||
}
|
||||
}
|
||||
@@ -21,7 +21,13 @@
|
||||
</div>
|
||||
<div class="ml-4 grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||
@for (tool of feature.tools; track $index) {
|
||||
<app-custom-card [title]="tool.name" [description]="tool.description" descriptionColor="oklch(70.4% 0.04 256.788)" [destination]="tool.link" [enabled]="tool.enabled"></app-custom-card>
|
||||
<app-custom-card
|
||||
[title]="tool.name"
|
||||
[description]="tool.description"
|
||||
descriptionColor="oklch(70.4% 0.04 256.788)"
|
||||
[destination]="tool.link"
|
||||
[enabled]="tool.enabled"
|
||||
></app-custom-card>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -2,7 +2,7 @@ import { Component } from '@angular/core';
|
||||
import { NgOptimizedImage } from '@angular/common';
|
||||
import { CustomTitle } from '../../components/custom-title/custom-title';
|
||||
import { CustomCard } from '../../components/custom-card/custom-card';
|
||||
import {ReactiveFormsModule} from '@angular/forms';
|
||||
import { ReactiveFormsModule } from '@angular/forms';
|
||||
|
||||
@Component({
|
||||
selector: 'app-startpage',
|
||||
@@ -11,33 +11,42 @@ import {ReactiveFormsModule} from '@angular/forms';
|
||||
imports: [CustomTitle, CustomCard, ReactiveFormsModule],
|
||||
})
|
||||
export class Startpage {
|
||||
|
||||
features = [{
|
||||
name: 'Generators',
|
||||
enabled: true,
|
||||
tools: [{
|
||||
name: 'Password Generator',
|
||||
description: 'Create secure passwords with custom options',
|
||||
link: '/generator/password',
|
||||
features = [
|
||||
{
|
||||
name: 'Generators',
|
||||
enabled: true,
|
||||
}, {
|
||||
name: 'QR Code Generator',
|
||||
description: 'Generate and download QR codes for any text or URL',
|
||||
link: '/generator/qr',
|
||||
tools: [
|
||||
{
|
||||
name: 'Password Generator',
|
||||
description: 'Create secure passwords with custom options',
|
||||
link: '/generator/password',
|
||||
enabled: true,
|
||||
},
|
||||
{
|
||||
name: 'QR Code Generator',
|
||||
description: 'Generate and download QR codes for any text or URL',
|
||||
link: '/generator/qrcode',
|
||||
enabled: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'Tests',
|
||||
enabled: true,
|
||||
}]}, {
|
||||
name: 'Tests',
|
||||
enabled: true,
|
||||
tools: [{
|
||||
name: 'Test 1',
|
||||
description: 'This is a just test description.',
|
||||
link: '/test',
|
||||
enabled: true,
|
||||
},{
|
||||
name: 'Test 2',
|
||||
description: 'This is a just test description.',
|
||||
link: '/test',
|
||||
enabled: false,
|
||||
}]
|
||||
}];
|
||||
tools: [
|
||||
{
|
||||
name: 'Test 1',
|
||||
description: 'This is a just test description.',
|
||||
link: '/test',
|
||||
enabled: true,
|
||||
},
|
||||
{
|
||||
name: 'Test 2',
|
||||
description: 'This is a just test description.',
|
||||
link: '/test',
|
||||
enabled: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
<button
|
||||
class="text-xl w-fit bg-blue-500 text-white py-2 px-4 rounded-md hover:bg-blue-600 transition-colors hover:cursor-pointer"
|
||||
routerLink="/"
|
||||
>Home</button>
|
||||
>
|
||||
Home
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -8,9 +8,8 @@ describe('TestIt', () => {
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [TestIt]
|
||||
})
|
||||
.compileComponents();
|
||||
imports: [TestIt],
|
||||
}).compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(TestIt);
|
||||
component = fixture.componentInstance;
|
||||
|
||||
@@ -1,14 +1,10 @@
|
||||
import { Component } from '@angular/core';
|
||||
import {RouterLink} from '@angular/router';
|
||||
import { RouterLink } from '@angular/router';
|
||||
|
||||
@Component({
|
||||
selector: 'app-test-it',
|
||||
imports: [
|
||||
RouterLink
|
||||
],
|
||||
imports: [RouterLink],
|
||||
templateUrl: './test-it.html',
|
||||
styleUrl: './test-it.css',
|
||||
})
|
||||
export class TestIt {
|
||||
|
||||
}
|
||||
export class TestIt {}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>ToolsWebsite</title>
|
||||
<title>Tools Website</title>
|
||||
<base href="/" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<link rel="icon" type="image/x-icon" href="app/assets/logo.ico" />
|
||||
|
||||
Reference in New Issue
Block a user