diff --git a/package-lock.json b/package-lock.json index 13491539f..3bdaa2e1d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,8 +8,10 @@ "name": "react-training", "version": "2.0.0", "dependencies": { + "bootstrap": "^5.3.3", "react": "^18.2.0", - "react-dom": "^18.2.0" + "react-dom": "^18.2.0", + "reactstrap": "^9.2.2" }, "devDependencies": { "@types/react": "^18.0.28", @@ -315,6 +317,17 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/runtime": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.25.0.tgz", + "integrity": "sha512-7dRy4DwXwtzBrPbZflqxnvfxLF8kdZXPkhymtDeFoFqE6ldzjQFgYTtYIFARcLEYDrqfBfYcZt1WqFxRoyC9Rw==", + "dependencies": { + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/template": { "version": "7.21.9", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.21.9.tgz", @@ -909,6 +922,15 @@ "node": ">= 8" } }, + "node_modules/@popperjs/core": { + "version": "2.11.8", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", + "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/popperjs" + } + }, "node_modules/@types/prop-types": { "version": "15.7.5", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", @@ -1104,6 +1126,24 @@ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true }, + "node_modules/bootstrap": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.3.3.tgz", + "integrity": "sha512-8HLCdWgyoMguSO9o+aH+iuZ+aht+mzW0u3HIMzVu7Srrpv7EBBxTnrFlSCskwdY1+EOFQSm7uMJhNQHkdPcmjg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/twbs" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/bootstrap" + } + ], + "peerDependencies": { + "@popperjs/core": "^2.11.8" + } + }, "node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -1198,6 +1238,11 @@ "node": ">=4" } }, + "node_modules/classnames": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz", + "integrity": "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==" + }, "node_modules/color-convert": { "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", @@ -1242,8 +1287,7 @@ "node_modules/csstype": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz", - "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==", - "dev": true + "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==" }, "node_modules/debug": { "version": "4.3.4", @@ -1296,6 +1340,15 @@ "node": ">=6.0.0" } }, + "node_modules/dom-helpers": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", + "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", + "dependencies": { + "@babel/runtime": "^7.8.7", + "csstype": "^3.0.2" + } + }, "node_modules/electron-to-chromium": { "version": "1.4.404", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.404.tgz", @@ -2547,7 +2600,6 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -2797,7 +2849,6 @@ "version": "15.8.1", "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", - "dev": true, "dependencies": { "loose-envify": "^1.4.0", "object-assign": "^4.1.1", @@ -2856,11 +2907,29 @@ "react": "^18.2.0" } }, + "node_modules/react-fast-compare": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.2.tgz", + "integrity": "sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ==" + }, "node_modules/react-is": { "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", - "dev": true + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + }, + "node_modules/react-popper": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/react-popper/-/react-popper-2.3.0.tgz", + "integrity": "sha512-e1hj8lL3uM+sgSR4Lxzn5h1GxBlpa4CQz0XLF8kx4MDrDRWY0Ena4c97PUeSX9i5W3UAfDP0z0FXCTQkoXUl3Q==", + "dependencies": { + "react-fast-compare": "^3.0.1", + "warning": "^4.0.2" + }, + "peerDependencies": { + "@popperjs/core": "^2.0.0", + "react": "^16.8.0 || ^17 || ^18", + "react-dom": "^16.8.0 || ^17 || ^18" + } }, "node_modules/react-refresh": { "version": "0.14.0", @@ -2871,6 +2940,43 @@ "node": ">=0.10.0" } }, + "node_modules/react-transition-group": { + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", + "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==", + "dependencies": { + "@babel/runtime": "^7.5.5", + "dom-helpers": "^5.0.1", + "loose-envify": "^1.4.0", + "prop-types": "^15.6.2" + }, + "peerDependencies": { + "react": ">=16.6.0", + "react-dom": ">=16.6.0" + } + }, + "node_modules/reactstrap": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/reactstrap/-/reactstrap-9.2.2.tgz", + "integrity": "sha512-4KroiGOdqZLAnMGzHjpErW3G7bLB+QbKzzMLIDXydPIV0y74lpdL7WtXHkLWAGInd97WCPNx4+R0NQDPyzIfhw==", + "dependencies": { + "@babel/runtime": "^7.12.5", + "@popperjs/core": "^2.6.0", + "classnames": "^2.2.3", + "prop-types": "^15.5.8", + "react-popper": "^2.2.4", + "react-transition-group": "^4.4.2" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==" + }, "node_modules/regexp.prototype.flags": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.0.tgz", @@ -3320,6 +3426,14 @@ } } }, + "node_modules/warning": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz", + "integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==", + "dependencies": { + "loose-envify": "^1.0.0" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -3617,6 +3731,14 @@ "@babel/helper-plugin-utils": "^7.19.0" } }, + "@babel/runtime": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.25.0.tgz", + "integrity": "sha512-7dRy4DwXwtzBrPbZflqxnvfxLF8kdZXPkhymtDeFoFqE6ldzjQFgYTtYIFARcLEYDrqfBfYcZt1WqFxRoyC9Rw==", + "requires": { + "regenerator-runtime": "^0.14.0" + } + }, "@babel/template": { "version": "7.21.9", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.21.9.tgz", @@ -3956,6 +4078,11 @@ "fastq": "^1.6.0" } }, + "@popperjs/core": { + "version": "2.11.8", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", + "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==" + }, "@types/prop-types": { "version": "15.7.5", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", @@ -4106,6 +4233,12 @@ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true }, + "bootstrap": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.3.3.tgz", + "integrity": "sha512-8HLCdWgyoMguSO9o+aH+iuZ+aht+mzW0u3HIMzVu7Srrpv7EBBxTnrFlSCskwdY1+EOFQSm7uMJhNQHkdPcmjg==", + "requires": {} + }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -4161,6 +4294,11 @@ "supports-color": "^5.3.0" } }, + "classnames": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz", + "integrity": "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==" + }, "color-convert": { "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", @@ -4202,8 +4340,7 @@ "csstype": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz", - "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==", - "dev": true + "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==" }, "debug": { "version": "4.3.4", @@ -4239,6 +4376,15 @@ "esutils": "^2.0.2" } }, + "dom-helpers": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", + "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", + "requires": { + "@babel/runtime": "^7.8.7", + "csstype": "^3.0.2" + } + }, "electron-to-chromium": { "version": "1.4.404", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.404.tgz", @@ -5148,8 +5294,7 @@ "object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "dev": true + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==" }, "object-inspect": { "version": "1.12.3", @@ -5319,7 +5464,6 @@ "version": "15.8.1", "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", - "dev": true, "requires": { "loose-envify": "^1.4.0", "object-assign": "^4.1.1", @@ -5355,11 +5499,24 @@ "scheduler": "^0.23.0" } }, + "react-fast-compare": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.2.tgz", + "integrity": "sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ==" + }, "react-is": { "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", - "dev": true + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + }, + "react-popper": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/react-popper/-/react-popper-2.3.0.tgz", + "integrity": "sha512-e1hj8lL3uM+sgSR4Lxzn5h1GxBlpa4CQz0XLF8kx4MDrDRWY0Ena4c97PUeSX9i5W3UAfDP0z0FXCTQkoXUl3Q==", + "requires": { + "react-fast-compare": "^3.0.1", + "warning": "^4.0.2" + } }, "react-refresh": { "version": "0.14.0", @@ -5367,6 +5524,35 @@ "integrity": "sha512-wViHqhAd8OHeLS/IRMJjTSDHF3U9eWi62F/MledQGPdJGDhodXJ9PBLNGr6WWL7qlH12Mt3TyTpbS+hGXMjCzQ==", "dev": true }, + "react-transition-group": { + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", + "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==", + "requires": { + "@babel/runtime": "^7.5.5", + "dom-helpers": "^5.0.1", + "loose-envify": "^1.4.0", + "prop-types": "^15.6.2" + } + }, + "reactstrap": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/reactstrap/-/reactstrap-9.2.2.tgz", + "integrity": "sha512-4KroiGOdqZLAnMGzHjpErW3G7bLB+QbKzzMLIDXydPIV0y74lpdL7WtXHkLWAGInd97WCPNx4+R0NQDPyzIfhw==", + "requires": { + "@babel/runtime": "^7.12.5", + "@popperjs/core": "^2.6.0", + "classnames": "^2.2.3", + "prop-types": "^15.5.8", + "react-popper": "^2.2.4", + "react-transition-group": "^4.4.2" + } + }, + "regenerator-runtime": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==" + }, "regexp.prototype.flags": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.0.tgz", @@ -5645,6 +5831,14 @@ "rollup": "^3.21.0" } }, + "warning": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz", + "integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==", + "requires": { + "loose-envify": "^1.0.0" + } + }, "which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", diff --git a/package.json b/package.json index 7fd5a2d02..fe259ed61 100644 --- a/package.json +++ b/package.json @@ -10,8 +10,10 @@ "preview": "vite preview" }, "dependencies": { + "bootstrap": "^5.3.3", "react": "^18.2.0", - "react-dom": "^18.2.0" + "react-dom": "^18.2.0", + "reactstrap": "^9.2.2" }, "devDependencies": { "@types/react": "^18.0.28", diff --git a/src/App.css b/src/App.css index 74b5e0534..54595a715 100644 --- a/src/App.css +++ b/src/App.css @@ -36,3 +36,179 @@ transform: rotate(360deg); } } + +.IdCard { + border: 1px solid black; + padding: 10px; + display: flex; + align-items: flex-start; + margin: 10px; +} + +.IdCard__ImageContainer { + margin-right: 15px; +} + +.IdCard__ImageContainer img { + max-width: 150px; + height: auto; + border-radius: 5px; +} + +.IdCard__InfoContainer { + display: flex; + flex-direction: column; + justify-content: flex-start; + align-items: flex-start; +} + +.IdCard__InfoContainer p { + margin: 2px 0; + line-height: 1.2; +} + +.Greetings { + border: 1px solid black; + font-size: large; + margin: 10px; + padding: 10px; + text-align: left; +} + +.Random { + border: 1px solid black; + font-size: large; + margin: 10px; + padding: 10px; + text-align: left; +} + +.BoxColor { + border: 1px solid black; + font-size: large; + margin: 10px; + text-align: center; +} + +.CreditCard { + width: 320px; + height: 200px; + border-radius: 15px; + padding: 20px; + display: flex; + flex-direction: column; + justify-content: space-between; + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); + color: white; + background-color: #222; + font-family: "Arial", sans-serif; + margin: 10px; +} + +.CreditCard_CardLogo { + display: flex; + justify-content: flex-end; +} + +.CreditCard_CardLogo img { + width: 60px; +} + +.CreditCard_CardNumber { + font-size: 24px; + letter-spacing: 2px; + text-align: center; +} + +.CreditCard_ExpirationBank { + display: flex; + justify-content: space-between; + font-size: 14px; +} + +.CreditCard_Owner { + margin-top: 10px; + font-size: 16px; + font-weight: bold; + text-align: right; +} + +.Rating { + font-size: 36px; + letter-spacing: 2px; + text-align: left; + margin: 10px; +} + +.DriverCard { + display: flex; + align-items: center; + justify-content: center; + background-color: #471fcd; /* Purple/blue background */ + color: white; /* White text color */ + padding: 20px; + border-radius: 10px; + width: 100%; + margin: 10px; +} + +.DriverCard_ProfilePic { + flex-shrink: 0; + width: 100px; + height: 100px; + border-radius: 50%; + overflow: hidden; + display: flex; + align-items: center; + justify-content: center; +} + +.DriverCard_ProfilePic img { + width: 100%; + height: auto; + display: block; +} + +.DriverCard_DriverInfo { + display: flex; + flex-direction: column; + align-items: flex-start; + justify-content: center; + margin-left: 20px; +} + +.DriverCard_DriverInfo p { + margin: 5px 0; +} + +.DriverCard_DriverInfo strong { + font-size: 1.5em; /* Larger font size for name */ +} + +.DriverCard_DriverInfo .Rating { + font-size: 1.2em; /* Larger font size for rating */ +} + +.NumbersTable { + display: grid; + grid-template-columns: repeat( + auto-fill, + minmax(50px, 1fr) + ); /* Adjust 50px to control item size */ + gap: 0; /* No spacing between grid items */ + color: #000; + width: 50%; + margin: 10px auto; +} + +.NumbersTable_NumberContainer { + display: flex; + justify-content: center; + align-items: center; + height: 50px; /* Adjust height as needed */ + font-weight: bold; + padding: 10px; /* Adjust padding as needed */ + box-sizing: border-box; + border: 1px solid #000; /* Optional: Add borders to separate items */ + color: #000; +} diff --git a/src/App.jsx b/src/App.jsx index 98d0f49aa..92d4c8f8a 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -1,9 +1,120 @@ import "./App.css"; +import IdCard from "./components/IdCard"; +import Greetings from "./components/Greetings"; +import Random from "./components/Random"; +import BoxColor from "./components/BoxColor"; +import CreditCard from "./components/creditCard"; +import Rating from "./components/Rating"; +import DriverCard from "./components/DriverCard"; +import LikeButton from "./components/LikeButton"; +import maxence from "./assets/images/maxence.png"; +import maxenceGlasses from "./assets/images/maxence-glasses.png"; +import ClickablePicture from "./components/ClickablePicture"; +import Dice from "./components/Dice"; +import Carousel from "./components/Carousel"; +import NumbersTable from "./components/NumbersTable"; +import FaceBook from "./components/FaceBook"; +import SignupPage from "./components/SignupPage"; +import RGBColorPicker from "./components/RGBColorPicker"; function App() { return (

LAB | React Training

+ + + Ludwig + François + + + + + + + + + + 0 + 1.49 + 1.5 + 3 + 4 + 5 + + + + + + + + + + +
); } diff --git a/src/assets/images/maxence-glasses.png b/src/assets/images/maxence-glasses.png new file mode 100644 index 000000000..612689875 Binary files /dev/null and b/src/assets/images/maxence-glasses.png differ diff --git a/src/assets/images/maxence.png b/src/assets/images/maxence.png new file mode 100644 index 000000000..4b23b64b7 Binary files /dev/null and b/src/assets/images/maxence.png differ diff --git a/src/components/BoxColor.jsx b/src/components/BoxColor.jsx new file mode 100644 index 000000000..1d28e773a --- /dev/null +++ b/src/components/BoxColor.jsx @@ -0,0 +1,21 @@ +function BoxColor({ r, g, b }) { + function componentToHex(c) { + var hex = c.toString(16); + return hex.length == 1 ? "0" + hex : hex; + } + + function rgbToHex(r, g, b) { + return "#" + componentToHex(r) + componentToHex(g) + componentToHex(b); + } + let hexColor = rgbToHex(r, g, b); + return ( +
+

+ rgb({r},{g},{b}) +

+

{hexColor}

+
+ ); +} + +export default BoxColor; diff --git a/src/components/Carousel.jsx b/src/components/Carousel.jsx new file mode 100644 index 000000000..88674c140 --- /dev/null +++ b/src/components/Carousel.jsx @@ -0,0 +1,26 @@ +import { useState } from "react"; + +function Carousel({ images }) { + const [imageNumber, setImageNumber] = useState(0); + const handleLeftClick = () => { + let imageNumberInt = Number(imageNumber); + if (imageNumberInt == 0) { + setImageNumber(images.length - 1); + } else { + setImageNumber((imageNumberInt - 1) % images.length); + } + }; + const handleRightClick = () => { + let imageNumberInt = Number(imageNumber); + setImageNumber((imageNumberInt + 1) % images.length); + }; + return ( +
+ + + +
+ ); +} + +export default Carousel; diff --git a/src/components/ClickablePicture.jsx b/src/components/ClickablePicture.jsx new file mode 100644 index 000000000..cbd762fa1 --- /dev/null +++ b/src/components/ClickablePicture.jsx @@ -0,0 +1,19 @@ +import { useState } from "react"; + +function ClickablePicture({ img, imgClicked }) { + const [profilePic, setProfilePic] = useState(); + const handleImageClick = () => { + if (profilePic == img) { + setProfilePic(imgClicked); + } else { + setProfilePic(img); + } + }; + return ( +
+ +
+ ); +} + +export default ClickablePicture; diff --git a/src/components/CreditCard.jsx b/src/components/CreditCard.jsx new file mode 100644 index 000000000..572e06bd6 --- /dev/null +++ b/src/components/CreditCard.jsx @@ -0,0 +1,49 @@ +import visaLogo from "../assets/images/visa.png"; +import masterCardLogo from "../assets/images/master-card.svg"; + +function CreditCard({ + type, + number, + expirationMonth, + expirationYear, + bank, + owner, + bgColor, + color, +}) { + let cardLogo; + if (type == "Master Card") { + cardLogo = masterCardLogo; + } else { + cardLogo = visaLogo; + } + let month = String(expirationMonth); + month = month.length == 1 ? "0" + month : month; + + return ( +
+
+ +
+
+

•••• •••• •••• {number.slice(-4)}

+
+
+
+

+ Expires {month}/{expirationYear} +

+

{bank}

+
+
+

{owner}

+
+
+
+ ); +} + +export default CreditCard; diff --git a/src/components/Dice.jsx b/src/components/Dice.jsx new file mode 100644 index 000000000..e2f929a63 --- /dev/null +++ b/src/components/Dice.jsx @@ -0,0 +1,33 @@ +import emptyDice from "../assets/images/dice-empty.png"; +import dice1 from "../assets/images/dice1.png"; +import dice2 from "../assets/images/dice2.png"; +import dice3 from "../assets/images/dice3.png"; +import dice4 from "../assets/images/dice4.png"; +import dice5 from "../assets/images/dice5.png"; +import dice6 from "../assets/images/dice6.png"; +import { useState } from "react"; + +const allDices = [dice1, dice2, dice3, dice4, dice5, dice6]; + +function Dice() { + let initialRandomValue = Math.floor(Math.random() * allDices.length); + const [diceImage, setDiceImage] = useState(allDices[initialRandomValue]); + + const handleOnClickDice = () => { + setDiceImage(emptyDice); + setTimeout(() => { + let randomValue = 1 + Math.floor(Math.random() * 6); + setDiceImage(allDices[randomValue]); + }, 1000); + }; + + console.log(diceImage); + + return ( +
+ +
+ ); +} + +export default Dice; diff --git a/src/components/DriverCard.jsx b/src/components/DriverCard.jsx new file mode 100644 index 000000000..900c417e3 --- /dev/null +++ b/src/components/DriverCard.jsx @@ -0,0 +1,22 @@ +import Rating from "./Rating"; + +function DriverCard({ name, rating, img, car }) { + return ( +
+
+ +
+
+

+ {name} +

+ {rating} +

+ {car.model} - {car.licensePlate} +

+
+
+ ); +} + +export default DriverCard; diff --git a/src/components/FaceBook.jsx b/src/components/FaceBook.jsx new file mode 100644 index 000000000..acbcbcd59 --- /dev/null +++ b/src/components/FaceBook.jsx @@ -0,0 +1,60 @@ +import profiles from "../data/berlin.json"; +import { useState } from "react"; + +function FaceBook() { + const allCountries = [ + "All", + ...profiles + .map((profile) => profile.country) + .filter((value, index, array) => { + return array.indexOf(value) === index; + }), + ]; + + const [selectedCountry, setSelectedCountry] = useState(allCountries[0]); + + const handleClickButton = (e) => { + setSelectedCountry(e.target.value); + }; + + return ( +
+
+ {allCountries.map((country, index) => ( + + ))} +
+
+ {profiles.map((profile, index) => ( +
+
+ +
+
+

+ First name: + {profile.firstName} +

+

+ Last name: + {profile.lastName} +

+

+ Country: + {profile.country} +

+

+ Type + {profile.isStudent ? "Student" : "Teacher"} +

+
+
+ ))} +
+
+ ); +} + +export default FaceBook; diff --git a/src/components/Greetings.jsx b/src/components/Greetings.jsx new file mode 100644 index 000000000..2fd3dbf47 --- /dev/null +++ b/src/components/Greetings.jsx @@ -0,0 +1,21 @@ +function Greetings({lang, children}){ + let greeting; + + if (lang === "de") { + greeting = "Hallo "; + } else if (lang === "es") { + greeting = "Hola "; + } else if (lang === "fr") { + greeting = "Bonjour "; + } else { + greeting = "Hello "; + } + return ( +
+

{greeting} {children}

+ +
+ ) +} + +export default Greetings; \ No newline at end of file diff --git a/src/components/IdCard.jsx b/src/components/IdCard.jsx new file mode 100644 index 000000000..16169b42c --- /dev/null +++ b/src/components/IdCard.jsx @@ -0,0 +1,18 @@ +function IdCard({lastName, firstName, gender, height, birth, picture}){ + return ( +
+
+ +
+
+

First name: {firstName}

+

Last name: {lastName}

+

Gender: {gender}

+

Height {height}

+

Birth: {birth.toDateString()}

+
+
+ ) +} + +export default IdCard; diff --git a/src/components/LikeButton.jsx b/src/components/LikeButton.jsx new file mode 100644 index 000000000..bbadd276a --- /dev/null +++ b/src/components/LikeButton.jsx @@ -0,0 +1,26 @@ +import { useState } from "react"; + +const availableColors = ["purple", "blue", "green", "yellow", "orange", "red"]; + +function LikeButton() { + const [likesNumber, setLikesNumber] = useState(0); + const [buttonColor, setButtonColor] = useState(availableColors[0]); + + const handleButtonIncrement = () => { + let numericLikesNumber = Number(likesNumber); + setLikesNumber(numericLikesNumber + 1); + if (numericLikesNumber + 1 < availableColors.length) { + setButtonColor(availableColors[numericLikesNumber + 1]); + } + }; + return ( + + ); +} + +export default LikeButton; diff --git a/src/components/NumbersTable.jsx b/src/components/NumbersTable.jsx new file mode 100644 index 000000000..59e48c263 --- /dev/null +++ b/src/components/NumbersTable.jsx @@ -0,0 +1,18 @@ +function NumbersTable({ limit }) { + const range = [...Array(limit).keys()].map((num) => num + 1); // Adjusted to start from 1 instead of 0 + return ( +
+ {range.map((number) => ( +
+

{number}

+
+ ))} +
+ ); +} + +export default NumbersTable; diff --git a/src/components/RGBColorPicker.jsx b/src/components/RGBColorPicker.jsx new file mode 100644 index 000000000..b87e39eda --- /dev/null +++ b/src/components/RGBColorPicker.jsx @@ -0,0 +1,47 @@ +import { useState } from "react"; +import SingleColorPicker from "./SingleColorPicker"; + +function RGBColorPicker() { + const [rValue, setRValue] = useState(0); + const [gValue, setGValue] = useState(0); + const [bValue, setBValue] = useState(0); + + return ( +
+ setRValue(e.target.value)} + /> + setGValue(e.target.value)} + /> + setBValue(e.target.value)} + /> +
+

+ {`rgb(${rValue}, ${gValue}, ${bValue})`} +

+
+
+ ); +} + +export default RGBColorPicker; diff --git a/src/components/Random.jsx b/src/components/Random.jsx new file mode 100644 index 000000000..3197011ab --- /dev/null +++ b/src/components/Random.jsx @@ -0,0 +1,12 @@ +function Random({ min, max }) { + let randomValue = min + Math.floor(Math.random() * (max + 1 - min)); + return ( +
+

+ Random value between {min} and {max} => {randomValue} +

+
+ ); +} + +export default Random; diff --git a/src/components/Rating.jsx b/src/components/Rating.jsx new file mode 100644 index 000000000..c1b4d01bf --- /dev/null +++ b/src/components/Rating.jsx @@ -0,0 +1,10 @@ +function Rating({ children }) { + let ratingRounded = Math.round(children); + return ( +
+

{"★".repeat(ratingRounded) + "☆".repeat(5 - ratingRounded)}

+
+ ); +} + +export default Rating; diff --git a/src/components/SignupPage.jsx b/src/components/SignupPage.jsx new file mode 100644 index 000000000..6203ca003 --- /dev/null +++ b/src/components/SignupPage.jsx @@ -0,0 +1,101 @@ +import { Button, Form, FormGroup, Label, Input } from "reactstrap"; +import { useState } from "react"; + +function SignupPage() { + const [email, setEmail] = useState(""); + const [password, setPassword] = useState(""); + const [nationality, setNationality] = useState(""); + const [isValidEmail, setIsValidEmail] = useState(false); + const [isStrongPassword, setIsStrongPassword] = useState(false); + + const handleFormSubmission = (e) => { + e.preventDefault(); + // Handle form submission logic here + console.log({ email, password, nationality }); + setEmail(""); + setPassword(""); + setNationality(""); + }; + + const handleEmail = (e) => { + const emailValue = e.target.value; + setEmail(emailValue); + setIsValidEmail( + String(emailValue) + .toLowerCase() + .match( + /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|.(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/ + ) + ); + }; + + const handlePassword = (e) => { + const passwordValue = e.target.value; + setPassword(passwordValue); + setIsStrongPassword(passwordValue.length >= 8 && /[A-Z]/.test(passwordValue) && /\d/.test(passwordValue)); + }; + + return ( +
+ + + + + + + + + + + + + setNationality(e.target.value)} + value={nationality} + > + + + + + + + + +
+ {nationality === "en" &&

Hello

} + {nationality === "de" &&

Hallo

} + {nationality === "fr" &&

Bonjour

} +

Your email address is: {email}

+

+ Your email address is {isValidEmail ? "correct" : "incorrect"} +

+

+ Your password is {isStrongPassword ? "strong" : "weak"} +

+
+ ); +} + +export default SignupPage; diff --git a/src/components/SingleColorPicker.jsx b/src/components/SingleColorPicker.jsx new file mode 100644 index 000000000..eabee4a12 --- /dev/null +++ b/src/components/SingleColorPicker.jsx @@ -0,0 +1,44 @@ +function SingleColorPicker({ color, value, onChange }) { + let backgroundColor; + if (color === "r") { + backgroundColor = "red"; + } else if (color === "g") { + backgroundColor = "green"; + } else { + backgroundColor = "blue"; + } + + return ( +
+
+ +
+ ); + } + + export default SingleColorPicker; + \ No newline at end of file diff --git a/src/main.jsx b/src/main.jsx index 4046932ac..d7e436d5f 100644 --- a/src/main.jsx +++ b/src/main.jsx @@ -2,6 +2,7 @@ import React from 'react'; import ReactDOM from 'react-dom/client'; import './index.css'; import App from './App'; +import "bootstrap/dist/css/bootstrap.min.css"; const root = ReactDOM.createRoot(document.getElementById('root'));