diff --git a/package-lock.json b/package-lock.json index cc2db5b..78e4175 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,17 +8,24 @@ "name": "test-components", "version": "0.1.0", "dependencies": { + "classnames": "^2.5.1", + "lru-cache": "^11.2.7", "next": "16.1.6", + "rate-limiter-flexible": "^10.0.1", "react": "19.2.3", - "react-dom": "19.2.3" + "react-dom": "19.2.3", + "sass": "^1.98.0" }, "devDependencies": { + "@faker-js/faker": "^10.3.0", "@types/node": "^20", + "@types/prismjs": "^1.26.6", "@types/react": "^19", "@types/react-dom": "^19", "babel-plugin-react-compiler": "1.0.0", "eslint": "^9", "eslint-config-next": "16.1.6", + "prismjs": "^1.30.0", "typescript": "^5" } }, @@ -112,6 +119,16 @@ "node": ">=6.9.0" } }, + "node_modules/@babel/helper-compilation-targets/node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, "node_modules/@babel/helper-globals": { "version": "7.28.0", "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", @@ -439,6 +456,23 @@ "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, + "node_modules/@faker-js/faker": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/@faker-js/faker/-/faker-10.4.0.tgz", + "integrity": "sha512-sDBWI3yLy8EcDzgobvJTWq1MJYzAkQdpjXuPukga9wXonhpMRvd1Izuo2Qgwey2OiEoRIBr35RMU9HJRoOHzpw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/fakerjs" + } + ], + "license": "MIT", + "engines": { + "node": "^20.19.0 || ^22.13.0 || ^23.5.0 || >=24.0.0", + "npm": ">=10" + } + }, "node_modules/@humanfs/core": { "version": "0.19.1", "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", @@ -1212,6 +1246,315 @@ "node": ">=12.4.0" } }, + "node_modules/@parcel/watcher": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.6.tgz", + "integrity": "sha512-tmmZ3lQxAe/k/+rNnXQRawJ4NjxO2hqiOLTHvWchtGZULp4RyFeh6aU4XdOYBFe2KE1oShQTv4AblOs2iOrNnQ==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "dependencies": { + "detect-libc": "^2.0.3", + "is-glob": "^4.0.3", + "node-addon-api": "^7.0.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "@parcel/watcher-android-arm64": "2.5.6", + "@parcel/watcher-darwin-arm64": "2.5.6", + "@parcel/watcher-darwin-x64": "2.5.6", + "@parcel/watcher-freebsd-x64": "2.5.6", + "@parcel/watcher-linux-arm-glibc": "2.5.6", + "@parcel/watcher-linux-arm-musl": "2.5.6", + "@parcel/watcher-linux-arm64-glibc": "2.5.6", + "@parcel/watcher-linux-arm64-musl": "2.5.6", + "@parcel/watcher-linux-x64-glibc": "2.5.6", + "@parcel/watcher-linux-x64-musl": "2.5.6", + "@parcel/watcher-win32-arm64": "2.5.6", + "@parcel/watcher-win32-ia32": "2.5.6", + "@parcel/watcher-win32-x64": "2.5.6" + } + }, + "node_modules/@parcel/watcher-android-arm64": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.6.tgz", + "integrity": "sha512-YQxSS34tPF/6ZG7r/Ih9xy+kP/WwediEUsqmtf0cuCV5TPPKw/PQHRhueUo6JdeFJaqV3pyjm0GdYjZotbRt/A==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-darwin-arm64": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.6.tgz", + "integrity": "sha512-Z2ZdrnwyXvvvdtRHLmM4knydIdU9adO3D4n/0cVipF3rRiwP+3/sfzpAwA/qKFL6i1ModaabkU7IbpeMBgiVEA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-darwin-x64": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.6.tgz", + "integrity": "sha512-HgvOf3W9dhithcwOWX9uDZyn1lW9R+7tPZ4sug+NGrGIo4Rk1hAXLEbcH1TQSqxts0NYXXlOWqVpvS1SFS4fRg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-freebsd-x64": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.6.tgz", + "integrity": "sha512-vJVi8yd/qzJxEKHkeemh7w3YAn6RJCtYlE4HPMoVnCpIXEzSrxErBW5SJBgKLbXU3WdIpkjBTeUNtyBVn8TRng==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm-glibc": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.6.tgz", + "integrity": "sha512-9JiYfB6h6BgV50CCfasfLf/uvOcJskMSwcdH1PHH9rvS1IrNy8zad6IUVPVUfmXr+u+Km9IxcfMLzgdOudz9EQ==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm-musl": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.6.tgz", + "integrity": "sha512-Ve3gUCG57nuUUSyjBq/MAM0CzArtuIOxsBdQ+ftz6ho8n7s1i9E1Nmk/xmP323r2YL0SONs1EuwqBp2u1k5fxg==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm64-glibc": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.6.tgz", + "integrity": "sha512-f2g/DT3NhGPdBmMWYoxixqYr3v/UXcmLOYy16Bx0TM20Tchduwr4EaCbmxh1321TABqPGDpS8D/ggOTaljijOA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm64-musl": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.6.tgz", + "integrity": "sha512-qb6naMDGlbCwdhLj6hgoVKJl2odL34z2sqkC7Z6kzir8b5W65WYDpLB6R06KabvZdgoHI/zxke4b3zR0wAbDTA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-x64-glibc": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.6.tgz", + "integrity": "sha512-kbT5wvNQlx7NaGjzPFu8nVIW1rWqV780O7ZtkjuWaPUgpv2NMFpjYERVi0UYj1msZNyCzGlaCWEtzc+exjMGbQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-x64-musl": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.6.tgz", + "integrity": "sha512-1JRFeC+h7RdXwldHzTsmdtYR/Ku8SylLgTU/reMuqdVD7CtLwf0VR1FqeprZ0eHQkO0vqsbvFLXUmYm/uNKJBg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-arm64": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.6.tgz", + "integrity": "sha512-3ukyebjc6eGlw9yRt678DxVF7rjXatWiHvTXqphZLvo7aC5NdEgFufVwjFfY51ijYEWpXbqF5jtrK275z52D4Q==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-ia32": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.6.tgz", + "integrity": "sha512-k35yLp1ZMwwee3Ez/pxBi5cf4AoBKYXj00CZ80jUz5h8prpiaQsiRPKQMxoLstNuqe2vR4RNPEAEcjEFzhEz/g==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-x64": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.6.tgz", + "integrity": "sha512-hbQlYcCq5dlAX9Qx+kFb0FHue6vbjlf0FrNzSKdYK2APUf7tGfGxQCk2ihEREmbR6ZMc0MVAD5RIX/41gpUzTw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher/node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/@rtsao/scc": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz", @@ -1270,6 +1613,13 @@ "undici-types": "~6.21.0" } }, + "node_modules/@types/prismjs": { + "version": "1.26.6", + "resolved": "https://registry.npmjs.org/@types/prismjs/-/prismjs-1.26.6.tgz", + "integrity": "sha512-vqlvI7qlMvcCBbVe0AKAb4f97//Hy0EBTaiW8AalRnG/xAN5zOiWWyrNqNXeq8+KAuvRewjCVY1+IPxk4RdNYw==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/react": { "version": "19.2.14", "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.14.tgz", @@ -2324,6 +2674,27 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "license": "MIT", + "dependencies": { + "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "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==", + "license": "MIT" + }, "node_modules/client-only": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", @@ -3640,6 +4011,12 @@ "node": ">= 4" } }, + "node_modules/immutable": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.5.tgz", + "integrity": "sha512-t7xcm2siw+hlUM68I+UEOK+z84RzmN59as9DZ7P1l0994DKUWV7UXBMQZVxaoMSRQ+PBZbHCOoBt7a2wxOMt+A==", + "license": "MIT" + }, "node_modules/import-fresh": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", @@ -3844,7 +4221,7 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -3890,7 +4267,7 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "is-extglob": "^2.1.1" @@ -4293,13 +4670,12 @@ } }, "node_modules/lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^3.0.2" + "version": "11.2.7", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.7.tgz", + "integrity": "sha512-aY/R+aEsRelme17KGQa/1ZSIpLpNYYrhcrepKTZgE+W3WM16YMCaPwOHLHsmopZHELU0Ojin1lPVxKR0MihncA==", + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" } }, "node_modules/math-intrinsics": { @@ -4460,6 +4836,13 @@ } } }, + "node_modules/node-addon-api": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", + "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", + "license": "MIT", + "optional": true + }, "node_modules/node-exports-info": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/node-exports-info/-/node-exports-info-1.6.0.tgz", @@ -4784,6 +5167,16 @@ "node": ">= 0.8.0" } }, + "node_modules/prismjs": { + "version": "1.30.0", + "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.30.0.tgz", + "integrity": "sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/prop-types": { "version": "15.8.1", "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", @@ -4827,6 +5220,12 @@ ], "license": "MIT" }, + "node_modules/rate-limiter-flexible": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/rate-limiter-flexible/-/rate-limiter-flexible-10.0.1.tgz", + "integrity": "sha512-3G6GMFz5Oz5nVnDv9gQ1LLMdExR4B1lOjogPIjehtgyxPMIkY09BGyk2eCYt36/OkV/0t12GEt6J6HpTl6RzZg==", + "license": "ISC" + }, "node_modules/react": { "version": "19.2.3", "resolved": "https://registry.npmjs.org/react/-/react-19.2.3.tgz", @@ -4855,6 +5254,19 @@ "dev": true, "license": "MIT" }, + "node_modules/readdirp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "license": "MIT", + "engines": { + "node": ">= 14.18.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/reflect.getprototypeof": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz", @@ -5030,6 +5442,26 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/sass": { + "version": "1.98.0", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.98.0.tgz", + "integrity": "sha512-+4N/u9dZ4PrgzGgPlKnaaRQx64RO0JBKs9sDhQ2pLgN6JQZ25uPQZKQYaBJU48Kd5BxgXoJ4e09Dq7nMcOUW3A==", + "license": "MIT", + "dependencies": { + "chokidar": "^4.0.0", + "immutable": "^5.1.5", + "source-map-js": ">=0.6.2 <2.0.0" + }, + "bin": { + "sass": "sass.js" + }, + "engines": { + "node": ">=14.0.0" + }, + "optionalDependencies": { + "@parcel/watcher": "^2.4.1" + } + }, "node_modules/scheduler": { "version": "0.27.0", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", diff --git a/package.json b/package.json index f9aa143..5a86b17 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,9 @@ }, "dependencies": { "classnames": "^2.5.1", + "lru-cache": "^11.2.7", "next": "16.1.6", + "rate-limiter-flexible": "^10.0.1", "react": "19.2.3", "react-dom": "19.2.3", "sass": "^1.98.0" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 7dfb337..95dd817 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -11,9 +11,15 @@ importers: classnames: specifier: ^2.5.1 version: 2.5.1 + lru-cache: + specifier: ^11.2.7 + version: 11.2.7 next: specifier: 16.1.6 version: 16.1.6(@babel/core@7.29.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(sass@1.98.0) + rate-limiter-flexible: + specifier: ^10.0.1 + version: 10.0.1 react: specifier: 19.2.3 version: 19.2.3 @@ -221,105 +227,89 @@ packages: resolution: {integrity: sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==} cpu: [arm64] os: [linux] - libc: [glibc] '@img/sharp-libvips-linux-arm@1.2.4': resolution: {integrity: sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==} cpu: [arm] os: [linux] - libc: [glibc] '@img/sharp-libvips-linux-ppc64@1.2.4': resolution: {integrity: sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==} cpu: [ppc64] os: [linux] - libc: [glibc] '@img/sharp-libvips-linux-riscv64@1.2.4': resolution: {integrity: sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==} cpu: [riscv64] os: [linux] - libc: [glibc] '@img/sharp-libvips-linux-s390x@1.2.4': resolution: {integrity: sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==} cpu: [s390x] os: [linux] - libc: [glibc] '@img/sharp-libvips-linux-x64@1.2.4': resolution: {integrity: sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==} cpu: [x64] os: [linux] - libc: [glibc] '@img/sharp-libvips-linuxmusl-arm64@1.2.4': resolution: {integrity: sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==} cpu: [arm64] os: [linux] - libc: [musl] '@img/sharp-libvips-linuxmusl-x64@1.2.4': resolution: {integrity: sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==} cpu: [x64] os: [linux] - libc: [musl] '@img/sharp-linux-arm64@0.34.5': resolution: {integrity: sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [linux] - libc: [glibc] '@img/sharp-linux-arm@0.34.5': resolution: {integrity: sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm] os: [linux] - libc: [glibc] '@img/sharp-linux-ppc64@0.34.5': resolution: {integrity: sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [ppc64] os: [linux] - libc: [glibc] '@img/sharp-linux-riscv64@0.34.5': resolution: {integrity: sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [riscv64] os: [linux] - libc: [glibc] '@img/sharp-linux-s390x@0.34.5': resolution: {integrity: sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [s390x] os: [linux] - libc: [glibc] '@img/sharp-linux-x64@0.34.5': resolution: {integrity: sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [linux] - libc: [glibc] '@img/sharp-linuxmusl-arm64@0.34.5': resolution: {integrity: sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [linux] - libc: [musl] '@img/sharp-linuxmusl-x64@0.34.5': resolution: {integrity: sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [linux] - libc: [musl] '@img/sharp-wasm32@0.34.5': resolution: {integrity: sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==} @@ -386,28 +376,24 @@ packages: engines: {node: '>= 10'} cpu: [arm64] os: [linux] - libc: [glibc] '@next/swc-linux-arm64-musl@16.1.6': resolution: {integrity: sha512-S4J2v+8tT3NIO9u2q+S0G5KdvNDjXfAv06OhfOzNDaBn5rw84DGXWndOEB7d5/x852A20sW1M56vhC/tRVbccQ==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - libc: [musl] '@next/swc-linux-x64-gnu@16.1.6': resolution: {integrity: sha512-2eEBDkFlMMNQnkTyPBhQOAyn2qMxyG2eE7GPH2WIDGEpEILcBPI/jdSv4t6xupSP+ot/jkfrCShLAa7+ZUPcJQ==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - libc: [glibc] '@next/swc-linux-x64-musl@16.1.6': resolution: {integrity: sha512-oicJwRlyOoZXVlxmIMaTq7f8pN9QNbdes0q2FXfRsPhfCi8n8JmOZJm5oo1pwDaFbnnD421rVU409M3evFbIqg==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - libc: [musl] '@next/swc-win32-arm64-msvc@16.1.6': resolution: {integrity: sha512-gQmm8izDTPgs+DCWH22kcDmuUp7NyiJgEl18bcr8irXA5N2m2O+JQIr6f3ct42GOs9c0h8QF3L5SzIxcYAAXXw==} @@ -466,42 +452,36 @@ packages: engines: {node: '>= 10.0.0'} cpu: [arm] os: [linux] - libc: [glibc] '@parcel/watcher-linux-arm-musl@2.5.6': resolution: {integrity: sha512-Ve3gUCG57nuUUSyjBq/MAM0CzArtuIOxsBdQ+ftz6ho8n7s1i9E1Nmk/xmP323r2YL0SONs1EuwqBp2u1k5fxg==} engines: {node: '>= 10.0.0'} cpu: [arm] os: [linux] - libc: [musl] '@parcel/watcher-linux-arm64-glibc@2.5.6': resolution: {integrity: sha512-f2g/DT3NhGPdBmMWYoxixqYr3v/UXcmLOYy16Bx0TM20Tchduwr4EaCbmxh1321TABqPGDpS8D/ggOTaljijOA==} engines: {node: '>= 10.0.0'} cpu: [arm64] os: [linux] - libc: [glibc] '@parcel/watcher-linux-arm64-musl@2.5.6': resolution: {integrity: sha512-qb6naMDGlbCwdhLj6hgoVKJl2odL34z2sqkC7Z6kzir8b5W65WYDpLB6R06KabvZdgoHI/zxke4b3zR0wAbDTA==} engines: {node: '>= 10.0.0'} cpu: [arm64] os: [linux] - libc: [musl] '@parcel/watcher-linux-x64-glibc@2.5.6': resolution: {integrity: sha512-kbT5wvNQlx7NaGjzPFu8nVIW1rWqV780O7ZtkjuWaPUgpv2NMFpjYERVi0UYj1msZNyCzGlaCWEtzc+exjMGbQ==} engines: {node: '>= 10.0.0'} cpu: [x64] os: [linux] - libc: [glibc] '@parcel/watcher-linux-x64-musl@2.5.6': resolution: {integrity: sha512-1JRFeC+h7RdXwldHzTsmdtYR/Ku8SylLgTU/reMuqdVD7CtLwf0VR1FqeprZ0eHQkO0vqsbvFLXUmYm/uNKJBg==} engines: {node: '>= 10.0.0'} cpu: [x64] os: [linux] - libc: [musl] '@parcel/watcher-win32-arm64@2.5.6': resolution: {integrity: sha512-3ukyebjc6eGlw9yRt678DxVF7rjXatWiHvTXqphZLvo7aC5NdEgFufVwjFfY51ijYEWpXbqF5jtrK275z52D4Q==} @@ -655,49 +635,41 @@ packages: resolution: {integrity: sha512-34gw7PjDGB9JgePJEmhEqBhWvCiiWCuXsL9hYphDF7crW7UgI05gyBAi6MF58uGcMOiOqSJ2ybEeCvHcq0BCmQ==} cpu: [arm64] os: [linux] - libc: [glibc] '@unrs/resolver-binding-linux-arm64-musl@1.11.1': resolution: {integrity: sha512-RyMIx6Uf53hhOtJDIamSbTskA99sPHS96wxVE/bJtePJJtpdKGXO1wY90oRdXuYOGOTuqjT8ACccMc4K6QmT3w==} cpu: [arm64] os: [linux] - libc: [musl] '@unrs/resolver-binding-linux-ppc64-gnu@1.11.1': resolution: {integrity: sha512-D8Vae74A4/a+mZH0FbOkFJL9DSK2R6TFPC9M+jCWYia/q2einCubX10pecpDiTmkJVUH+y8K3BZClycD8nCShA==} cpu: [ppc64] os: [linux] - libc: [glibc] '@unrs/resolver-binding-linux-riscv64-gnu@1.11.1': resolution: {integrity: sha512-frxL4OrzOWVVsOc96+V3aqTIQl1O2TjgExV4EKgRY09AJ9leZpEg8Ak9phadbuX0BA4k8U5qtvMSQQGGmaJqcQ==} cpu: [riscv64] os: [linux] - libc: [glibc] '@unrs/resolver-binding-linux-riscv64-musl@1.11.1': resolution: {integrity: sha512-mJ5vuDaIZ+l/acv01sHoXfpnyrNKOk/3aDoEdLO/Xtn9HuZlDD6jKxHlkN8ZhWyLJsRBxfv9GYM2utQ1SChKew==} cpu: [riscv64] os: [linux] - libc: [musl] '@unrs/resolver-binding-linux-s390x-gnu@1.11.1': resolution: {integrity: sha512-kELo8ebBVtb9sA7rMe1Cph4QHreByhaZ2QEADd9NzIQsYNQpt9UkM9iqr2lhGr5afh885d/cB5QeTXSbZHTYPg==} cpu: [s390x] os: [linux] - libc: [glibc] '@unrs/resolver-binding-linux-x64-gnu@1.11.1': resolution: {integrity: sha512-C3ZAHugKgovV5YvAMsxhq0gtXuwESUKc5MhEtjBpLoHPLYM+iuwSj3lflFwK3DPm68660rZ7G8BMcwSro7hD5w==} cpu: [x64] os: [linux] - libc: [glibc] '@unrs/resolver-binding-linux-x64-musl@1.11.1': resolution: {integrity: sha512-rV0YSoyhK2nZ4vEswT/QwqzqQXw5I6CjoaYMOX0TqBlWhojUf8P94mvI7nuJTeaCkkds3QE4+zS8Ko+GdXuZtA==} cpu: [x64] os: [linux] - libc: [musl] '@unrs/resolver-binding-wasm32-wasi@1.11.1': resolution: {integrity: sha512-5u4RkfxJm+Ng7IWgkzi3qrFOvLvQYnPBmjmZQ8+szTK/b31fQCnleNl1GgEt7nIsZRIf5PLhPwT0WM+q45x/UQ==} @@ -1432,6 +1404,10 @@ packages: resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} hasBin: true + lru-cache@11.2.7: + resolution: {integrity: sha512-aY/R+aEsRelme17KGQa/1ZSIpLpNYYrhcrepKTZgE+W3WM16YMCaPwOHLHsmopZHELU0Ojin1lPVxKR0MihncA==} + engines: {node: 20 || >=22} + lru-cache@5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} @@ -1604,6 +1580,9 @@ packages: queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + rate-limiter-flexible@10.0.1: + resolution: {integrity: sha512-3G6GMFz5Oz5nVnDv9gQ1LLMdExR4B1lOjogPIjehtgyxPMIkY09BGyk2eCYt36/OkV/0t12GEt6J6HpTl6RzZg==} + react-dom@19.2.3: resolution: {integrity: sha512-yELu4WmLPw5Mr/lmeEpox5rw3RETacE++JgHqQzd2dg+YbJuat3jH4ingc+WPZhxaoFzdv9y33G+F7Nl5O0GBg==} peerDependencies: @@ -3367,6 +3346,8 @@ snapshots: dependencies: js-tokens: 4.0.0 + lru-cache@11.2.7: {} + lru-cache@5.1.1: dependencies: yallist: 3.1.1 @@ -3539,6 +3520,8 @@ snapshots: queue-microtask@1.2.3: {} + rate-limiter-flexible@10.0.1: {} + react-dom@19.2.3(react@19.2.3): dependencies: react: 19.2.3 diff --git a/src/app/_posts-generator/page.tsx b/src/app/_posts-generator/page.tsx new file mode 100644 index 0000000..dbb43cd --- /dev/null +++ b/src/app/_posts-generator/page.tsx @@ -0,0 +1,65 @@ +"use client"; +import { UsersGeneratorContext } from "./template"; +import { useContext, useMemo } from "react"; +import SwitchSection from "@/components/switch-section"; +import { useFetchPosts } from "@/hooks/useFetchPosts"; +import { Button } from "@/components/ui"; +import * as Prism from "prismjs"; +import "prismjs/components/prism-json"; +import "prismjs/components/prism-sql"; +import buildQuery from "@/utilities/buildQuery"; + +export default function UsersGeneratorPage() { + const { + count, + seed, + } = useContext(UsersGeneratorContext); + + const { isLoading, refetch, data } = useFetchPosts(); + + const highlightedJson = useMemo(() => { + if (!data) return "[]"; + if (!data.ok) return Prism.highlight(data.error, Prism.languages.json, "json"); + const jsonString = JSON.stringify(data.value, null, 2); + return Prism.highlight(jsonString, Prism.languages.json, "json"); + }, [data]); + + const highlightedSql = useMemo(() => { + if (!data) return ""; + if (!data.ok) return Prism.highlight(data.error, Prism.languages.json, "json"); + const sqlString = buildQuery(data); + return Prism.highlight(sqlString, Prism.languages.sql, "sql"); + }, [data]); + + const handleGenerate = () => { + refetch({ count, seed }); + } + + return ( + <> +

Random posts generator

+ + + + +
+
+            
+          
+
+ +
+
+            
+          
+
+
+ + ); +} diff --git a/src/app/_posts-generator/template.tsx b/src/app/_posts-generator/template.tsx new file mode 100644 index 0000000..c3b2213 --- /dev/null +++ b/src/app/_posts-generator/template.tsx @@ -0,0 +1,40 @@ +"use client"; +import { ReactNode, createContext, useState } from "react"; +import Sidebar from "@/components/sidebar"; +import { Input } from "@/components/ui"; +import { cn } from "@/utilities"; +import { PostArgs } from "@/types/generator"; + +export const UsersGeneratorContext = createContext({ + count: 10, + seed: undefined, +}); + +export default function UsersGeneratorTemplate({ children }: { children: ReactNode }) { + const [count, setCount] = useState(10); + const [seed, setSeed] = useState(undefined); + + return ( + <> + + +

Settings

+
+
Count
+
+ ) => setCount(Number(e.target.value) ? Number(e.target.value) : 0)} /> +
+ +
Seed
+
+ ) => setSeed(Number(e.target.value) ? Number(e.target.value) : undefined)} /> +
+
+
+
+ {children} +
+
+ + ); +} diff --git a/src/app/api/generate/route.ts b/src/app/api/generate/route.ts deleted file mode 100644 index 64fd691..0000000 --- a/src/app/api/generate/route.ts +++ /dev/null @@ -1,42 +0,0 @@ -"use server"; -import { NextRequest, NextResponse } from "next/server"; -import { generateData } from "@/utilities/dataGenerator"; -import { GeneratorResponse, GeneratorArgs } from "@/types/generator"; - -export async function POST(request: NextRequest): Promise { - try { - const body = await request.json(); - const { count, fields, seed }: GeneratorArgs = body; - if (typeof count !== "number" || count < 1 || count > 300) { - return NextResponse.json({ error: "Invalid count, must be between 1 and 300." }, { status: 400 }); - } - - if (typeof fields !== "number" && !Array.isArray(fields)) { - return NextResponse.json({ error: "Invalid fields format." }, { status: 400 }); - } - - let message = ""; - - const { result, data } = await generateData({ count, fields, seed }); - if (result == 0) { - message = "Data generated successfully."; - } else if (result == 1) { - return NextResponse.json({ error: "Invalid fields selected." }, { status: 400 }); - } else { - return NextResponse.json({ error: "Invalid count, must be between 1 and 300." }, { status: 400 }); - } - - const response: GeneratorResponse = { - meta: { - count, - generatedAt: new Date().toISOString(), - message, - }, - data, - }; - - return NextResponse.json(response); - } catch (_error) { - return NextResponse.json({ error: "Internal server error" }, { status: 500 }); - } -} diff --git a/src/app/api/generator/posts/route.ts b/src/app/api/generator/posts/route.ts new file mode 100644 index 0000000..dc5a656 --- /dev/null +++ b/src/app/api/generator/posts/route.ts @@ -0,0 +1,27 @@ +import { NextRequest, NextResponse } from "next/server"; +import { PostArgs } from "@/types/generator"; +import generatePosts from "@/utilities/postsGenerator"; +import { checkRateLimit } from "@/utilities/ratelimit/rateLimiter"; + +export async function POST(request: NextRequest): Promise { + try { + const rateLimit = await checkRateLimit(request); + if (!rateLimit.success) { + return NextResponse.json({ error: "Too many requests" }, { status: 429, headers: rateLimit.headers }); + } + + const body = await request.json(); + const { count, seed }: PostArgs = body; + + const response = await generatePosts({ count, seed }); + + if (!response.ok) { + return NextResponse.json(response, { status: 400, headers: rateLimit.headers }); + } + + return NextResponse.json(response, { headers: rateLimit.headers }); + } catch (error) { + console.error(error); + return NextResponse.json({ error: "Internal server error" }, { status: 500 }); + } +} diff --git a/src/app/api/generator/users/route.ts b/src/app/api/generator/users/route.ts new file mode 100644 index 0000000..9b22288 --- /dev/null +++ b/src/app/api/generator/users/route.ts @@ -0,0 +1,27 @@ +import { NextRequest, NextResponse } from "next/server"; +import generateData from "@/utilities/dataGenerator"; +import { UserArgs } from "@/types/generator"; +import { checkRateLimit } from "@/utilities/ratelimit/rateLimiter"; + +export async function POST(request: NextRequest) { + try { + const rateLimit = await checkRateLimit(request); + if (!rateLimit.success) { + return NextResponse.json({ error: "Too many requests" }, { status: 429, headers: rateLimit.headers }); + } + + const body = await request.json(); + const { count, fields, seed }: UserArgs = body; + + const response = await generateData({ count, fields, seed }); + + if (!response.ok) { + return NextResponse.json(response, { status: 400, headers: rateLimit.headers }); + } + + return NextResponse.json(response, { headers: rateLimit.headers }); + } catch (error) { + console.error(error); + return NextResponse.json({ error: "Internal server error" }, { status: 500 }); + } +} diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 9eddaf4..65a1806 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -1,7 +1,7 @@ import { ReactNode } from "react"; import { Metadata } from "next"; import "./styles/default.scss"; -import "prismjs/themes/prism-tomorrow.css"; +import "prismjs/themes/prism-solarizedlight.css"; import Header from "@/components/header"; export const metadata: Metadata = { @@ -14,10 +14,8 @@ export default function Layout({ children }: { children: ReactNode }) {
-
- {children} -
+
{children}
- ) + ); } diff --git a/src/app/page.tsx b/src/app/page.tsx index a927aed..bd36ecd 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -8,26 +8,41 @@ export default function HomePage() {

Primary section.

-

Lorem ipsum dolor sit amet consectetur adipisicing elit. Cupiditate ad, fuga facilis cum possimus nostrum id voluptates. Doloremque quibusdam consectetur, enim ut neque facere commodi eius at totam magnam quae. - Nam optio quibusdam libero distinctio reprehenderit officia ex eum quasi velit, impedit vero. Possimus, fugiat. Eveniet quasi labore molestiae enim, ullam dolore recusandae amet nihil quas quaerat obcaecati pariatur officiis.

+

+ Lorem ipsum dolor sit amet consectetur adipisicing elit. Cupiditate ad, fuga facilis cum possimus nostrum id + voluptates. Doloremque quibusdam consectetur, enim ut neque facere commodi eius at totam magnam quae. Nam + optio quibusdam libero distinctio reprehenderit officia ex eum quasi velit, impedit vero. Possimus, fugiat. + Eveniet quasi labore molestiae enim, ullam dolore recusandae amet nihil quas quaerat obcaecati pariatur + officiis. +

Secondary section.

-

Lorem ipsum dolor sit amet consectetur adipisicing elit. Cupiditate ad, fuga facilis cum possimus nostrum id voluptates. Doloremque quibusdam consectetur, enim ut neque facere commodi eius at totam magnam quae. - Nam optio quibusdam libero distinctio reprehenderit officia ex eum quasi velit, impedit vero. Possimus, fugiat. Eveniet quasi labore molestiae enim, ullam dolore recusandae amet nihil quas quaerat obcaecati pariatur officiis.

+

+ Lorem ipsum dolor sit amet consectetur adipisicing elit. Cupiditate ad, fuga facilis cum possimus nostrum id + voluptates. Doloremque quibusdam consectetur, enim ut neque facere commodi eius at totam magnam quae. Nam + optio quibusdam libero distinctio reprehenderit officia ex eum quasi velit, impedit vero. Possimus, fugiat. + Eveniet quasi labore molestiae enim, ullam dolore recusandae amet nihil quas quaerat obcaecati pariatur + officiis. +

Disabled section.

-

Lorem ipsum dolor sit amet consectetur adipisicing elit. Cupiditate ad, fuga facilis cum possimus nostrum id voluptates. Doloremque quibusdam consectetur, enim ut neque facere commodi eius at totam magnam quae. - Nam optio quibusdam libero distinctio reprehenderit officia ex eum quasi velit, impedit vero. Possimus, fugiat. Eveniet quasi labore molestiae enim, ullam dolore recusandae amet nihil quas quaerat obcaecati pariatur officiis.

+

+ Lorem ipsum dolor sit amet consectetur adipisicing elit. Cupiditate ad, fuga facilis cum possimus nostrum id + voluptates. Doloremque quibusdam consectetur, enim ut neque facere commodi eius at totam magnam quae. Nam + optio quibusdam libero distinctio reprehenderit officia ex eum quasi velit, impedit vero. Possimus, fugiat. + Eveniet quasi labore molestiae enim, ullam dolore recusandae amet nihil quas quaerat obcaecati pariatur + officiis. +

- ) + ); } diff --git a/src/app/styles/_config.scss b/src/app/styles/_config.scss index 67aae2c..ca24d1f 100644 --- a/src/app/styles/_config.scss +++ b/src/app/styles/_config.scss @@ -1,17 +1,17 @@ $props: ( - color-gray-0: #FFFFFF, - color-gray-25: #FDFDFD, - color-gray-50: #FAFAFA, - color-gray-100: #F5F5F5, - color-gray-200: #EAEAEA, - color-gray-300: #D7D7D7, - color-gray-400: #A6A6A6, + color-gray-0: #ffffff, + color-gray-25: #fdfdfd, + color-gray-50: #fafafa, + color-gray-100: #f5f5f5, + color-gray-200: #eaeaea, + color-gray-300: #d7d7d7, + color-gray-400: #a6a6a6, color-gray-500: #777777, - color-gray-600: #5A5A5A, + color-gray-600: #5a5a5a, color-gray-700: #484848, - color-gray-800: #2D2D2D, - color-gray-900: #1F1F1F, - color-gray-950: #0E0E0E, + color-gray-800: #2d2d2d, + color-gray-900: #1f1f1f, + color-gray-950: #0e0e0e, color-gray-1000: #000000, color-brand-primary: #007bff, @@ -21,18 +21,17 @@ $props: ( color-bg-secondary: light-dark(var(--color-gray-200), var(--color-gray-900)), color-bg-secondary-inverse: light-dark(var(--color-gray-900), var(--color-gray-200)), color-bg-disabled: light-dark(var(--color-gray-300), var(--color-gray-700)), - color-fg-lighter: light-dark(var(--color-gray-1000), var(--color-gray-0)), color-fg-primary: light-dark(var(--color-gray-800), var(--color-gray-200)), color-fg-inverse: light-dark(var(--color-gray-0), var(--color-gray-900)), color-fg-secondary: light-dark(var(--color-gray-600), var(--color-gray-400)), color-fg-secondary-inverse: light-dark(var(--color-gray-400), var(--color-gray-600)), color-fg-disabled: light-dark(var(--color-gray-500), var(--color-gray-400)), - box-shadow-primary: light-dark(0 0 15px 1px rgba(0, 0, 0, 0.25), 0 0 15px 1px rgba(255, 255, 255, 0.25)), - box-shadow-focus: (0 0 0px 2px var(--color-bg-primary), - 0 0 0px 4px color-mix(in oklab, var(--color-brand-primary), var(--color-bg-primary))), - + box-shadow-focus: ( + 0 0 0px 2px var(--color-bg-primary), + 0 0 0px 4px color-mix(in oklab, var(--color-brand-primary), var(--color-bg-primary)), + ), size-xxxs: 8px, size-xxs: 16px, size-xs: 24px, diff --git a/src/app/styles/_open-props.scss b/src/app/styles/_open-props.scss index 696b16b..eaeeef1 100644 --- a/src/app/styles/_open-props.scss +++ b/src/app/styles/_open-props.scss @@ -7,9 +7,14 @@ --font-classical-humanist: Optima, Candara, Noto Sans, source-sans-pro, sans-serif; --font-neo-grotesque: Inter, Roboto, Helvetica Neue, Arial Nova, Nimbus Sans, Arial, sans-serif; --font-monospace-slab-serif: Nimbus Mono PS, Courier New, monospace; - --font-monospace-code: Dank Mono, Operator Mono, Inconsolata, Fira Mono, ui-monospace, SF Mono, Monaco, Droid Sans Mono, Source Code Pro, Cascadia Code, Menlo, Consolas, DejaVu Sans Mono, monospace; - --font-industrial: Bahnschrift, DIN Alternate, Franklin Gothic Medium, Nimbus Sans Narrow, sans-serif-condensed, sans-serif; - --font-rounded-sans: ui-rounded, Hiragino Maru Gothic ProN, Quicksand, Comfortaa, Manjari, Arial Rounded MT, Arial Rounded MT Bold, Calibri, source-sans-pro, sans-serif; + --font-monospace-code: + Dank Mono, Operator Mono, Inconsolata, Fira Mono, ui-monospace, SF Mono, Monaco, Droid Sans Mono, Source Code Pro, + Cascadia Code, Menlo, Consolas, DejaVu Sans Mono, monospace; + --font-industrial: + Bahnschrift, DIN Alternate, Franklin Gothic Medium, Nimbus Sans Narrow, sans-serif-condensed, sans-serif; + --font-rounded-sans: + ui-rounded, Hiragino Maru Gothic ProN, Quicksand, Comfortaa, Manjari, Arial Rounded MT, Arial Rounded MT Bold, + Calibri, source-sans-pro, sans-serif; --font-slab-serif: Rockwell, Rockwell Nova, Roboto Slab, DejaVu Serif, Sitka Small, serif; --font-antique: Superclarendon, Bookman Old Style, URW Bookman, URW Bookman L, Georgia Pro, Georgia, serif; --font-didone: Didot, Bodoni MT, Noto Serif Display, URW Palladio L, P052, Sylfaen, serif; @@ -26,23 +31,23 @@ --font-weight-7: 700; --font-weight-8: 800; --font-weight-9: 900; - --font-lineheight-00: .95; + --font-lineheight-00: 0.95; --font-lineheight-0: 1.1; --font-lineheight-1: 1.25; --font-lineheight-2: 1.375; --font-lineheight-3: 1.5; --font-lineheight-4: 1.75; --font-lineheight-5: 2; - --font-letterspacing-0: -.05em; - --font-letterspacing-1: .025em; - --font-letterspacing-2: .050em; - --font-letterspacing-3: .075em; - --font-letterspacing-4: .150em; - --font-letterspacing-5: .500em; - --font-letterspacing-6: .750em; + --font-letterspacing-0: -0.05em; + --font-letterspacing-1: 0.025em; + --font-letterspacing-2: 0.05em; + --font-letterspacing-3: 0.075em; + --font-letterspacing-4: 0.15em; + --font-letterspacing-5: 0.5em; + --font-letterspacing-6: 0.75em; --font-letterspacing-7: 1em; - --font-size-00: .5rem; - --font-size-0: .75rem; + --font-size-00: 0.5rem; + --font-size-0: 0.75rem; --font-size-1: 1rem; --font-size-2: 1.1rem; --font-size-3: 1.25rem; @@ -51,14 +56,14 @@ --font-size-6: 2.5rem; --font-size-7: 3rem; --font-size-8: 3.5rem; - --font-size-fluid-0: max(.75rem, min(2vw, 1rem)); + --font-size-fluid-0: max(0.75rem, min(2vw, 1rem)); --font-size-fluid-1: max(1rem, min(4vw, 1.5rem)); --font-size-fluid-2: max(1.5rem, min(6vw, 2.5rem)); --font-size-fluid-3: max(2rem, min(9vw, 3.5rem)); - --size-000: -.5rem; - --size-00: -.25rem; - --size-1: .25rem; - --size-2: .5rem; + --size-000: -0.5rem; + --size-00: -0.25rem; + --size-1: 0.25rem; + --size-2: 0.5rem; --size-3: 1rem; --size-4: 1.25rem; --size-5: 1.5rem; @@ -89,7 +94,7 @@ --size-px-13: 240px; --size-px-14: 320px; --size-px-15: 480px; - --size-fluid-1: max(.5rem, min(1vw, 1rem)); + --size-fluid-1: max(0.5rem, min(1vw, 1rem)); --size-fluid-2: max(1rem, min(2vw, 1.5rem)); --size-fluid-3: max(1.5rem, min(3vw, 2rem)); --size-fluid-4: max(2rem, min(4vw, 3rem)); @@ -112,10 +117,10 @@ --size-lg: 1024px; --size-xl: 1440px; --size-xxl: 1920px; - --size-relative-000: -.5ch; - --size-relative-00: -.25ch; - --size-relative-1: .25ch; - --size-relative-2: .5ch; + --size-relative-000: -0.5ch; + --size-relative-00: -0.25ch; + --size-relative-1: 0.25ch; + --size-relative-2: 0.5ch; --size-relative-3: 1ch; --size-relative-4: 1.25ch; --size-relative-5: 1.5ch; @@ -129,41 +134,41 @@ --size-relative-13: 15ch; --size-relative-14: 20ch; --size-relative-15: 30ch; - --ease-1: cubic-bezier(.25, 0, .5, 1); - --ease-2: cubic-bezier(.25, 0, .4, 1); - --ease-3: cubic-bezier(.25, 0, .3, 1); - --ease-4: cubic-bezier(.25, 0, .2, 1); - --ease-5: cubic-bezier(.25, 0, .1, 1); - --ease-in-1: cubic-bezier(.25, 0, 1, 1); - --ease-in-2: cubic-bezier(.50, 0, 1, 1); - --ease-in-3: cubic-bezier(.70, 0, 1, 1); - --ease-in-4: cubic-bezier(.90, 0, 1, 1); + --ease-1: cubic-bezier(0.25, 0, 0.5, 1); + --ease-2: cubic-bezier(0.25, 0, 0.4, 1); + --ease-3: cubic-bezier(0.25, 0, 0.3, 1); + --ease-4: cubic-bezier(0.25, 0, 0.2, 1); + --ease-5: cubic-bezier(0.25, 0, 0.1, 1); + --ease-in-1: cubic-bezier(0.25, 0, 1, 1); + --ease-in-2: cubic-bezier(0.5, 0, 1, 1); + --ease-in-3: cubic-bezier(0.7, 0, 1, 1); + --ease-in-4: cubic-bezier(0.9, 0, 1, 1); --ease-in-5: cubic-bezier(1, 0, 1, 1); - --ease-out-1: cubic-bezier(0, 0, .75, 1); - --ease-out-2: cubic-bezier(0, 0, .50, 1); - --ease-out-3: cubic-bezier(0, 0, .3, 1); - --ease-out-4: cubic-bezier(0, 0, .1, 1); + --ease-out-1: cubic-bezier(0, 0, 0.75, 1); + --ease-out-2: cubic-bezier(0, 0, 0.5, 1); + --ease-out-3: cubic-bezier(0, 0, 0.3, 1); + --ease-out-4: cubic-bezier(0, 0, 0.1, 1); --ease-out-5: cubic-bezier(0, 0, 0, 1); - --ease-in-out-1: cubic-bezier(.1, 0, .9, 1); - --ease-in-out-2: cubic-bezier(.3, 0, .7, 1); - --ease-in-out-3: cubic-bezier(.5, 0, .5, 1); - --ease-in-out-4: cubic-bezier(.7, 0, .3, 1); - --ease-in-out-5: cubic-bezier(.9, 0, .1, 1); - --ease-elastic-out-1: cubic-bezier(.5, .75, .75, 1.25); - --ease-elastic-out-2: cubic-bezier(.5, 1, .75, 1.25); - --ease-elastic-out-3: cubic-bezier(.5, 1.25, .75, 1.25); - --ease-elastic-out-4: cubic-bezier(.5, 1.5, .75, 1.25); - --ease-elastic-out-5: cubic-bezier(.5, 1.75, .75, 1.25); - --ease-elastic-in-1: cubic-bezier(.5, -0.25, .75, 1); - --ease-elastic-in-2: cubic-bezier(.5, -0.50, .75, 1); - --ease-elastic-in-3: cubic-bezier(.5, -0.75, .75, 1); - --ease-elastic-in-4: cubic-bezier(.5, -1.00, .75, 1); - --ease-elastic-in-5: cubic-bezier(.5, -1.25, .75, 1); - --ease-elastic-in-out-1: cubic-bezier(.5, -.1, .1, 1.5); - --ease-elastic-in-out-2: cubic-bezier(.5, -.3, .1, 1.5); - --ease-elastic-in-out-3: cubic-bezier(.5, -.5, .1, 1.5); - --ease-elastic-in-out-4: cubic-bezier(.5, -.7, .1, 1.5); - --ease-elastic-in-out-5: cubic-bezier(.5, -.9, .1, 1.5); + --ease-in-out-1: cubic-bezier(0.1, 0, 0.9, 1); + --ease-in-out-2: cubic-bezier(0.3, 0, 0.7, 1); + --ease-in-out-3: cubic-bezier(0.5, 0, 0.5, 1); + --ease-in-out-4: cubic-bezier(0.7, 0, 0.3, 1); + --ease-in-out-5: cubic-bezier(0.9, 0, 0.1, 1); + --ease-elastic-out-1: cubic-bezier(0.5, 0.75, 0.75, 1.25); + --ease-elastic-out-2: cubic-bezier(0.5, 1, 0.75, 1.25); + --ease-elastic-out-3: cubic-bezier(0.5, 1.25, 0.75, 1.25); + --ease-elastic-out-4: cubic-bezier(0.5, 1.5, 0.75, 1.25); + --ease-elastic-out-5: cubic-bezier(0.5, 1.75, 0.75, 1.25); + --ease-elastic-in-1: cubic-bezier(0.5, -0.25, 0.75, 1); + --ease-elastic-in-2: cubic-bezier(0.5, -0.5, 0.75, 1); + --ease-elastic-in-3: cubic-bezier(0.5, -0.75, 0.75, 1); + --ease-elastic-in-4: cubic-bezier(0.5, -1, 0.75, 1); + --ease-elastic-in-5: cubic-bezier(0.5, -1.25, 0.75, 1); + --ease-elastic-in-out-1: cubic-bezier(0.5, -0.1, 0.1, 1.5); + --ease-elastic-in-out-2: cubic-bezier(0.5, -0.3, 0.1, 1.5); + --ease-elastic-in-out-3: cubic-bezier(0.5, -0.5, 0.1, 1.5); + --ease-elastic-in-out-4: cubic-bezier(0.5, -0.7, 0.1, 1.5); + --ease-elastic-in-out-5: cubic-bezier(0.5, -0.9, 0.1, 1.5); --ease-step-1: steps(2); --ease-step-2: steps(3); --ease-step-3: steps(4); @@ -179,37 +184,339 @@ --ease-squish-3: var(--ease-elastic-in-out-3); --ease-squish-4: var(--ease-elastic-in-out-4); --ease-squish-5: var(--ease-elastic-in-out-5); - --ease-spring-1: linear(0, 0.006, 0.025 2.8%, 0.101 6.1%, 0.539 18.9%, 0.721 25.3%, 0.849 31.5%, 0.937 38.1%, 0.968 41.8%, 0.991 45.7%, 1.006 50.1%, 1.015 55%, 1.017 63.9%, 1.001); - --ease-spring-2: linear(0, 0.007, 0.029 2.2%, 0.118 4.7%, 0.625 14.4%, 0.826 19%, 0.902, 0.962, 1.008 26.1%, 1.041 28.7%, 1.064 32.1%, 1.07 36%, 1.061 40.5%, 1.015 53.4%, 0.999 61.6%, 0.995 71.2%, 1); - --ease-spring-3: linear(0, 0.009, 0.035 2.1%, 0.141 4.4%, 0.723 12.9%, 0.938 16.7%, 1.017, 1.077, 1.121, 1.149 24.3%, 1.159, 1.163, 1.161, 1.154 29.9%, 1.129 32.8%, 1.051 39.6%, 1.017 43.1%, 0.991, 0.977 51%, 0.974 53.8%, 0.975 57.1%, 0.997 69.8%, 1.003 76.9%, 1); - --ease-spring-4: linear(0, 0.009, 0.037 1.7%, 0.153 3.6%, 0.776 10.3%, 1.001, 1.142 16%, 1.185, 1.209 19%, 1.215 19.9% 20.8%, 1.199, 1.165 25%, 1.056 30.3%, 1.008 33%, 0.973, 0.955 39.2%, 0.953 41.1%, 0.957 43.3%, 0.998 53.3%, 1.009 59.1% 63.7%, 0.998 78.9%, 1); - --ease-spring-5: linear(0, 0.01, 0.04 1.6%, 0.161 3.3%, 0.816 9.4%, 1.046, 1.189 14.4%, 1.231, 1.254 17%, 1.259, 1.257 18.6%, 1.236, 1.194 22.3%, 1.057 27%, 0.999 29.4%, 0.955 32.1%, 0.942, 0.935 34.9%, 0.933, 0.939 38.4%, 1 47.3%, 1.011, 1.017 52.6%, 1.016 56.4%, 1 65.2%, 0.996 70.2%, 1.001 87.2%, 1); - --ease-bounce-1: linear(0, 0.004, 0.016, 0.035, 0.063, 0.098, 0.141, 0.191, 0.25, 0.316, 0.391 36.8%, 0.563, 0.766, 1 58.8%, 0.946, 0.908 69.1%, 0.895, 0.885, 0.879, 0.878, 0.879, 0.885, 0.895, 0.908 89.7%, 0.946, 1); - --ease-bounce-2: linear(0, 0.004, 0.016, 0.035, 0.063, 0.098, 0.141 15.1%, 0.25, 0.391, 0.562, 0.765, 1, 0.892 45.2%, 0.849, 0.815, 0.788, 0.769, 0.757, 0.753, 0.757, 0.769, 0.788, 0.815, 0.85, 0.892 75.2%, 1 80.2%, 0.973, 0.954, 0.943, 0.939, 0.943, 0.954, 0.973, 1); - --ease-bounce-3: linear(0, 0.004, 0.016, 0.035, 0.062, 0.098, 0.141 11.4%, 0.25, 0.39, 0.562, 0.764, 1 30.3%, 0.847 34.8%, 0.787, 0.737, 0.699, 0.672, 0.655, 0.65, 0.656, 0.672, 0.699, 0.738, 0.787, 0.847 61.7%, 1 66.2%, 0.946, 0.908, 0.885 74.2%, 0.879, 0.878, 0.879, 0.885 79.5%, 0.908, 0.946, 1 87.4%, 0.981, 0.968, 0.96, 0.957, 0.96, 0.968, 0.981, 1); - --ease-bounce-4: linear(0, 0.004, 0.016 3%, 0.062, 0.141, 0.25, 0.391, 0.562 18.2%, 1 24.3%, 0.81, 0.676 32.3%, 0.629, 0.595, 0.575, 0.568, 0.575, 0.595, 0.629, 0.676 48.2%, 0.811, 1 56.2%, 0.918, 0.86, 0.825, 0.814, 0.825, 0.86, 0.918, 1 77.2%, 0.94 80.6%, 0.925, 0.92, 0.925, 0.94 87.5%, 1 90.9%, 0.974, 0.965, 0.974, 1); - --ease-bounce-5: linear(0, 0.004, 0.016 2.5%, 0.063, 0.141, 0.25 10.1%, 0.562, 1 20.2%, 0.783, 0.627, 0.534 30.9%, 0.511, 0.503, 0.511, 0.534 38%, 0.627, 0.782, 1 48.7%, 0.892, 0.815, 0.769 56.3%, 0.757, 0.753, 0.757, 0.769 61.3%, 0.815, 0.892, 1 68.8%, 0.908 72.4%, 0.885, 0.878, 0.885, 0.908 79.4%, 1 83%, 0.954 85.5%, 0.943, 0.939, 0.943, 0.954 90.5%, 1 93%, 0.977, 0.97, 0.977, 1); - --ease-circ-in: cubic-bezier(.6, .04, .98, .335); - --ease-circ-in-out: cubic-bezier(.785, .135, .15, .86); - --ease-circ-out: cubic-bezier(.075, .82, .165, 1); - --ease-cubic-in: cubic-bezier(.55, .055, .675, .19); - --ease-cubic-in-out: cubic-bezier(.645, .045, .355, 1); - --ease-cubic-out: cubic-bezier(.215, .61, .355, 1); - --ease-expo-in: cubic-bezier(.95, .05, .795, .035); + --ease-spring-1: linear( + 0, + 0.006, + 0.025 2.8%, + 0.101 6.1%, + 0.539 18.9%, + 0.721 25.3%, + 0.849 31.5%, + 0.937 38.1%, + 0.968 41.8%, + 0.991 45.7%, + 1.006 50.1%, + 1.015 55%, + 1.017 63.9%, + 1.001 + ); + --ease-spring-2: linear( + 0, + 0.007, + 0.029 2.2%, + 0.118 4.7%, + 0.625 14.4%, + 0.826 19%, + 0.902, + 0.962, + 1.008 26.1%, + 1.041 28.7%, + 1.064 32.1%, + 1.07 36%, + 1.061 40.5%, + 1.015 53.4%, + 0.999 61.6%, + 0.995 71.2%, + 1 + ); + --ease-spring-3: linear( + 0, + 0.009, + 0.035 2.1%, + 0.141 4.4%, + 0.723 12.9%, + 0.938 16.7%, + 1.017, + 1.077, + 1.121, + 1.149 24.3%, + 1.159, + 1.163, + 1.161, + 1.154 29.9%, + 1.129 32.8%, + 1.051 39.6%, + 1.017 43.1%, + 0.991, + 0.977 51%, + 0.974 53.8%, + 0.975 57.1%, + 0.997 69.8%, + 1.003 76.9%, + 1 + ); + --ease-spring-4: linear( + 0, + 0.009, + 0.037 1.7%, + 0.153 3.6%, + 0.776 10.3%, + 1.001, + 1.142 16%, + 1.185, + 1.209 19%, + 1.215 19.9% 20.8%, + 1.199, + 1.165 25%, + 1.056 30.3%, + 1.008 33%, + 0.973, + 0.955 39.2%, + 0.953 41.1%, + 0.957 43.3%, + 0.998 53.3%, + 1.009 59.1% 63.7%, + 0.998 78.9%, + 1 + ); + --ease-spring-5: linear( + 0, + 0.01, + 0.04 1.6%, + 0.161 3.3%, + 0.816 9.4%, + 1.046, + 1.189 14.4%, + 1.231, + 1.254 17%, + 1.259, + 1.257 18.6%, + 1.236, + 1.194 22.3%, + 1.057 27%, + 0.999 29.4%, + 0.955 32.1%, + 0.942, + 0.935 34.9%, + 0.933, + 0.939 38.4%, + 1 47.3%, + 1.011, + 1.017 52.6%, + 1.016 56.4%, + 1 65.2%, + 0.996 70.2%, + 1.001 87.2%, + 1 + ); + --ease-bounce-1: linear( + 0, + 0.004, + 0.016, + 0.035, + 0.063, + 0.098, + 0.141, + 0.191, + 0.25, + 0.316, + 0.391 36.8%, + 0.563, + 0.766, + 1 58.8%, + 0.946, + 0.908 69.1%, + 0.895, + 0.885, + 0.879, + 0.878, + 0.879, + 0.885, + 0.895, + 0.908 89.7%, + 0.946, + 1 + ); + --ease-bounce-2: linear( + 0, + 0.004, + 0.016, + 0.035, + 0.063, + 0.098, + 0.141 15.1%, + 0.25, + 0.391, + 0.562, + 0.765, + 1, + 0.892 45.2%, + 0.849, + 0.815, + 0.788, + 0.769, + 0.757, + 0.753, + 0.757, + 0.769, + 0.788, + 0.815, + 0.85, + 0.892 75.2%, + 1 80.2%, + 0.973, + 0.954, + 0.943, + 0.939, + 0.943, + 0.954, + 0.973, + 1 + ); + --ease-bounce-3: linear( + 0, + 0.004, + 0.016, + 0.035, + 0.062, + 0.098, + 0.141 11.4%, + 0.25, + 0.39, + 0.562, + 0.764, + 1 30.3%, + 0.847 34.8%, + 0.787, + 0.737, + 0.699, + 0.672, + 0.655, + 0.65, + 0.656, + 0.672, + 0.699, + 0.738, + 0.787, + 0.847 61.7%, + 1 66.2%, + 0.946, + 0.908, + 0.885 74.2%, + 0.879, + 0.878, + 0.879, + 0.885 79.5%, + 0.908, + 0.946, + 1 87.4%, + 0.981, + 0.968, + 0.96, + 0.957, + 0.96, + 0.968, + 0.981, + 1 + ); + --ease-bounce-4: linear( + 0, + 0.004, + 0.016 3%, + 0.062, + 0.141, + 0.25, + 0.391, + 0.562 18.2%, + 1 24.3%, + 0.81, + 0.676 32.3%, + 0.629, + 0.595, + 0.575, + 0.568, + 0.575, + 0.595, + 0.629, + 0.676 48.2%, + 0.811, + 1 56.2%, + 0.918, + 0.86, + 0.825, + 0.814, + 0.825, + 0.86, + 0.918, + 1 77.2%, + 0.94 80.6%, + 0.925, + 0.92, + 0.925, + 0.94 87.5%, + 1 90.9%, + 0.974, + 0.965, + 0.974, + 1 + ); + --ease-bounce-5: linear( + 0, + 0.004, + 0.016 2.5%, + 0.063, + 0.141, + 0.25 10.1%, + 0.562, + 1 20.2%, + 0.783, + 0.627, + 0.534 30.9%, + 0.511, + 0.503, + 0.511, + 0.534 38%, + 0.627, + 0.782, + 1 48.7%, + 0.892, + 0.815, + 0.769 56.3%, + 0.757, + 0.753, + 0.757, + 0.769 61.3%, + 0.815, + 0.892, + 1 68.8%, + 0.908 72.4%, + 0.885, + 0.878, + 0.885, + 0.908 79.4%, + 1 83%, + 0.954 85.5%, + 0.943, + 0.939, + 0.943, + 0.954 90.5%, + 1 93%, + 0.977, + 0.97, + 0.977, + 1 + ); + --ease-circ-in: cubic-bezier(0.6, 0.04, 0.98, 0.335); + --ease-circ-in-out: cubic-bezier(0.785, 0.135, 0.15, 0.86); + --ease-circ-out: cubic-bezier(0.075, 0.82, 0.165, 1); + --ease-cubic-in: cubic-bezier(0.55, 0.055, 0.675, 0.19); + --ease-cubic-in-out: cubic-bezier(0.645, 0.045, 0.355, 1); + --ease-cubic-out: cubic-bezier(0.215, 0.61, 0.355, 1); + --ease-expo-in: cubic-bezier(0.95, 0.05, 0.795, 0.035); --ease-expo-in-out: cubic-bezier(1, 0, 0, 1); - --ease-expo-out: cubic-bezier(.19, 1, .22, 1); - --ease-quad-in: cubic-bezier(.55, .085, .68, .53); - --ease-quad-in-out: cubic-bezier(.455, .03, .515, .955); - --ease-quad-out: cubic-bezier(.25, .46, .45, .94); - --ease-quart-in: cubic-bezier(.895, .03, .685, .22); - --ease-quart-in-out: cubic-bezier(.77, 0, .175, 1); - --ease-quart-out: cubic-bezier(.165, .84, .44, 1); - --ease-quint-in: cubic-bezier(.755, .05, .855, .06); - --ease-quint-in-out: cubic-bezier(.86, 0, .07, 1); - --ease-quint-out: cubic-bezier(.23, 1, .32, 1); - --ease-sine-in: cubic-bezier(.47, 0, .745, .715); - --ease-sine-in-out: cubic-bezier(.445, .05, .55, .95); - --ease-sine-out: cubic-bezier(.39, .575, .565, 1); + --ease-expo-out: cubic-bezier(0.19, 1, 0.22, 1); + --ease-quad-in: cubic-bezier(0.55, 0.085, 0.68, 0.53); + --ease-quad-in-out: cubic-bezier(0.455, 0.03, 0.515, 0.955); + --ease-quad-out: cubic-bezier(0.25, 0.46, 0.45, 0.94); + --ease-quart-in: cubic-bezier(0.895, 0.03, 0.685, 0.22); + --ease-quart-in-out: cubic-bezier(0.77, 0, 0.175, 1); + --ease-quart-out: cubic-bezier(0.165, 0.84, 0.44, 1); + --ease-quint-in: cubic-bezier(0.755, 0.05, 0.855, 0.06); + --ease-quint-in-out: cubic-bezier(0.86, 0, 0.07, 1); + --ease-quint-out: cubic-bezier(0.23, 1, 0.32, 1); + --ease-sine-in: cubic-bezier(0.47, 0, 0.745, 0.715); + --ease-sine-in-out: cubic-bezier(0.445, 0.05, 0.55, 0.95); + --ease-sine-out: cubic-bezier(0.39, 0.575, 0.565, 1); --layer-1: 1; --layer-2: 2; --layer-3: 3; @@ -225,24 +532,51 @@ --shadow-strength-7: calc(var(--shadow-strength) + 6%); --shadow-strength-8: calc(var(--shadow-strength) + 7%); --shadow-strength-10: calc(var(--shadow-strength) + 9%); - --inner-shadow-highlight: inset 0 -.5px 0 0 #fff, inset 0 .5px 0 0 rgba(0, 0, 0, .067); + --inner-shadow-highlight: inset 0 -0.5px 0 0 #fff, inset 0 0.5px 0 0 rgba(0, 0, 0, 0.067); --shadow-1: 0 1px 2px -1px hsl(var(--shadow-color)/var(--shadow-strength-10)); - --shadow-2: 0 3px 5px -2px hsl(var(--shadow-color)/var(--shadow-strength-4)), 0 7px 14px -5px hsl(var(--shadow-color)/var(--shadow-strength-6)); - --shadow-3: 0 -1px 3px 0 hsl(var(--shadow-color)/var(--shadow-strength-3)), 0 1px 2px -5px hsl(var(--shadow-color)/var(--shadow-strength-3)), 0 2px 5px -5px hsl(var(--shadow-color)/var(--shadow-strength-5)), 0 4px 12px -5px hsl(var(--shadow-color)/var(--shadow-strength-6)), 0 12px 15px -5px hsl(var(--shadow-color)/var(--shadow-strength-8)); - --shadow-4: 0 -2px 5px 0 hsl(var(--shadow-color)/var(--shadow-strength-3)), 0 1px 1px -2px hsl(var(--shadow-color)/var(--shadow-strength-4)), 0 2px 2px -2px hsl(var(--shadow-color)/var(--shadow-strength-4)), 0 5px 5px -2px hsl(var(--shadow-color)/var(--shadow-strength-5)), 0 9px 9px -2px hsl(var(--shadow-color)/var(--shadow-strength-6)), 0 16px 16px -2px hsl(var(--shadow-color)/var(--shadow-strength-7)); - --shadow-5: 0 -1px 2px 0 hsl(var(--shadow-color)/var(--shadow-strength-3)), 0 2px 1px -2px hsl(var(--shadow-color)/var(--shadow-strength-4)), 0 5px 5px -2px hsl(var(--shadow-color)/var(--shadow-strength-4)), 0 10px 10px -2px hsl(var(--shadow-color)/var(--shadow-strength-5)), 0 20px 20px -2px hsl(var(--shadow-color)/var(--shadow-strength-6)), 0 40px 40px -2px hsl(var(--shadow-color)/var(--shadow-strength-8)); - --shadow-6: 0 -1px 2px 0 hsl(var(--shadow-color)/var(--shadow-strength-3)), 0 3px 2px -2px hsl(var(--shadow-color)/var(--shadow-strength-4)), 0 7px 5px -2px hsl(var(--shadow-color)/var(--shadow-strength-4)), 0 12px 10px -2px hsl(var(--shadow-color)/var(--shadow-strength-5)), 0 22px 18px -2px hsl(var(--shadow-color)/var(--shadow-strength-6)), 0 41px 33px -2px hsl(var(--shadow-color)/var(--shadow-strength-7)), 0 100px 80px -2px hsl(var(--shadow-color)/var(--shadow-strength-8)); + --shadow-2: + 0 3px 5px -2px hsl(var(--shadow-color)/var(--shadow-strength-4)), + 0 7px 14px -5px hsl(var(--shadow-color)/var(--shadow-strength-6)); + --shadow-3: + 0 -1px 3px 0 hsl(var(--shadow-color)/var(--shadow-strength-3)), + 0 1px 2px -5px hsl(var(--shadow-color)/var(--shadow-strength-3)), + 0 2px 5px -5px hsl(var(--shadow-color)/var(--shadow-strength-5)), + 0 4px 12px -5px hsl(var(--shadow-color)/var(--shadow-strength-6)), + 0 12px 15px -5px hsl(var(--shadow-color)/var(--shadow-strength-8)); + --shadow-4: + 0 -2px 5px 0 hsl(var(--shadow-color)/var(--shadow-strength-3)), + 0 1px 1px -2px hsl(var(--shadow-color)/var(--shadow-strength-4)), + 0 2px 2px -2px hsl(var(--shadow-color)/var(--shadow-strength-4)), + 0 5px 5px -2px hsl(var(--shadow-color)/var(--shadow-strength-5)), + 0 9px 9px -2px hsl(var(--shadow-color)/var(--shadow-strength-6)), + 0 16px 16px -2px hsl(var(--shadow-color)/var(--shadow-strength-7)); + --shadow-5: + 0 -1px 2px 0 hsl(var(--shadow-color)/var(--shadow-strength-3)), + 0 2px 1px -2px hsl(var(--shadow-color)/var(--shadow-strength-4)), + 0 5px 5px -2px hsl(var(--shadow-color)/var(--shadow-strength-4)), + 0 10px 10px -2px hsl(var(--shadow-color)/var(--shadow-strength-5)), + 0 20px 20px -2px hsl(var(--shadow-color)/var(--shadow-strength-6)), + 0 40px 40px -2px hsl(var(--shadow-color)/var(--shadow-strength-8)); + --shadow-6: + 0 -1px 2px 0 hsl(var(--shadow-color)/var(--shadow-strength-3)), + 0 3px 2px -2px hsl(var(--shadow-color)/var(--shadow-strength-4)), + 0 7px 5px -2px hsl(var(--shadow-color)/var(--shadow-strength-4)), + 0 12px 10px -2px hsl(var(--shadow-color)/var(--shadow-strength-5)), + 0 22px 18px -2px hsl(var(--shadow-color)/var(--shadow-strength-6)), + 0 41px 33px -2px hsl(var(--shadow-color)/var(--shadow-strength-7)), + 0 100px 80px -2px hsl(var(--shadow-color)/var(--shadow-strength-8)); --inner-shadow-0: inset 0 0 0 1px hsl(var(--shadow-color)/var(--shadow-strength-10)); --inner-shadow-1: inset 0 1px 2px 0 hsl(var(--shadow-color)/var(--shadow-strength-10)), var(--inner-shadow-highlight); --inner-shadow-2: inset 0 1px 4px 0 hsl(var(--shadow-color)/var(--shadow-strength-10)), var(--inner-shadow-highlight); --inner-shadow-3: inset 0 2px 8px 0 hsl(var(--shadow-color)/var(--shadow-strength-10)), var(--inner-shadow-highlight); - --inner-shadow-4: inset 0 2px 14px 0 hsl(var(--shadow-color)/var(--shadow-strength-10)), var(--inner-shadow-highlight); + --inner-shadow-4: + inset 0 2px 14px 0 hsl(var(--shadow-color)/var(--shadow-strength-10)), var(--inner-shadow-highlight); --ratio-square: 1; --ratio-landscape: 4/3; --ratio-portrait: 3/4; --ratio-widescreen: 16/9; --ratio-ultrawide: 18/5; - --ratio-golden: 1.6180/1; + --ratio-golden: 1.618/1; --gray-0: #f8f9fa; --gray-1: #f1f3f5; --gray-2: #e9ecef; @@ -491,36 +825,111 @@ --jungle-11: #516605; --jungle-12: #3d4d04; --gradient-space: ; - --gradient-1: linear-gradient(to bottom right var(--gradient-space), #1f005c, #5b0060, #870160, #ac255e, #ca485c, #e16b5c, #f39060, #ffb56b); + --gradient-1: linear-gradient( + to bottom right var(--gradient-space), + #1f005c, + #5b0060, + #870160, + #ac255e, + #ca485c, + #e16b5c, + #f39060, + #ffb56b + ); --gradient-2: linear-gradient(to bottom right var(--gradient-space), #48005c, #8300e2, #a269ff); - --gradient-3: radial-gradient(circle at top right var(--gradient-space), #0ff, rgba(0, 255, 255, 0)), radial-gradient(circle at bottom left var(--gradient-space), #ff1492, rgba(255, 20, 146, 0)); + --gradient-3: + radial-gradient(circle at top right var(--gradient-space), #0ff, rgba(0, 255, 255, 0)), + radial-gradient(circle at bottom left var(--gradient-space), #ff1492, rgba(255, 20, 146, 0)); --gradient-4: linear-gradient(to bottom right var(--gradient-space), #00f5a0, #00d9f5); --gradient-5: conic-gradient(from -270deg at 75% 110% var(--gradient-space), #f0f, #fffaf0); --gradient-6: conic-gradient(from -90deg at top left var(--gradient-space), #000, #fff); --gradient-7: linear-gradient(to bottom right var(--gradient-space), #72c6ef, #004e8f); --gradient-8: conic-gradient(from 90deg at 50% 0% var(--gradient-space), #111, 50%, #222, #111); - --gradient-9: conic-gradient(from .5turn at bottom center var(--gradient-space), #add8e6, #fff); - --gradient-10: conic-gradient(from 90deg at 40% -25% var(--gradient-space), gold, #f79d03, #ee6907, #e6390a, #de0d0d, #d61039, #cf1261, #c71585, #cf1261, #d61039, #de0d0d, #ee6907, #f79d03, gold, gold, gold); + --gradient-9: conic-gradient(from 0.5turn at bottom center var(--gradient-space), #add8e6, #fff); + --gradient-10: conic-gradient( + from 90deg at 40% -25% var(--gradient-space), + gold, + #f79d03, + #ee6907, + #e6390a, + #de0d0d, + #d61039, + #cf1261, + #c71585, + #cf1261, + #d61039, + #de0d0d, + #ee6907, + #f79d03, + gold, + gold, + gold + ); --gradient-11: conic-gradient(at bottom left var(--gradient-space), #ff1493, cyan); - --gradient-12: conic-gradient(from 90deg at 25% -10% var(--gradient-space), #ff4500, #d3f340, #7bee85, #afeeee, #7bee85); - --gradient-13: radial-gradient(circle at 50% 200% var(--gradient-space), #000142, #3b0083, #b300c3, #ff059f, #ff4661, #ffad86, #fff3c7); + --gradient-12: conic-gradient( + from 90deg at 25% -10% var(--gradient-space), + #ff4500, + #d3f340, + #7bee85, + #afeeee, + #7bee85 + ); + --gradient-13: radial-gradient( + circle at 50% 200% var(--gradient-space), + #000142, + #3b0083, + #b300c3, + #ff059f, + #ff4661, + #ffad86, + #fff3c7 + ); --gradient-14: conic-gradient(at top right var(--gradient-space), lime, cyan); --gradient-15: linear-gradient(to bottom right var(--gradient-space), #c7d2fe, #fecaca, #fef3c7); --gradient-16: radial-gradient(circle at 50% -250% var(--gradient-space), #374151, #111827, #000); --gradient-17: conic-gradient(from -90deg at 50% -25% var(--gradient-space), blue, #8a2be2); - --gradient-18: linear-gradient(0deg var(--gradient-space), rgba(255, 0, 0, .8), rgba(255, 0, 0, 0) 75%), linear-gradient(60deg var(--gradient-space), rgba(255, 255, 0, .8), rgba(255, 255, 0, 0) 75%), linear-gradient(120deg var(--gradient-space), rgba(0, 255, 0, .8), rgba(0, 255, 0, 0) 75%), linear-gradient(180deg var(--gradient-space), rgba(0, 255, 255, .8), rgba(0, 255, 255, 0) 75%), linear-gradient(240deg var(--gradient-space), rgba(0, 0, 255, .8), rgba(0, 0, 255, 0) 75%), linear-gradient(300deg var(--gradient-space), rgba(255, 0, 255, .8), rgba(255, 0, 255, 0) 75%); + --gradient-18: + linear-gradient(0deg var(--gradient-space), rgba(255, 0, 0, 0.8), rgba(255, 0, 0, 0) 75%), + linear-gradient(60deg var(--gradient-space), rgba(255, 255, 0, 0.8), rgba(255, 255, 0, 0) 75%), + linear-gradient(120deg var(--gradient-space), rgba(0, 255, 0, 0.8), rgba(0, 255, 0, 0) 75%), + linear-gradient(180deg var(--gradient-space), rgba(0, 255, 255, 0.8), rgba(0, 255, 255, 0) 75%), + linear-gradient(240deg var(--gradient-space), rgba(0, 0, 255, 0.8), rgba(0, 0, 255, 0) 75%), + linear-gradient(300deg var(--gradient-space), rgba(255, 0, 255, 0.8), rgba(255, 0, 255, 0) 75%); --gradient-19: linear-gradient(to bottom right var(--gradient-space), #ffe259, #ffa751); - --gradient-20: conic-gradient(from -135deg at -10% center var(--gradient-space), orange, #ff7715, #ff522a, #ff3f47, #ff5482, #ff69b4); - --gradient-21: conic-gradient(from -90deg at 25% 115% var(--gradient-space), red, #f06, #f0c, #c0f, #60f, #00f, #00f, #00f, #00f); + --gradient-20: conic-gradient( + from -135deg at -10% center var(--gradient-space), + orange, + #ff7715, + #ff522a, + #ff3f47, + #ff5482, + #ff69b4 + ); + --gradient-21: conic-gradient( + from -90deg at 25% 115% var(--gradient-space), + red, + #f06, + #f0c, + #c0f, + #60f, + #00f, + #00f, + #00f, + #00f + ); --gradient-22: linear-gradient(to bottom right var(--gradient-space), #acb6e5, #86fde8); --gradient-23: linear-gradient(to bottom right var(--gradient-space), #536976, #292e49); - --gradient-24: conic-gradient(from .5turn at 0% 0% var(--gradient-space), #00c476, 10%, #82b0ff, 90%, #00c476); + --gradient-24: conic-gradient(from 0.5turn at 0% 0% var(--gradient-space), #00c476, 10%, #82b0ff, 90%, #00c476); --gradient-25: conic-gradient(at 125% 50% var(--gradient-space), #b78cf7, #ff7c94, #ffcf0d, #ff7c94, #b78cf7); --gradient-26: linear-gradient(to bottom right var(--gradient-space), #9796f0, #fbc7d4); - --gradient-27: conic-gradient(from .5turn at bottom left var(--gradient-space), #ff1493, #639); + --gradient-27: conic-gradient(from 0.5turn at bottom left var(--gradient-space), #ff1493, #639); --gradient-28: conic-gradient(from -90deg at 50% 105% var(--gradient-space), #fff, orchid); - --gradient-29: radial-gradient(circle at top right var(--gradient-space), #bfb3ff, rgba(191, 179, 255, 0)), radial-gradient(circle at bottom left var(--gradient-space), #86acf9, rgba(134, 172, 249, 0)); - --gradient-30: radial-gradient(circle at top right var(--gradient-space), #00ff80, rgba(0, 255, 128, 0)), radial-gradient(circle at bottom left var(--gradient-space), #adffd6, rgba(173, 255, 214, 0)); + --gradient-29: + radial-gradient(circle at top right var(--gradient-space), #bfb3ff, rgba(191, 179, 255, 0)), + radial-gradient(circle at bottom left var(--gradient-space), #86acf9, rgba(134, 172, 249, 0)); + --gradient-30: + radial-gradient(circle at top right var(--gradient-space), #00ff80, rgba(0, 255, 128, 0)), + radial-gradient(circle at bottom left var(--gradient-space), #adffd6, rgba(173, 255, 214, 0)); --noise-1: url("data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 200 200' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='a'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.005' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23a)'/%3E%3C/svg%3E"); --noise-2: url("data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 300 300' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='a'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.05' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23a)'/%3E%3C/svg%3E"); --noise-3: url("data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 1024 1024' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='a'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.25' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23a)'/%3E%3C/svg%3E"); @@ -531,22 +940,22 @@ --noise-filter-3: contrast(200%) brightness(250%); --noise-filter-4: contrast(200%) brightness(500%); --noise-filter-5: contrast(200%) brightness(1000%); - --animation-fade-in: fade-in .5s var(--ease-3); + --animation-fade-in: fade-in 0.5s var(--ease-3); --animation-fade-in-bloom: fade-in-bloom 2s var(--ease-3); - --animation-fade-out: fade-out .5s var(--ease-3); + --animation-fade-out: fade-out 0.5s var(--ease-3); --animation-fade-out-bloom: fade-out-bloom 2s var(--ease-3); - --animation-scale-up: scale-up .5s var(--ease-3); - --animation-scale-down: scale-down .5s var(--ease-3); - --animation-slide-out-up: slide-out-up .5s var(--ease-3); - --animation-slide-out-down: slide-out-down .5s var(--ease-3); - --animation-slide-out-right: slide-out-right .5s var(--ease-3); - --animation-slide-out-left: slide-out-left .5s var(--ease-3); - --animation-slide-in-up: slide-in-up .5s var(--ease-3); - --animation-slide-in-down: slide-in-down .5s var(--ease-3); - --animation-slide-in-right: slide-in-right .5s var(--ease-3); - --animation-slide-in-left: slide-in-left .5s var(--ease-3); - --animation-shake-x: shake-x .75s var(--ease-out-5); - --animation-shake-y: shake-y .75s var(--ease-out-5); + --animation-scale-up: scale-up 0.5s var(--ease-3); + --animation-scale-down: scale-down 0.5s var(--ease-3); + --animation-slide-out-up: slide-out-up 0.5s var(--ease-3); + --animation-slide-out-down: slide-out-down 0.5s var(--ease-3); + --animation-slide-out-right: slide-out-right 0.5s var(--ease-3); + --animation-slide-out-left: slide-out-left 0.5s var(--ease-3); + --animation-slide-in-up: slide-in-up 0.5s var(--ease-3); + --animation-slide-in-down: slide-in-down 0.5s var(--ease-3); + --animation-slide-in-right: slide-in-right 0.5s var(--ease-3); + --animation-slide-in-left: slide-in-left 0.5s var(--ease-3); + --animation-shake-x: shake-x 0.75s var(--ease-out-5); + --animation-shake-y: shake-y 0.75s var(--ease-out-5); --animation-shake-z: shake-z 1s var(--ease-in-out-3); --animation-spin: spin 2s linear infinite; --animation-ping: ping 5s var(--ease-out-3) infinite; @@ -586,305 +995,312 @@ --palette-hue: 250; --palette-hue-rotate-by: 0; --palette-chroma: 0.15; - --color-1: oklch(98% calc(var(--palette-chroma)*0.03) calc(var(--palette-hue) + var(--palette-hue-rotate-by)*0)); - --color-2: oklch(97% calc(var(--palette-chroma)*0.06) calc(var(--palette-hue) + var(--palette-hue-rotate-by)*1)); - --color-3: oklch(93% calc(var(--palette-chroma)*0.1) calc(var(--palette-hue) + var(--palette-hue-rotate-by)*2)); - --color-4: oklch(84% calc(var(--palette-chroma)*0.12) calc(var(--palette-hue) + var(--palette-hue-rotate-by)*3)); - --color-5: oklch(80% calc(var(--palette-chroma)*0.16) calc(var(--palette-hue) + var(--palette-hue-rotate-by)*4)); - --color-6: oklch(71% calc(var(--palette-chroma)*0.19) calc(var(--palette-hue) + var(--palette-hue-rotate-by)*5)); - --color-7: oklch(66% calc(var(--palette-chroma)*0.2) calc(var(--palette-hue) + var(--palette-hue-rotate-by)*6)); - --color-8: oklch(58% calc(var(--palette-chroma)*0.21) calc(var(--palette-hue) + var(--palette-hue-rotate-by)*7)); - --color-9: oklch(53% calc(var(--palette-chroma)*0.2) calc(var(--palette-hue) + var(--palette-hue-rotate-by)*8)); - --color-10: oklch(49% calc(var(--palette-chroma)*0.19) calc(var(--palette-hue) + var(--palette-hue-rotate-by)*9)); - --color-11: oklch(42% calc(var(--palette-chroma)*0.17) calc(var(--palette-hue) + var(--palette-hue-rotate-by)*10)); - --color-12: oklch(35% calc(var(--palette-chroma)*0.15) calc(var(--palette-hue) + var(--palette-hue-rotate-by)*11)); - --color-13: oklch(27% calc(var(--palette-chroma)*0.12) calc(var(--palette-hue) + var(--palette-hue-rotate-by)*12)); - --color-14: oklch(20% calc(var(--palette-chroma)*0.09) calc(var(--palette-hue) + var(--palette-hue-rotate-by)*13)); - --color-15: oklch(16% calc(var(--palette-chroma)*0.07) calc(var(--palette-hue) + var(--palette-hue-rotate-by)*14)); - --color-16: oklch(10% calc(var(--palette-chroma)*0.05) calc(var(--palette-hue) + var(--palette-hue-rotate-by)*15)) + --color-1: oklch(98% calc(var(--palette-chroma) * 0.03) calc(var(--palette-hue) + var(--palette-hue-rotate-by) * 0)); + --color-2: oklch(97% calc(var(--palette-chroma) * 0.06) calc(var(--palette-hue) + var(--palette-hue-rotate-by) * 1)); + --color-3: oklch(93% calc(var(--palette-chroma) * 0.1) calc(var(--palette-hue) + var(--palette-hue-rotate-by) * 2)); + --color-4: oklch(84% calc(var(--palette-chroma) * 0.12) calc(var(--palette-hue) + var(--palette-hue-rotate-by) * 3)); + --color-5: oklch(80% calc(var(--palette-chroma) * 0.16) calc(var(--palette-hue) + var(--palette-hue-rotate-by) * 4)); + --color-6: oklch(71% calc(var(--palette-chroma) * 0.19) calc(var(--palette-hue) + var(--palette-hue-rotate-by) * 5)); + --color-7: oklch(66% calc(var(--palette-chroma) * 0.2) calc(var(--palette-hue) + var(--palette-hue-rotate-by) * 6)); + --color-8: oklch(58% calc(var(--palette-chroma) * 0.21) calc(var(--palette-hue) + var(--palette-hue-rotate-by) * 7)); + --color-9: oklch(53% calc(var(--palette-chroma) * 0.2) calc(var(--palette-hue) + var(--palette-hue-rotate-by) * 8)); + --color-10: oklch(49% calc(var(--palette-chroma) * 0.19) calc(var(--palette-hue) + var(--palette-hue-rotate-by) * 9)); + --color-11: oklch( + 42% calc(var(--palette-chroma) * 0.17) calc(var(--palette-hue) + var(--palette-hue-rotate-by) * 10) + ); + --color-12: oklch( + 35% calc(var(--palette-chroma) * 0.15) calc(var(--palette-hue) + var(--palette-hue-rotate-by) * 11) + ); + --color-13: oklch( + 27% calc(var(--palette-chroma) * 0.12) calc(var(--palette-hue) + var(--palette-hue-rotate-by) * 12) + ); + --color-14: oklch( + 20% calc(var(--palette-chroma) * 0.09) calc(var(--palette-hue) + var(--palette-hue-rotate-by) * 13) + ); + --color-15: oklch( + 16% calc(var(--palette-chroma) * 0.07) calc(var(--palette-hue) + var(--palette-hue-rotate-by) * 14) + ); + --color-16: oklch( + 10% calc(var(--palette-chroma) * 0.05) calc(var(--palette-hue) + var(--palette-hue-rotate-by) * 15) + ); } -@media (prefers-color-scheme:dark) { +@media (prefers-color-scheme: dark) { :where(html) { --shadow-color: 220 40% 2%; --shadow-strength: 25%; - --inner-shadow-highlight: inset 0 -.5px 0 0 hsla(0, 0%, 100%, .067), inset 0 .5px 0 0 rgba(0, 0, 0, .467) + --inner-shadow-highlight: inset 0 -0.5px 0 0 hsla(0, 0%, 100%, 0.067), inset 0 0.5px 0 0 rgba(0, 0, 0, 0.467); } } -@supports (background:linear-gradient(to right in oklab, #000, #fff)) { +@supports (background: linear-gradient(to right in oklab, #000, #fff)) { :where(html) { - --gradient-space: in oklab + --gradient-space: in oklab; } } @keyframes fade-in { to { - opacity: 1 + opacity: 1; } } @keyframes fade-in-bloom { 0% { filter: brightness(1) blur(20px); - opacity: 0 + opacity: 0; } 10% { filter: brightness(2) blur(10px); - opacity: 1 + opacity: 1; } to { filter: brightness(1) blur(0); - opacity: 1 + opacity: 1; } } @keyframes fade-out { to { - opacity: 0 + opacity: 0; } } @keyframes fade-out-bloom { to { filter: brightness(1) blur(20px); - opacity: 0 + opacity: 0; } 10% { filter: brightness(2) blur(10px); - opacity: 1 + opacity: 1; } 0% { filter: brightness(1) blur(0); - opacity: 1 + opacity: 1; } } @keyframes scale-up { to { - transform: scale(1.25) + transform: scale(1.25); } } @keyframes scale-down { to { - transform: scale(.75) + transform: scale(0.75); } } @keyframes slide-out-up { to { - transform: translateY(-100%) + transform: translateY(-100%); } } @keyframes slide-out-down { to { - transform: translateY(100%) + transform: translateY(100%); } } @keyframes slide-out-right { to { - transform: translateX(100%) + transform: translateX(100%); } } @keyframes slide-out-left { to { - transform: translateX(-100%) + transform: translateX(-100%); } } @keyframes slide-in-up { 0% { - transform: translateY(100%) + transform: translateY(100%); } } @keyframes slide-in-down { 0% { - transform: translateY(-100%) + transform: translateY(-100%); } } @keyframes slide-in-right { 0% { - transform: translateX(-100%) + transform: translateX(-100%); } } @keyframes slide-in-left { 0% { - transform: translateX(100%) + transform: translateX(100%); } } @keyframes shake-x { - 0%, to { - transform: translateX(0) + transform: translateX(0); } 20% { - transform: translateX(-5%) + transform: translateX(-5%); } 40% { - transform: translateX(5%) + transform: translateX(5%); } 60% { - transform: translateX(-5%) + transform: translateX(-5%); } 80% { - transform: translateX(5%) + transform: translateX(5%); } } @keyframes shake-y { - 0%, to { - transform: translateY(0) + transform: translateY(0); } 20% { - transform: translateY(-5%) + transform: translateY(-5%); } 40% { - transform: translateY(5%) + transform: translateY(5%); } 60% { - transform: translateY(-5%) + transform: translateY(-5%); } 80% { - transform: translateY(5%) + transform: translateY(5%); } } @keyframes shake-z { - 0%, to { - transform: rotate(0deg) + transform: rotate(0deg); } 20% { - transform: rotate(-2deg) + transform: rotate(-2deg); } 40% { - transform: rotate(2deg) + transform: rotate(2deg); } 60% { - transform: rotate(-2deg) + transform: rotate(-2deg); } 80% { - transform: rotate(2deg) + transform: rotate(2deg); } } @keyframes spin { to { - transform: rotate(1turn) + transform: rotate(1turn); } } @keyframes ping { - 90%, to { opacity: 0; - transform: scale(2) + transform: scale(2); } } @keyframes blink { - 0%, to { - opacity: 1 + opacity: 1; } 50% { - opacity: .5 + opacity: 0.5; } } @keyframes float { 50% { - transform: translateY(-25%) + transform: translateY(-25%); } } @keyframes bounce { 25% { - transform: translateY(-20%) + transform: translateY(-20%); } 40% { - transform: translateY(-3%) + transform: translateY(-3%); } 0%, 60%, to { - transform: translateY(0) + transform: translateY(0); } } @keyframes pulse { 50% { - transform: scale(.9) + transform: scale(0.9); } } -@media (prefers-color-scheme:dark) { +@media (prefers-color-scheme: dark) { @keyframes fade-in-bloom { 0% { filter: brightness(1) blur(20px); - opacity: 0 + opacity: 0; } 10% { - filter: brightness(.5) blur(10px); - opacity: 1 + filter: brightness(0.5) blur(10px); + opacity: 1; } to { filter: brightness(1) blur(0); - opacity: 1 + opacity: 1; } } } -@media (prefers-color-scheme:dark) { +@media (prefers-color-scheme: dark) { @keyframes fade-out-bloom { to { filter: brightness(1) blur(20px); - opacity: 0 + opacity: 0; } 10% { - filter: brightness(.5) blur(10px); - opacity: 1 + filter: brightness(0.5) blur(10px); + opacity: 1; } 0% { filter: brightness(1) blur(0); - opacity: 1 + opacity: 1; } } } diff --git a/src/app/styles/_typography.scss b/src/app/styles/_typography.scss index e53c30f..523a21a 100644 --- a/src/app/styles/_typography.scss +++ b/src/app/styles/_typography.scss @@ -1,5 +1,4 @@ @layer typography { - h1, h2, h3, diff --git a/src/app/styles/components/_button.scss b/src/app/styles/components/_button.scss index 4ce20e4..fa3e123 100644 --- a/src/app/styles/components/_button.scss +++ b/src/app/styles/components/_button.scss @@ -14,6 +14,10 @@ font-size: var(--font-size); font-weight: var(--font-weight); transition: 0.2s; + display: inline-flex; + align-items: center; + justify-content: center; + gap: var(--space-xxs); &:not(&:disabled):hover { background-color: var(--btn-bg-color-hover); diff --git a/src/app/styles/components/_code.scss b/src/app/styles/components/_code.scss new file mode 100644 index 0000000..b94cc62 --- /dev/null +++ b/src/app/styles/components/_code.scss @@ -0,0 +1,29 @@ +@layer components { + .code { + position: relative; + border: 1px solid var(--color-bg-disabled); + background-color: var(--color-bg-secondary); + padding: var(--space-s); + border-radius: var(--border-radius); + + .copy { + position: absolute; + top: var(--space-xs); + right: var(--space-xs); + + .feedback { + position: absolute; + top: 0; + right: 0; + transform: translateY(-110%); + background-color: var(--color-bg-secondary); + color: var(--color-fg-secondary); + border: 1px solid var(--color-fg-secondary); + border-radius: var(--border-radius); + padding: var(--space-xxs); + white-space: nowrap; + transition: 0.2s; + } + } + } +} diff --git a/src/app/styles/components/_icon.scss b/src/app/styles/components/_icon.scss index 3deb5c6..9cc12eb 100644 --- a/src/app/styles/components/_icon.scss +++ b/src/app/styles/components/_icon.scss @@ -2,11 +2,21 @@ .icon { width: var(--size-xs); height: var(--size-xs); - display: flex; + display: inline-flex; align-items: center; justify-content: center; color: inherit; + &.size-xxs { + width: var(--size-xxs); + height: var(--size-xxs); + } + + &.size-xs { + width: var(--size-xs); + height: var(--size-xs); + } + &.size-s { width: var(--size-s); height: var(--size-s); diff --git a/src/app/styles/components/_index.scss b/src/app/styles/components/_index.scss index c6f6aba..eadae6c 100644 --- a/src/app/styles/components/_index.scss +++ b/src/app/styles/components/_index.scss @@ -6,3 +6,4 @@ @forward "./icon"; @forward "./switch-section"; @forward "./input"; +@forward "./code"; diff --git a/src/app/styles/utilities/_display.scss b/src/app/styles/utilities/_display.scss new file mode 100644 index 0000000..1ed160f --- /dev/null +++ b/src/app/styles/utilities/_display.scss @@ -0,0 +1,5 @@ +@layer utilities { + .display-none { + display: none; + } +} diff --git a/src/app/styles/utilities/_index.scss b/src/app/styles/utilities/_index.scss index bb4b9be..3bbb43f 100644 --- a/src/app/styles/utilities/_index.scss +++ b/src/app/styles/utilities/_index.scss @@ -2,3 +2,4 @@ @forward "./position"; @forward "./grid"; @forward "./sizes"; +@forward "./display"; diff --git a/src/app/users-generator/page.tsx b/src/app/users-generator/page.tsx index 825d4f1..98427c3 100644 --- a/src/app/users-generator/page.tsx +++ b/src/app/users-generator/page.tsx @@ -1,13 +1,15 @@ "use client"; import { UsersGeneratorContext } from "./template"; -import { useContext, useMemo } from "react"; +import { useContext, useMemo, useState } from "react"; import SwitchSection from "@/components/switch-section"; -import { useFetch } from "@/hooks/useFetch"; +import { useFetchUsers } from "@/hooks/useFetchUsers"; import { Button } from "@/components/ui"; import * as Prism from "prismjs"; import "prismjs/components/prism-json"; import "prismjs/components/prism-sql"; import buildQuery from "@/utilities/buildQuery"; +import Icon from "@/components/ui/icon"; +import { cn } from "@/utilities"; export default function UsersGeneratorPage() { const { @@ -21,60 +23,101 @@ export default function UsersGeneratorPage() { seed, } = useContext(UsersGeneratorContext); - const { isLoading, refetch, data, error } = useFetch(); + const { isLoading, refetch, data } = useFetchUsers(); + + const fields = useMemo(() => { + let fields = 0; + if (isName) fields |= 1; + if (isSurname) fields |= 2; + if (isUsername) fields |= 4; + if (isAvatar) fields |= 8; + if (isEmail) fields |= 16; + if (isPassword) fields |= 32; + return fields; + }, [isName, isSurname, isUsername, isAvatar, isEmail, isPassword]); + + const jsonText = useMemo(() => { + const jsonString = JSON.stringify(data?.ok ? data.value : [], null, 2); + return jsonString; + }, [data]); + const sqlText = useMemo(() => { + const sqlString = data?.ok ? buildQuery(data) : ""; + return sqlString; + }, [data]); + const [isCopied, setIsCopied] = useState(false); const highlightedJson = useMemo(() => { - const jsonString = JSON.stringify(data?.data ?? [], null, 2); + if (!data) return "[]"; + if (!data.ok) return Prism.highlight(data.error, Prism.languages.json, "json"); + const jsonString = JSON.stringify(data.value, null, 2); return Prism.highlight(jsonString, Prism.languages.json, "json"); }, [data]); const highlightedSql = useMemo(() => { - const sqlString = buildQuery(data?.data ?? []); + if (!data) return ""; + if (!data.ok) return Prism.highlight(data.error, Prism.languages.json, "json"); + const sqlString = buildQuery(data); return Prism.highlight(sqlString, Prism.languages.sql, "sql"); }, [data]); const handleGenerate = () => { - refetch({ - count, fields: [ - isName ? "name" : "", - isSurname ? "surname" : "", - isUsername ? "username" : "", - isAvatar ? "avatar" : "", - isEmail ? "email" : "", - isPassword ? "password" : "", - ], seed - }) - } + refetch({ count, fields, seed }); + }; + + const copyJson = async () => { + try { + await navigator.clipboard.writeText(jsonText); + setIsCopied(true); + setTimeout(() => { + setIsCopied(false); + }, 2000); + } catch {} + }; + + const copySql = async () => { + try { + await navigator.clipboard.writeText(sqlText); + setIsCopied(true); + setTimeout(() => { + setIsCopied(false); + }, 2000); + } catch {} + }; return ( <>

Random users generator

-

Name: {isName ? "enabled" : "disabled"}

-

Surname: {isSurname ? "enabled" : "disabled"}

-

Username: {isUsername ? "enabled" : "disabled"}

-

Avatar: {isAvatar ? "enabled" : "disabled"}

-

Email: {isEmail ? "enabled" : "disabled"}

-

Password: {isPassword ? "enabled" : "disabled"}

+

You can choose what gets generated in the settings.

- +
-
-            
-          
+
+ +
+              
+            
+
-
-            
-          
+
+ +
+              
+            
+
diff --git a/src/app/users-generator/template.tsx b/src/app/users-generator/template.tsx index 4525613..c86a548 100644 --- a/src/app/users-generator/template.tsx +++ b/src/app/users-generator/template.tsx @@ -3,9 +3,9 @@ import { ReactNode, createContext, useState } from "react"; import Sidebar from "@/components/sidebar"; import { Toggle, Input } from "@/components/ui"; import { cn } from "@/utilities"; -import { GeneratorSettings } from "@/types/generator"; +import { UserSettings } from "@/types/generator"; -export const UsersGeneratorContext = createContext({ +export const UsersGeneratorContext = createContext({ name: false, surname: false, username: false, @@ -34,12 +34,24 @@ export default function UsersGeneratorTemplate({ children }: { children: ReactNo
Count
- ) => setCount(Number(e.target.value) ? Number(e.target.value) : 0)} /> + ) => + setCount(Number(e.target.value) ? Number(e.target.value) : 0) + } + />
Seed
- ) => setSeed(Number(e.target.value) ? Number(e.target.value) : undefined)} /> + ) => + setSeed(Number(e.target.value) ? Number(e.target.value) : undefined) + } + />
Name
@@ -73,9 +85,7 @@ export default function UsersGeneratorTemplate({ children }: { children: ReactNo
-
- {children} -
+
{children}
); diff --git a/src/components/header.tsx b/src/components/header.tsx index 18cabd6..739bd67 100644 --- a/src/components/header.tsx +++ b/src/components/header.tsx @@ -19,7 +19,12 @@ export default function Header() { useEffect(() => { const HideSidebarOnClick = (e: MouseEvent) => { - if (sidebarRef.current && headerRef.current && !sidebarRef.current.contains(e.target as Node) && !headerRef.current.contains(e.target as Node)) { + if ( + sidebarRef.current && + headerRef.current && + !sidebarRef.current.contains(e.target as Node) && + !headerRef.current.contains(e.target as Node) + ) { setIsSidebarOpen(false); } }; @@ -28,26 +33,32 @@ export default function Header() { return () => { document.removeEventListener("click", HideSidebarOnClick); - } + }; }, []); return (
-

Mock data generator

+ +

Mock data generator

+
- users generator + + users generator +
-
- users generator +
+ + users generator +
- ) + ); } diff --git a/src/components/section.tsx b/src/components/section.tsx index 1688fe9..0ab0f96 100644 --- a/src/components/section.tsx +++ b/src/components/section.tsx @@ -1,13 +1,6 @@ import { ReactNode } from "react"; import { cn } from "@/utilities"; -export default function Section({ children, variant }: { - children: ReactNode, - variant?: "secondary" | "disabled" -}) { - return ( -
- {children} -
- ) +export default function Section({ children, variant }: { children: ReactNode; variant?: "secondary" | "disabled" }) { + return
{children}
; } diff --git a/src/components/sidebar.tsx b/src/components/sidebar.tsx index 4cb833e..6be3ac6 100644 --- a/src/components/sidebar.tsx +++ b/src/components/sidebar.tsx @@ -1,4 +1,4 @@ -"use client" +"use client"; import { ReactNode, useState, useEffect, useRef } from "react"; import { cn } from "@/utilities"; import Icon from "./ui/icon"; @@ -14,7 +14,12 @@ export default function Sidebar({ children }: { children: ReactNode }) { useEffect(() => { const HideSidebarOnClick = (e: MouseEvent) => { - if (sidebarRef.current && sidebarToggleRef.current && !sidebarRef.current.contains(e.target as Node) && !sidebarToggleRef.current.contains(e.target as Node)) { + if ( + sidebarRef.current && + sidebarToggleRef.current && + !sidebarRef.current.contains(e.target as Node) && + !sidebarToggleRef.current.contains(e.target as Node) + ) { setIsSidebarOpen(false); } }; @@ -23,7 +28,7 @@ export default function Sidebar({ children }: { children: ReactNode }) { return () => { document.removeEventListener("click", HideSidebarOnClick); - } + }; }, []); return ( @@ -36,9 +41,9 @@ export default function Sidebar({ children }: { children: ReactNode }) { -
+
{children}
- ) + ); } diff --git a/src/components/switch-section.tsx b/src/components/switch-section.tsx index 2edf90f..26e6eb7 100644 --- a/src/components/switch-section.tsx +++ b/src/components/switch-section.tsx @@ -1,11 +1,8 @@ -"use client" +"use client"; import { ReactNode, Children, useEffect, useState, isValidElement, createElement } from "react"; import { cn } from "@/utilities"; -export default function SwitchSection({ children, className }: { - children: ReactNode, - className?: string -}) { +export default function SwitchSection({ children, className }: { children: ReactNode; className?: string }) { const [childrenArray, setChildrenArray] = useState([]); const [activeIndex, setActiveIndex] = useState(0); @@ -15,7 +12,6 @@ export default function SwitchSection({ children, className }: { return (
-
{childrenArray.map((el: ReactNode, i: number) => { if (isValidElement<{ id?: string }>(el)) { @@ -30,19 +26,19 @@ export default function SwitchSection({ children, className }: {
{childrenArray.map((el: ReactNode, i: number) => { - if (isValidElement<{ id?: string, children?: ReactNode, className?: string }>(el)) { + if (isValidElement<{ id?: string; children?: ReactNode; className?: string }>(el)) { return createElement( "div", { ...el.props, key: i, - className: cn(el.props.className, "content-item", { "active": i === activeIndex }) + className: cn(el.props.className, "content-item", { active: i === activeIndex }), }, - el.props.children + el.props.children, ); } })}
- ) + ); } diff --git a/src/components/ui/icon.tsx b/src/components/ui/icon.tsx index 7050963..65aac2f 100644 --- a/src/components/ui/icon.tsx +++ b/src/components/ui/icon.tsx @@ -11,6 +11,12 @@ const icons = { + ), + copy: ( + + + + ) } diff --git a/src/hooks/useFetch.ts b/src/hooks/useFetch.ts deleted file mode 100644 index fc63fb4..0000000 --- a/src/hooks/useFetch.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { useState } from "react"; -import { GeneratorArgs, GeneratorResponse } from "@/types/generator"; - -export function useFetch() { - const [isLoading, setIsLoading] = useState(false); - const [data, setData] = useState(null); - const [error, setError] = useState(null); - - const refetch = async ({ count, fields, seed }: GeneratorArgs) => { - setIsLoading(true); - setError(null); - try { - const response = await fetch("/api/generate", { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ count, fields, seed }), - }); - - if (!response.ok) { - throw new Error(`HTTP error! status: ${response.status}`); - } - - const json = await response.json(); - setData(json); - } catch (err) { - setError(err instanceof Error ? err.message : "An error occurred"); - setData(null); - } finally { - setIsLoading(false); - } - }; - - return { isLoading, refetch, data, error }; -} diff --git a/src/hooks/useFetchPosts.ts b/src/hooks/useFetchPosts.ts new file mode 100644 index 0000000..7ee03e3 --- /dev/null +++ b/src/hooks/useFetchPosts.ts @@ -0,0 +1,29 @@ +import { useState } from "react"; +import { PostArgs, GeneratorResponse } from "@/types/generator"; + +export function useFetchPosts() { + const [isLoading, setIsLoading] = useState(false); + const [data, setData] = useState(null); + + const refetch = async ({ count, seed }: PostArgs) => { + setIsLoading(true); + try { + const response = await fetch("/api/generator/posts", { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ count, seed }), + }); + + const json = await response.json(); + setData(json); + } catch { + setData({ ok: false, error: "Internal server error" }); + } finally { + setIsLoading(false); + } + }; + + return { isLoading, refetch, data }; +} diff --git a/src/hooks/useFetchUsers.ts b/src/hooks/useFetchUsers.ts new file mode 100644 index 0000000..cbc289f --- /dev/null +++ b/src/hooks/useFetchUsers.ts @@ -0,0 +1,54 @@ +import { useState } from "react"; +import { UserArgs, GeneratorResponse } from "@/types/generator"; + +export function useFetchUsers() { + const [isLoading, setIsLoading] = useState(false); + const [data, setData] = useState(null); + + const validate = ({ count, fields, seed }: UserArgs): { ok: boolean; error?: string } => { + if ( + typeof fields !== "number" || + typeof count !== "number" || + (seed !== undefined && typeof seed !== "number" && typeof seed !== "number") + ) { + return { ok: false, error: "Invalid arguments" }; + } + + if (fields < 1 || fields > 63) { + return { ok: false, error: "No fields selected" }; + } + + if (count < 1 || count > 300) { + return { ok: false, error: "Count must be between 1 and 300" }; + } + + return { ok: true }; + }; + + const refetch = async ({ count, fields, seed }: UserArgs) => { + const validation = validate({ count, fields }); + if (!validation.ok) { + setData({ ok: false, error: validation.error! }); + return; + } + setIsLoading(true); + try { + const response = await fetch("/api/generator/users", { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ count, fields, seed }), + }); + + const json = await response.json(); + setData(json); + } catch { + setData({ ok: false, error: "Internal server error" }); + } finally { + setIsLoading(false); + } + }; + + return { isLoading, refetch, data }; +} diff --git a/src/types/generator.ts b/src/types/generator.ts index ebfffd8..938ccc6 100644 --- a/src/types/generator.ts +++ b/src/types/generator.ts @@ -1,19 +1,15 @@ -export interface GeneratorResponse { - meta: { - count: number; - generatedAt: string; - message: string; - }; - data: Record[]; +export interface UserArgs { + count: number; + fields: number | string[]; + seed?: number; } -export interface GeneratorArgs { +export interface PostArgs { count: number; - fields: number | string[]; seed?: number; } -export interface GeneratorSettings { +export interface UserSettings { name: boolean; surname: boolean; username: boolean; @@ -23,3 +19,15 @@ export interface GeneratorSettings { count: number; seed: number | undefined; } + +export interface Ok { + ok: true; + value: Record[]; +} + +export interface Err { + ok: false; + error: string; +} + +export type GeneratorResponse = Ok | Err; diff --git a/src/utilities/buildQuery.ts b/src/utilities/buildQuery.ts index 195a267..9d367d1 100644 --- a/src/utilities/buildQuery.ts +++ b/src/utilities/buildQuery.ts @@ -1,11 +1,16 @@ -export default function buildQuery(data: Record[]): string { - if (data.length === 0) { - return ""; - } +import { Ok } from "@/types/generator"; - const columns = Object.keys(data[0]).join(", "); - const values = data - .map((row) => `(${Object.values(row).map((value) => `"${value}"`).join(", ")})`) +export default function buildUserQuery(data: Ok): string { + const tableName = data.value[0].hasOwnProperty("authorId") ? "posts" : "users"; + + const columns = Object.keys(data.value[0]).join(", "); + const values = data.value + .map( + (row) => + `(${Object.values(row) + .map((value) => `"${value}"`) + .join(", ")})`, + ) .join(",\n"); - return `INSERT INTO users (${columns}) VALUES\n${values};`; + return `INSERT INTO ${tableName} (${columns}) VALUES\n${values};`; } diff --git a/src/utilities/dataGenerator.ts b/src/utilities/dataGenerator.ts index 0e73c73..0079b2c 100644 --- a/src/utilities/dataGenerator.ts +++ b/src/utilities/dataGenerator.ts @@ -1,10 +1,5 @@ -"use server"; import { faker } from "@faker-js/faker"; -import { GeneratorArgs } from "../types/generator"; -// config start -const errorSuccess = 0; // "Data generated successfully."; -const errorInvalidFields = 1; // "Invalid fields selected."; -const errorInvalidCount = 2; // "Invalid count, must be between 1 and 300."; +import { UserArgs, GeneratorResponse } from "../types/generator"; const availableFields = 6; // 6 fields: name, surname, username, email, password, avatar @@ -40,17 +35,14 @@ const generators = [ generator: () => faker.internet.password(), }, ]; -// config end -export async function generateData({ count, fields, seed }: GeneratorArgs): Promise<{ - result: number; - data: Record[]; -}> { - let returnCode = errorSuccess; - - if (count > 300 || count < 1) { - console.error("Count is invalid: ", count); - returnCode = errorInvalidCount; +export default async function generateData({ count, fields, seed }: UserArgs): Promise { + if (typeof count !== "number" || count > 300 || count < 1) { + // console.error("Count is invalid: ", count); // dev + return { + ok: false, + error: "Invalid count, must be a number between 1 and 300.", + }; } if (seed !== undefined) { @@ -61,8 +53,11 @@ export async function generateData({ count, fields, seed }: GeneratorArgs): Prom if (typeof fields === "number") { if (fields >= 2 ** availableFields || fields < 1) { - console.error("Invalid fields number: ", fields); - returnCode = errorInvalidFields; + // console.error("Invalid fields number: ", fields); // dev + return { + ok: false, + error: "Invalid fields number, must be between 1 and " + (2 ** availableFields - 1), + }; } for (let i = 0; i < count; i++) { @@ -86,12 +81,15 @@ export async function generateData({ count, fields, seed }: GeneratorArgs): Prom data.push(record); } } else { - console.error("Invalid fields type: ", fields); - returnCode = errorInvalidFields; + // console.error("Invalid fields type: ", fields); // dev + return { + ok: false, + error: "Invalid fields type, must be a number or an array.", + }; } return { - result: returnCode, - data: data, + ok: true, + value: data, }; } diff --git a/src/utilities/postsGenerator.ts b/src/utilities/postsGenerator.ts new file mode 100644 index 0000000..ea1015e --- /dev/null +++ b/src/utilities/postsGenerator.ts @@ -0,0 +1,30 @@ +import { faker } from "@faker-js/faker"; +import { GeneratorResponse, PostArgs } from "@/types/generator"; + +export default async function generatePosts({ count, seed }: PostArgs): Promise { + if (typeof count !== "number" || count > 300 || count < 1) { + return { + ok: false, + error: "Invalid count, must be a number between 1 and 300.", + }; + } + + if (seed !== undefined) { + faker.seed(seed); + } + + const data: Record[] = []; + + for (let i = 0; i < count; i++) { + const record: Record = {}; + record["title"] = faker.hacker.phrase(); + record["content"] = faker.lorem.paragraphs(); + record["authorId"] = (i + 1).toString(); + data.push(record); + } + + return { + ok: true, + value: data, + }; +} diff --git a/src/utilities/ratelimit/rateLimiter.ts b/src/utilities/ratelimit/rateLimiter.ts new file mode 100644 index 0000000..133affd --- /dev/null +++ b/src/utilities/ratelimit/rateLimiter.ts @@ -0,0 +1,35 @@ +import { RateLimiterMemory, RateLimiterRes } from "rate-limiter-flexible"; +import { NextRequest } from "next/server"; + +const rateLimiter = new RateLimiterMemory({ + points: 10, + duration: 1, +}); + +export async function checkRateLimit(request: NextRequest): Promise<{ success: boolean; headers: Headers }> { + try { + const ip = request.headers.get("x-forwarded-for") ?? "127.0.0.1"; + const res = await rateLimiter.consume(ip, 1); + + const headers = new Headers({ + "X-RateLimit-Limit": "10", + "X-RateLimit-Remaining": String(res.remainingPoints), + "X-RateLimit-Reset": new Date(Date.now() + res.msBeforeNext).toISOString(), + }); + + return { success: true, headers }; + } catch (err: unknown) { + if (err instanceof Error) { + return { success: false, headers: new Headers() }; + } + const rejRes = err as RateLimiterRes; + const headers = new Headers({ + "Retry-After": String(Math.round(rejRes.msBeforeNext / 1000) || 1), + "X-RateLimit-Limit": "10", + "X-RateLimit-Remaining": String(rejRes.remainingPoints), + "X-RateLimit-Reset": new Date(Date.now() + rejRes.msBeforeNext).toISOString(), + }); + + return { success: false, headers }; + } +}