feat: create new analysis page
This commit is contained in:
parent
98475437a9
commit
338fdb9bb1
|
@ -11,6 +11,7 @@
|
|||
"@hookform/resolvers": "^3.3.4",
|
||||
"@radix-ui/react-avatar": "^1.0.4",
|
||||
"@radix-ui/react-checkbox": "^1.0.4",
|
||||
"@radix-ui/react-collapsible": "^1.0.3",
|
||||
"@radix-ui/react-dialog": "^1.0.5",
|
||||
"@radix-ui/react-dropdown-menu": "^2.0.6",
|
||||
"@radix-ui/react-hover-card": "^1.0.7",
|
||||
|
@ -34,6 +35,8 @@
|
|||
"next-themes": "^0.3.0",
|
||||
"react": "^18",
|
||||
"react-dom": "^18",
|
||||
"react-drag-drop-files": "^2.3.10",
|
||||
"react-dropzone": "^14.2.3",
|
||||
"react-hook-form": "^7.51.3",
|
||||
"react-resizable-panels": "^2.0.16",
|
||||
"tailwind-merge": "^2.2.2",
|
||||
|
@ -72,6 +75,390 @@
|
|||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/@ampproject/remapping": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz",
|
||||
"integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@jridgewell/gen-mapping": "^0.3.5",
|
||||
"@jridgewell/trace-mapping": "^0.3.24"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/code-frame": {
|
||||
"version": "7.24.2",
|
||||
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.2.tgz",
|
||||
"integrity": "sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ==",
|
||||
"dependencies": {
|
||||
"@babel/highlight": "^7.24.2",
|
||||
"picocolors": "^1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/compat-data": {
|
||||
"version": "7.24.4",
|
||||
"resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.24.4.tgz",
|
||||
"integrity": "sha512-vg8Gih2MLK+kOkHJp4gBEIkyaIi00jgWot2D9QOmmfLC8jINSOzmCLta6Bvz/JSBCqnegV0L80jhxkol5GWNfQ==",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/core": {
|
||||
"version": "7.24.4",
|
||||
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.4.tgz",
|
||||
"integrity": "sha512-MBVlMXP+kkl5394RBLSxxk/iLTeVGuXTV3cIDXavPpMMqnSnt6apKgan/U8O3USWZCWZT/TbgfEpKa4uMgN4Dg==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@ampproject/remapping": "^2.2.0",
|
||||
"@babel/code-frame": "^7.24.2",
|
||||
"@babel/generator": "^7.24.4",
|
||||
"@babel/helper-compilation-targets": "^7.23.6",
|
||||
"@babel/helper-module-transforms": "^7.23.3",
|
||||
"@babel/helpers": "^7.24.4",
|
||||
"@babel/parser": "^7.24.4",
|
||||
"@babel/template": "^7.24.0",
|
||||
"@babel/traverse": "^7.24.1",
|
||||
"@babel/types": "^7.24.0",
|
||||
"convert-source-map": "^2.0.0",
|
||||
"debug": "^4.1.0",
|
||||
"gensync": "^1.0.0-beta.2",
|
||||
"json5": "^2.2.3",
|
||||
"semver": "^6.3.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/babel"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/core/node_modules/json5": {
|
||||
"version": "2.2.3",
|
||||
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
|
||||
"integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"json5": "lib/cli.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/core/node_modules/semver": {
|
||||
"version": "6.3.1",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
|
||||
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/generator": {
|
||||
"version": "7.24.4",
|
||||
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.4.tgz",
|
||||
"integrity": "sha512-Xd6+v6SnjWVx/nus+y0l1sxMOTOMBkyL4+BIdbALyatQnAe/SRVjANeDPSCYaX+i1iJmuGSKf3Z+E+V/va1Hvw==",
|
||||
"dependencies": {
|
||||
"@babel/types": "^7.24.0",
|
||||
"@jridgewell/gen-mapping": "^0.3.5",
|
||||
"@jridgewell/trace-mapping": "^0.3.25",
|
||||
"jsesc": "^2.5.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-annotate-as-pure": {
|
||||
"version": "7.22.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.22.5.tgz",
|
||||
"integrity": "sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==",
|
||||
"dependencies": {
|
||||
"@babel/types": "^7.22.5"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-compilation-targets": {
|
||||
"version": "7.23.6",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.23.6.tgz",
|
||||
"integrity": "sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@babel/compat-data": "^7.23.5",
|
||||
"@babel/helper-validator-option": "^7.23.5",
|
||||
"browserslist": "^4.22.2",
|
||||
"lru-cache": "^5.1.1",
|
||||
"semver": "^6.3.1"
|
||||
},
|
||||
"engines": {
|
||||
"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==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"yallist": "^3.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-compilation-targets/node_modules/semver": {
|
||||
"version": "6.3.1",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
|
||||
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-compilation-targets/node_modules/yallist": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
|
||||
"integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/@babel/helper-environment-visitor": {
|
||||
"version": "7.22.20",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz",
|
||||
"integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==",
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-function-name": {
|
||||
"version": "7.23.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz",
|
||||
"integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==",
|
||||
"dependencies": {
|
||||
"@babel/template": "^7.22.15",
|
||||
"@babel/types": "^7.23.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-hoist-variables": {
|
||||
"version": "7.22.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz",
|
||||
"integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==",
|
||||
"dependencies": {
|
||||
"@babel/types": "^7.22.5"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-module-imports": {
|
||||
"version": "7.24.3",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.3.tgz",
|
||||
"integrity": "sha512-viKb0F9f2s0BCS22QSF308z/+1YWKV/76mwt61NBzS5izMzDPwdq1pTrzf+Li3npBWX9KdQbkeCt1jSAM7lZqg==",
|
||||
"dependencies": {
|
||||
"@babel/types": "^7.24.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-module-transforms": {
|
||||
"version": "7.23.3",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz",
|
||||
"integrity": "sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@babel/helper-environment-visitor": "^7.22.20",
|
||||
"@babel/helper-module-imports": "^7.22.15",
|
||||
"@babel/helper-simple-access": "^7.22.5",
|
||||
"@babel/helper-split-export-declaration": "^7.22.6",
|
||||
"@babel/helper-validator-identifier": "^7.22.20"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@babel/core": "^7.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-plugin-utils": {
|
||||
"version": "7.24.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.0.tgz",
|
||||
"integrity": "sha512-9cUznXMG0+FxRuJfvL82QlTqIzhVW9sL0KjMPHhAOOvpQGL8QtdxnBKILjBqxlHyliz0yCa1G903ZXI/FuHy2w==",
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-simple-access": {
|
||||
"version": "7.22.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz",
|
||||
"integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@babel/types": "^7.22.5"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-split-export-declaration": {
|
||||
"version": "7.22.6",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz",
|
||||
"integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==",
|
||||
"dependencies": {
|
||||
"@babel/types": "^7.22.5"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-string-parser": {
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.1.tgz",
|
||||
"integrity": "sha512-2ofRCjnnA9y+wk8b9IAREroeUP02KHp431N2mhKniy2yKIDKpbrHv9eXwm8cBeWQYcJmzv5qKCu65P47eCF7CQ==",
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-validator-identifier": {
|
||||
"version": "7.22.20",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz",
|
||||
"integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==",
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-validator-option": {
|
||||
"version": "7.23.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz",
|
||||
"integrity": "sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helpers": {
|
||||
"version": "7.24.4",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.4.tgz",
|
||||
"integrity": "sha512-FewdlZbSiwaVGlgT1DPANDuCHaDMiOo+D/IDYRFYjHOuv66xMSJ7fQwwODwRNAPkADIO/z1EoF/l2BCWlWABDw==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@babel/template": "^7.24.0",
|
||||
"@babel/traverse": "^7.24.1",
|
||||
"@babel/types": "^7.24.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/highlight": {
|
||||
"version": "7.24.2",
|
||||
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.2.tgz",
|
||||
"integrity": "sha512-Yac1ao4flkTxTteCDZLEvdxg2fZfz1v8M4QpaGypq/WPDqg3ijHYbDfs+LG5hvzSoqaSZ9/Z9lKSP3CjZjv+pA==",
|
||||
"dependencies": {
|
||||
"@babel/helper-validator-identifier": "^7.22.20",
|
||||
"chalk": "^2.4.2",
|
||||
"js-tokens": "^4.0.0",
|
||||
"picocolors": "^1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/highlight/node_modules/ansi-styles": {
|
||||
"version": "3.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
|
||||
"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
|
||||
"dependencies": {
|
||||
"color-convert": "^1.9.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/highlight/node_modules/chalk": {
|
||||
"version": "2.4.2",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
|
||||
"integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
|
||||
"dependencies": {
|
||||
"ansi-styles": "^3.2.1",
|
||||
"escape-string-regexp": "^1.0.5",
|
||||
"supports-color": "^5.3.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/highlight/node_modules/color-convert": {
|
||||
"version": "1.9.3",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
|
||||
"integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
|
||||
"dependencies": {
|
||||
"color-name": "1.1.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/highlight/node_modules/color-name": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
|
||||
"integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw=="
|
||||
},
|
||||
"node_modules/@babel/highlight/node_modules/escape-string-regexp": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
|
||||
"integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
|
||||
"engines": {
|
||||
"node": ">=0.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/highlight/node_modules/has-flag": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
|
||||
"integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/highlight/node_modules/supports-color": {
|
||||
"version": "5.5.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
|
||||
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
|
||||
"dependencies": {
|
||||
"has-flag": "^3.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/parser": {
|
||||
"version": "7.24.4",
|
||||
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.4.tgz",
|
||||
"integrity": "sha512-zTvEBcghmeBma9QIGunWevvBAp4/Qu9Bdq+2k0Ot4fVMD6v3dsC9WOcRSKk7tRRyBM/53yKMJko9xOatGQAwSg==",
|
||||
"bin": {
|
||||
"parser": "bin/babel-parser.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-syntax-jsx": {
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.24.1.tgz",
|
||||
"integrity": "sha512-2eCtxZXf+kbkMIsXS4poTvT4Yu5rXiRa+9xGVT56raghjmBTKMpFNc9R4IDiB4emao9eO22Ox7CxuJG7BgExqA==",
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.24.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@babel/core": "^7.0.0-0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/runtime": {
|
||||
"version": "7.24.4",
|
||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.4.tgz",
|
||||
|
@ -83,6 +470,83 @@
|
|||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/template": {
|
||||
"version": "7.24.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.0.tgz",
|
||||
"integrity": "sha512-Bkf2q8lMB0AFpX0NFEqSbx1OkTHf0f+0j82mkw+ZpzBnkk7e9Ql0891vlfgi+kHwOk8tQjiQHpqh4LaSa0fKEA==",
|
||||
"dependencies": {
|
||||
"@babel/code-frame": "^7.23.5",
|
||||
"@babel/parser": "^7.24.0",
|
||||
"@babel/types": "^7.24.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/traverse": {
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.1.tgz",
|
||||
"integrity": "sha512-xuU6o9m68KeqZbQuDt2TcKSxUw/mrsvavlEqQ1leZ/B+C9tk6E4sRWy97WaXgvq5E+nU3cXMxv3WKOCanVMCmQ==",
|
||||
"dependencies": {
|
||||
"@babel/code-frame": "^7.24.1",
|
||||
"@babel/generator": "^7.24.1",
|
||||
"@babel/helper-environment-visitor": "^7.22.20",
|
||||
"@babel/helper-function-name": "^7.23.0",
|
||||
"@babel/helper-hoist-variables": "^7.22.5",
|
||||
"@babel/helper-split-export-declaration": "^7.22.6",
|
||||
"@babel/parser": "^7.24.1",
|
||||
"@babel/types": "^7.24.0",
|
||||
"debug": "^4.3.1",
|
||||
"globals": "^11.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/traverse/node_modules/globals": {
|
||||
"version": "11.12.0",
|
||||
"resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz",
|
||||
"integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==",
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/types": {
|
||||
"version": "7.24.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.0.tgz",
|
||||
"integrity": "sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w==",
|
||||
"dependencies": {
|
||||
"@babel/helper-string-parser": "^7.23.4",
|
||||
"@babel/helper-validator-identifier": "^7.22.20",
|
||||
"to-fast-properties": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@emotion/is-prop-valid": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.2.2.tgz",
|
||||
"integrity": "sha512-uNsoYd37AFmaCdXlg6EYD1KaPOaRWRByMCYzbKUX4+hhMfrxdVSelShywL4JVaAeM/eHUOSprYBQls+/neX3pw==",
|
||||
"dependencies": {
|
||||
"@emotion/memoize": "^0.8.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@emotion/memoize": {
|
||||
"version": "0.8.1",
|
||||
"resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.1.tgz",
|
||||
"integrity": "sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA=="
|
||||
},
|
||||
"node_modules/@emotion/stylis": {
|
||||
"version": "0.8.5",
|
||||
"resolved": "https://registry.npmjs.org/@emotion/stylis/-/stylis-0.8.5.tgz",
|
||||
"integrity": "sha512-h6KtPihKFn3T9fuIrwvXXUOwlx3rfUvfZIcP5a6rh8Y7zjE3O06hT5Ss4S/YI1AYhuZ1kjaE/5EaOOI2NqSylQ=="
|
||||
},
|
||||
"node_modules/@emotion/unitless": {
|
||||
"version": "0.7.5",
|
||||
"resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.7.5.tgz",
|
||||
"integrity": "sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg=="
|
||||
},
|
||||
"node_modules/@eslint-community/eslint-utils": {
|
||||
"version": "4.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz",
|
||||
|
@ -583,6 +1047,36 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-collapsible": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-collapsible/-/react-collapsible-1.0.3.tgz",
|
||||
"integrity": "sha512-UBmVDkmR6IvDsloHVN+3rtx4Mi5TFvylYXpluuv0f37dtaz3H99bp8No0LGXRigVpl3UAT4l9j6bIchh42S/Gg==",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.13.10",
|
||||
"@radix-ui/primitive": "1.0.1",
|
||||
"@radix-ui/react-compose-refs": "1.0.1",
|
||||
"@radix-ui/react-context": "1.0.1",
|
||||
"@radix-ui/react-id": "1.0.1",
|
||||
"@radix-ui/react-presence": "1.0.1",
|
||||
"@radix-ui/react-primitive": "1.0.3",
|
||||
"@radix-ui/react-use-controllable-state": "1.0.1",
|
||||
"@radix-ui/react-use-layout-effect": "1.0.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"@types/react-dom": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0",
|
||||
"react-dom": "^16.8 || ^17.0 || ^18.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
},
|
||||
"@types/react-dom": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-collection": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.0.3.tgz",
|
||||
|
@ -1953,6 +2447,14 @@
|
|||
"integrity": "sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/attr-accept": {
|
||||
"version": "2.2.2",
|
||||
"resolved": "https://registry.npmjs.org/attr-accept/-/attr-accept-2.2.2.tgz",
|
||||
"integrity": "sha512-7prDjvt9HmqiZ0cl5CRjtS84sEyhsHP2coDkaZKRKVfCDo9s7iw7ChVmar78Gu9pC4SoR/28wFu/G5JJhTnqEg==",
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/autoprefixer": {
|
||||
"version": "10.4.19",
|
||||
"resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.19.tgz",
|
||||
|
@ -2023,6 +2525,21 @@
|
|||
"dequal": "^2.0.3"
|
||||
}
|
||||
},
|
||||
"node_modules/babel-plugin-styled-components": {
|
||||
"version": "2.1.4",
|
||||
"resolved": "https://registry.npmjs.org/babel-plugin-styled-components/-/babel-plugin-styled-components-2.1.4.tgz",
|
||||
"integrity": "sha512-Xgp9g+A/cG47sUyRwwYxGM4bR/jDRg5N6it/8+HxCnbT5XNKSKDT9xm4oag/osgqjC2It/vH0yXsomOG6k558g==",
|
||||
"dependencies": {
|
||||
"@babel/helper-annotate-as-pure": "^7.22.5",
|
||||
"@babel/helper-module-imports": "^7.22.5",
|
||||
"@babel/plugin-syntax-jsx": "^7.22.5",
|
||||
"lodash": "^4.17.21",
|
||||
"picomatch": "^2.3.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"styled-components": ">= 2"
|
||||
}
|
||||
},
|
||||
"node_modules/balanced-match": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
||||
|
@ -2064,7 +2581,6 @@
|
|||
"version": "4.23.0",
|
||||
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.0.tgz",
|
||||
"integrity": "sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "opencollective",
|
||||
|
@ -2139,6 +2655,14 @@
|
|||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/camelize": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/camelize/-/camelize-1.0.1.tgz",
|
||||
"integrity": "sha512-dU+Tx2fsypxTgtLoE36npi3UqcjSSMNYfkqgmoEhtZrraP5VWq0K7FkWVTYa8eMPtnU/G2txVsfdCJTn9uzpuQ==",
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/caniuse-lite": {
|
||||
"version": "1.0.30001608",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001608.tgz",
|
||||
|
@ -2283,6 +2807,12 @@
|
|||
"integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/convert-source-map": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz",
|
||||
"integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/cross-spawn": {
|
||||
"version": "7.0.3",
|
||||
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
|
||||
|
@ -2296,6 +2826,24 @@
|
|||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/css-color-keywords": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/css-color-keywords/-/css-color-keywords-1.0.0.tgz",
|
||||
"integrity": "sha512-FyyrDHZKEjXDpNJYvVsV960FiqQyXc/LlYmsxl2BcdMb2WPx0OGRVgTg55rPSyLSNMqP52R9r8geSp7apN3Ofg==",
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/css-to-react-native": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/css-to-react-native/-/css-to-react-native-3.2.0.tgz",
|
||||
"integrity": "sha512-e8RKaLXMOFii+02mOlqwjbD00KSEKqblnpO9e++1aXS1fPQOpS1YoqdVHBqPjHNoxeF2mimzVqawm2KCbEdtHQ==",
|
||||
"dependencies": {
|
||||
"camelize": "^1.0.0",
|
||||
"css-color-keywords": "^1.0.0",
|
||||
"postcss-value-parser": "^4.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/cssesc": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
|
||||
|
@ -2383,7 +2931,6 @@
|
|||
"version": "4.3.4",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
|
||||
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"ms": "2.1.2"
|
||||
},
|
||||
|
@ -2492,8 +3039,7 @@
|
|||
"node_modules/electron-to-chromium": {
|
||||
"version": "1.4.733",
|
||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.733.tgz",
|
||||
"integrity": "sha512-gUI9nhI2iBGF0OaYYLKOaOtliFMl+Bt1rY7VmEjwxOxqoYLub/D9xmduPEhbw2imE6gYkJKhIE5it+KE2ulVxQ==",
|
||||
"dev": true
|
||||
"integrity": "sha512-gUI9nhI2iBGF0OaYYLKOaOtliFMl+Bt1rY7VmEjwxOxqoYLub/D9xmduPEhbw2imE6gYkJKhIE5it+KE2ulVxQ=="
|
||||
},
|
||||
"node_modules/emoji-regex": {
|
||||
"version": "9.2.2",
|
||||
|
@ -2675,7 +3221,6 @@
|
|||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz",
|
||||
"integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
|
@ -3168,6 +3713,17 @@
|
|||
"node": "^10.12.0 || >=12.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/file-selector": {
|
||||
"version": "0.6.0",
|
||||
"resolved": "https://registry.npmjs.org/file-selector/-/file-selector-0.6.0.tgz",
|
||||
"integrity": "sha512-QlZ5yJC0VxHxQQsQhXvBaC7VRJ2uaxTf+Tfpu4Z/OcVQJVpZO+DGU0rkoVW5ce2SccxugvpBJoMvUs59iILYdw==",
|
||||
"dependencies": {
|
||||
"tslib": "^2.4.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 12"
|
||||
}
|
||||
},
|
||||
"node_modules/fill-range": {
|
||||
"version": "7.0.1",
|
||||
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
|
||||
|
@ -3306,6 +3862,15 @@
|
|||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/gensync": {
|
||||
"version": "1.0.0-beta.2",
|
||||
"resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
|
||||
"integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/get-intrinsic": {
|
||||
"version": "1.2.4",
|
||||
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz",
|
||||
|
@ -3569,6 +4134,14 @@
|
|||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/hoist-non-react-statics": {
|
||||
"version": "3.3.2",
|
||||
"resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz",
|
||||
"integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==",
|
||||
"dependencies": {
|
||||
"react-is": "^16.7.0"
|
||||
}
|
||||
},
|
||||
"node_modules/ignore": {
|
||||
"version": "5.3.1",
|
||||
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz",
|
||||
|
@ -4068,6 +4641,17 @@
|
|||
"js-yaml": "bin/js-yaml.js"
|
||||
}
|
||||
},
|
||||
"node_modules/jsesc": {
|
||||
"version": "2.5.2",
|
||||
"resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz",
|
||||
"integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==",
|
||||
"bin": {
|
||||
"jsesc": "bin/jsesc"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/json-buffer": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz",
|
||||
|
@ -4181,6 +4765,11 @@
|
|||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/lodash": {
|
||||
"version": "4.17.21",
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
||||
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
|
||||
},
|
||||
"node_modules/lodash.merge": {
|
||||
"version": "4.6.2",
|
||||
"resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
|
||||
|
@ -4266,8 +4855,7 @@
|
|||
"node_modules/ms": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
|
||||
"dev": true
|
||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
|
||||
},
|
||||
"node_modules/mz": {
|
||||
"version": "2.7.0",
|
||||
|
@ -4386,8 +4974,7 @@
|
|||
"node_modules/node-releases": {
|
||||
"version": "2.0.14",
|
||||
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz",
|
||||
"integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==",
|
||||
"dev": true
|
||||
"integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw=="
|
||||
},
|
||||
"node_modules/normalize-path": {
|
||||
"version": "3.0.0",
|
||||
|
@ -4856,7 +5443,6 @@
|
|||
"version": "15.8.1",
|
||||
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
|
||||
"integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"loose-envify": "^1.4.0",
|
||||
"object-assign": "^4.1.1",
|
||||
|
@ -4914,6 +5500,35 @@
|
|||
"react": "^18.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-drag-drop-files": {
|
||||
"version": "2.3.10",
|
||||
"resolved": "https://registry.npmjs.org/react-drag-drop-files/-/react-drag-drop-files-2.3.10.tgz",
|
||||
"integrity": "sha512-Fv614W9+OtXFB5O+gjompTxQZLYGO7wJeT4paETGiXtiADB9yPOMGYD4A3PMCTY9Be874/wcpl+2dm3MvCIRzg==",
|
||||
"dependencies": {
|
||||
"prop-types": "^15.7.2",
|
||||
"styled-components": "^5.3.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^18.0.0",
|
||||
"react-dom": "^18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-dropzone": {
|
||||
"version": "14.2.3",
|
||||
"resolved": "https://registry.npmjs.org/react-dropzone/-/react-dropzone-14.2.3.tgz",
|
||||
"integrity": "sha512-O3om8I+PkFKbxCukfIR3QAGftYXDZfOE2N1mr/7qebQJHs7U+/RSL/9xomJNpRg9kM5h9soQSdf0Gc7OHF5Fug==",
|
||||
"dependencies": {
|
||||
"attr-accept": "^2.2.2",
|
||||
"file-selector": "^0.6.0",
|
||||
"prop-types": "^15.8.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 10.13"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">= 16.8 || 18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-hook-form": {
|
||||
"version": "7.51.3",
|
||||
"resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.51.3.tgz",
|
||||
|
@ -4932,8 +5547,7 @@
|
|||
"node_modules/react-is": {
|
||||
"version": "16.13.1",
|
||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
||||
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
|
||||
"dev": true
|
||||
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
|
||||
},
|
||||
"node_modules/react-remove-scroll": {
|
||||
"version": "2.5.5",
|
||||
|
@ -5276,6 +5890,11 @@
|
|||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/shallowequal": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz",
|
||||
"integrity": "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ=="
|
||||
},
|
||||
"node_modules/shebang-command": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
|
||||
|
@ -5528,6 +6147,54 @@
|
|||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/styled-components": {
|
||||
"version": "5.3.11",
|
||||
"resolved": "https://registry.npmjs.org/styled-components/-/styled-components-5.3.11.tgz",
|
||||
"integrity": "sha512-uuzIIfnVkagcVHv9nE0VPlHPSCmXIUGKfJ42LNjxCCTDTL5sgnJ8Z7GZBq0EnLYGln77tPpEpExt2+qa+cZqSw==",
|
||||
"dependencies": {
|
||||
"@babel/helper-module-imports": "^7.0.0",
|
||||
"@babel/traverse": "^7.4.5",
|
||||
"@emotion/is-prop-valid": "^1.1.0",
|
||||
"@emotion/stylis": "^0.8.4",
|
||||
"@emotion/unitless": "^0.7.4",
|
||||
"babel-plugin-styled-components": ">= 1.12.0",
|
||||
"css-to-react-native": "^3.0.0",
|
||||
"hoist-non-react-statics": "^3.0.0",
|
||||
"shallowequal": "^1.1.0",
|
||||
"supports-color": "^5.5.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/styled-components"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">= 16.8.0",
|
||||
"react-dom": ">= 16.8.0",
|
||||
"react-is": ">= 16.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/styled-components/node_modules/has-flag": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
|
||||
"integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/styled-components/node_modules/supports-color": {
|
||||
"version": "5.5.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
|
||||
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
|
||||
"dependencies": {
|
||||
"has-flag": "^3.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/styled-jsx": {
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.1.tgz",
|
||||
|
@ -5684,6 +6351,14 @@
|
|||
"node": ">=0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/to-fast-properties": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
|
||||
"integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==",
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/to-regex-range": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
|
||||
|
@ -5864,7 +6539,6 @@
|
|||
"version": "1.0.13",
|
||||
"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz",
|
||||
"integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "opencollective",
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
"@hookform/resolvers": "^3.3.4",
|
||||
"@radix-ui/react-avatar": "^1.0.4",
|
||||
"@radix-ui/react-checkbox": "^1.0.4",
|
||||
"@radix-ui/react-collapsible": "^1.0.3",
|
||||
"@radix-ui/react-dialog": "^1.0.5",
|
||||
"@radix-ui/react-dropdown-menu": "^2.0.6",
|
||||
"@radix-ui/react-hover-card": "^1.0.7",
|
||||
|
@ -35,6 +36,8 @@
|
|||
"next-themes": "^0.3.0",
|
||||
"react": "^18",
|
||||
"react-dom": "^18",
|
||||
"react-drag-drop-files": "^2.3.10",
|
||||
"react-dropzone": "^14.2.3",
|
||||
"react-hook-form": "^7.51.3",
|
||||
"react-resizable-panels": "^2.0.16",
|
||||
"tailwind-merge": "^2.2.2",
|
||||
|
|
|
@ -0,0 +1,126 @@
|
|||
"use client";
|
||||
|
||||
import { Step, type StepItem, Stepper } from "@/components/stepper";
|
||||
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Card } from "@/components/ui/card";
|
||||
import { ArrowRight, X } from "lucide-react";
|
||||
import Image from "next/image";
|
||||
import { useCallback, useState } from "react";
|
||||
// import { FileUploader } from "react-drag-drop-files";
|
||||
import { useDropzone } from "react-dropzone";
|
||||
|
||||
const steps = [
|
||||
{ label: "Upload extraction.zip" },
|
||||
{ label: "Result of analysis" },
|
||||
{ label: "Course recommendation" },
|
||||
] satisfies StepItem[];
|
||||
|
||||
// const fileTypes = ["JPEG", "PNG", "GIF"];
|
||||
const Page = () => {
|
||||
const [uploadedFiles, setUploadedFiles] = useState<
|
||||
{ file: File; preview: string; size: string }[]
|
||||
>([]);
|
||||
// const [uploadedFiles, setUploadedFiles] = useState<File[]>([]);
|
||||
// const [preview, setPreview] = useState<(string | ArrayBuffer | null)[]>([]);
|
||||
|
||||
const onDrop = useCallback((acceptedFiles: Array<File>) => {
|
||||
console.log(acceptedFiles);
|
||||
console.log(acceptedFiles[0].size / 1024);
|
||||
|
||||
acceptedFiles.forEach((f) => {
|
||||
const file = new FileReader();
|
||||
|
||||
file.onload = function () {
|
||||
let fileSize = "";
|
||||
|
||||
if (f.size < 1024) {
|
||||
// File size is less than 1KB
|
||||
fileSize = `${f.size} bytes`;
|
||||
} else if (f.size < 1024 * 1024) {
|
||||
// File size is less than 1MB
|
||||
fileSize = `${(f.size / 1024).toFixed(2)} kb`;
|
||||
} else {
|
||||
// File size is in MB
|
||||
fileSize = `${(f.size / (1024 * 1024)).toFixed(2)} mb`;
|
||||
}
|
||||
|
||||
setUploadedFiles((uploadFile) => [
|
||||
...uploadFile,
|
||||
{ file: f, preview: file.result as string, size: fileSize },
|
||||
]);
|
||||
};
|
||||
|
||||
file.readAsDataURL(f);
|
||||
});
|
||||
}, []);
|
||||
|
||||
const { getRootProps, getInputProps } = useDropzone({
|
||||
onDrop,
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="flex-1 space-y-8 p-4 md:p-8 pt-6 md:pt-10">
|
||||
<div className="flex w-full flex-col gap-4">
|
||||
<Stepper initialStep={0} steps={steps} variant="circle-alt">
|
||||
{steps.map((stepProps, index) => {
|
||||
return <Step key={stepProps.label} {...stepProps}></Step>;
|
||||
})}
|
||||
</Stepper>
|
||||
</div>
|
||||
|
||||
<Alert className="py-6 space-y-2 bg-secondary">
|
||||
<AlertTitle className="text-xl font-bold">Please upload the extraction.zip file</AlertTitle>
|
||||
<AlertDescription>
|
||||
You should have a script that creates it.
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
|
||||
<div
|
||||
{...getRootProps()}
|
||||
className="border border-dashed min-h-40 rounded-md relative cursor-pointer p-4"
|
||||
>
|
||||
<input {...getInputProps()} />
|
||||
<div className="flex gap-4 flex-wrap">
|
||||
{uploadedFiles.length !== 0 ? (
|
||||
uploadedFiles.map((f, i) => (
|
||||
<div key={i} className="w-28 h-full">
|
||||
<div className="relative w-28 h-28">
|
||||
<Image
|
||||
src={(f.preview || "") as string}
|
||||
alt=""
|
||||
fill
|
||||
className="object-cover rounded"
|
||||
/>
|
||||
<button
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
setUploadedFiles((files) => {
|
||||
return files.filter(
|
||||
(file) => file.file.name !== f.file.name
|
||||
);
|
||||
});
|
||||
}}
|
||||
className="absolute top-1 right-1 p-1 bg-background rounded-md text-foreground"
|
||||
>
|
||||
<X className="size-4 text-rose-100" />
|
||||
</button>
|
||||
</div>
|
||||
<p className="truncate">{f.file.name}</p>
|
||||
<p className="text-sm text-muted-foreground">{f.size}</p>
|
||||
</div>
|
||||
))
|
||||
) : (
|
||||
<p className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2">
|
||||
Drag and drop files here or click to browse.
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Button size="lg" className="inline-flex items-center gap-2"> <ArrowRight/> Start Analysis</Button>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Page;
|
|
@ -0,0 +1,78 @@
|
|||
import * as React from "react"
|
||||
import type { StepperProps } from "./types"
|
||||
|
||||
interface StepperContextValue extends StepperProps {
|
||||
clickable?: boolean
|
||||
isError?: boolean
|
||||
isLoading?: boolean
|
||||
isVertical?: boolean
|
||||
stepCount?: number
|
||||
expandVerticalSteps?: boolean
|
||||
activeStep: number
|
||||
initialStep: number
|
||||
}
|
||||
|
||||
type StepperContextProviderProps = {
|
||||
value: Omit<StepperContextValue, "activeStep">
|
||||
children: React.ReactNode
|
||||
}
|
||||
|
||||
const StepperContext = React.createContext<
|
||||
StepperContextValue & {
|
||||
nextStep: () => void
|
||||
prevStep: () => void
|
||||
resetSteps: () => void
|
||||
setStep: (step: number) => void
|
||||
}
|
||||
>({
|
||||
steps: [],
|
||||
activeStep: 0,
|
||||
initialStep: 0,
|
||||
nextStep: () => {},
|
||||
prevStep: () => {},
|
||||
resetSteps: () => {},
|
||||
setStep: () => {},
|
||||
})
|
||||
|
||||
|
||||
const StepperProvider = ({ value, children }: StepperContextProviderProps) => {
|
||||
const isError = value.state === "error"
|
||||
const isLoading = value.state === "loading"
|
||||
|
||||
const [activeStep, setActiveStep] = React.useState(value.initialStep)
|
||||
|
||||
const nextStep = () => {
|
||||
setActiveStep((prev) => prev + 1)
|
||||
}
|
||||
|
||||
const prevStep = () => {
|
||||
setActiveStep((prev) => prev - 1)
|
||||
}
|
||||
|
||||
const resetSteps = () => {
|
||||
setActiveStep(value.initialStep)
|
||||
}
|
||||
|
||||
const setStep = (step: number) => {
|
||||
setActiveStep(step)
|
||||
}
|
||||
|
||||
return (
|
||||
<StepperContext.Provider
|
||||
value={{
|
||||
...value,
|
||||
isError,
|
||||
isLoading,
|
||||
activeStep,
|
||||
nextStep,
|
||||
prevStep,
|
||||
resetSteps,
|
||||
setStep,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</StepperContext.Provider>
|
||||
)
|
||||
}
|
||||
|
||||
export { StepperContext, StepperProvider }
|
|
@ -0,0 +1,114 @@
|
|||
/* eslint-disable react/display-name */
|
||||
import { cn } from "@/lib/utils";
|
||||
import * as React from "react";
|
||||
import { StepButtonContainer } from "./step-button-container";
|
||||
import { StepIcon } from "./step-icon";
|
||||
import { StepLabel } from "./step-label";
|
||||
import type { StepSharedProps } from "./types";
|
||||
import { useStepper } from "./use-stepper";
|
||||
|
||||
const HorizontalStep = React.forwardRef<HTMLDivElement, StepSharedProps>(
|
||||
(props, ref) => {
|
||||
const {
|
||||
isError,
|
||||
isLoading,
|
||||
onClickStep,
|
||||
variant,
|
||||
clickable,
|
||||
checkIcon: checkIconContext,
|
||||
errorIcon: errorIconContext,
|
||||
styles,
|
||||
steps,
|
||||
setStep,
|
||||
} = useStepper();
|
||||
|
||||
const {
|
||||
index,
|
||||
isCompletedStep,
|
||||
isCurrentStep,
|
||||
hasVisited,
|
||||
icon,
|
||||
label,
|
||||
description,
|
||||
isKeepError,
|
||||
state,
|
||||
checkIcon: checkIconProp,
|
||||
errorIcon: errorIconProp,
|
||||
} = props;
|
||||
|
||||
const localIsLoading = isLoading || state === "loading";
|
||||
const localIsError = isError || state === "error";
|
||||
|
||||
const opacity = hasVisited ? 1 : 0.8;
|
||||
|
||||
const active =
|
||||
variant === "line" ? isCompletedStep || isCurrentStep : isCompletedStep;
|
||||
|
||||
const checkIcon = checkIconProp || checkIconContext;
|
||||
const errorIcon = errorIconProp || errorIconContext;
|
||||
|
||||
return (
|
||||
<div
|
||||
aria-disabled={!hasVisited}
|
||||
className={cn(
|
||||
"stepper__horizontal-step",
|
||||
"flex items-center relative transition-all duration-200",
|
||||
"[&:not(:last-child)]:flex-1",
|
||||
"[&:not(:last-child)]:after:transition-all [&:not(:last-child)]:after:duration-200",
|
||||
"[&:not(:last-child)]:after:content-[''] [&:not(:last-child)]:after:h-[2px] [&:not(:last-child)]:after:bg-border",
|
||||
"data-[completed=true]:[&:not(:last-child)]:after:bg-primary",
|
||||
"data-[invalid=true]:[&:not(:last-child)]:after:bg-destructive",
|
||||
variant === "circle-alt" &&
|
||||
"justify-start flex-col flex-1 [&:not(:last-child)]:after:relative [&:not(:last-child)]:after:order-[-1] [&:not(:last-child)]:after:start-[50%] [&:not(:last-child)]:after:end-[50%] [&:not(:last-child)]:after:top-[calc(var(--step-icon-size)/2)] [&:not(:last-child)]:after:w-[calc((100%-var(--step-icon-size))-(var(--step-gap)))]",
|
||||
variant === "circle" &&
|
||||
"[&:not(:last-child)]:after:flex-1 [&:not(:last-child)]:after:ms-[var(--step-gap)] [&:not(:last-child)]:after:me-[var(--step-gap)]",
|
||||
variant === "line" &&
|
||||
"flex-col flex-1 border-t-[3px] data-[active=true]:border-primary",
|
||||
styles?.["horizontal-step"],
|
||||
)}
|
||||
data-optional={steps[index || 0]?.optional}
|
||||
data-completed={isCompletedStep}
|
||||
data-active={active}
|
||||
data-invalid={localIsError}
|
||||
data-clickable={clickable}
|
||||
onClick={() => onClickStep?.(index || 0, setStep)}
|
||||
ref={ref}
|
||||
>
|
||||
<div
|
||||
className={cn(
|
||||
"stepper__horizontal-step-container",
|
||||
"flex items-center",
|
||||
variant === "circle-alt" && "flex-col justify-center gap-1",
|
||||
variant === "line" && "w-full",
|
||||
styles?.["horizontal-step-container"],
|
||||
)}
|
||||
>
|
||||
<StepButtonContainer
|
||||
{...{ ...props, isError: localIsError, isLoading: localIsLoading }}
|
||||
>
|
||||
<StepIcon
|
||||
{...{
|
||||
index,
|
||||
isCompletedStep,
|
||||
isCurrentStep,
|
||||
isError: localIsError,
|
||||
isKeepError,
|
||||
isLoading: localIsLoading,
|
||||
}}
|
||||
icon={icon}
|
||||
checkIcon={checkIcon}
|
||||
errorIcon={errorIcon}
|
||||
/>
|
||||
</StepButtonContainer>
|
||||
<StepLabel
|
||||
label={label}
|
||||
description={description}
|
||||
{...{ isCurrentStep, opacity }}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
export { HorizontalStep };
|
|
@ -0,0 +1,184 @@
|
|||
/* eslint-disable react/display-name */
|
||||
"use client";
|
||||
|
||||
import { cn } from "@/lib/utils";
|
||||
import * as React from "react";
|
||||
import { StepperProvider } from "./context";
|
||||
import { Step } from "./step";
|
||||
import type { StepItem, StepProps, StepperProps } from "./types";
|
||||
import { useMediaQuery } from "./use-media-query";
|
||||
import { useStepper } from "./use-stepper";
|
||||
|
||||
const VARIABLE_SIZES = {
|
||||
sm: "36px",
|
||||
md: "40px",
|
||||
lg: "44px",
|
||||
};
|
||||
|
||||
const Stepper = React.forwardRef<HTMLDivElement, StepperProps>(
|
||||
(props, ref: React.Ref<HTMLDivElement>) => {
|
||||
const {
|
||||
className,
|
||||
children,
|
||||
orientation: orientationProp,
|
||||
state,
|
||||
responsive,
|
||||
checkIcon,
|
||||
errorIcon,
|
||||
onClickStep,
|
||||
mobileBreakpoint,
|
||||
expandVerticalSteps = false,
|
||||
initialStep = 0,
|
||||
size,
|
||||
steps,
|
||||
variant,
|
||||
styles,
|
||||
variables,
|
||||
scrollTracking = false,
|
||||
...rest
|
||||
} = props;
|
||||
|
||||
const childArr = React.Children.toArray(children);
|
||||
|
||||
const items = [] as React.ReactElement[];
|
||||
|
||||
const footer = childArr.map((child, _index) => {
|
||||
if (!React.isValidElement(child)) {
|
||||
throw new Error("Stepper children must be valid React elements.");
|
||||
}
|
||||
if (child.type === Step) {
|
||||
items.push(child);
|
||||
return null;
|
||||
}
|
||||
|
||||
return child;
|
||||
});
|
||||
|
||||
const stepCount = items.length;
|
||||
|
||||
const isMobile = useMediaQuery(
|
||||
`(max-width: ${mobileBreakpoint || "768px"})`,
|
||||
);
|
||||
|
||||
const clickable = !!onClickStep;
|
||||
|
||||
const orientation = isMobile && responsive ? "vertical" : orientationProp;
|
||||
|
||||
const isVertical = orientation === "vertical";
|
||||
|
||||
return (
|
||||
<StepperProvider
|
||||
value={{
|
||||
initialStep,
|
||||
orientation,
|
||||
state,
|
||||
size,
|
||||
responsive,
|
||||
checkIcon,
|
||||
errorIcon,
|
||||
onClickStep,
|
||||
clickable,
|
||||
stepCount,
|
||||
isVertical,
|
||||
variant: variant || "circle",
|
||||
expandVerticalSteps,
|
||||
steps,
|
||||
scrollTracking,
|
||||
styles,
|
||||
}}
|
||||
>
|
||||
<div
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"stepper__main-container",
|
||||
"flex w-full flex-wrap",
|
||||
stepCount === 1 ? "justify-end" : "justify-between",
|
||||
orientation === "vertical" ? "flex-col" : "flex-row",
|
||||
variant === "line" && orientation === "horizontal" && "gap-4",
|
||||
className,
|
||||
styles?.["main-container"],
|
||||
)}
|
||||
style={
|
||||
{
|
||||
"--step-icon-size":
|
||||
variables?.["--step-icon-size"] ||
|
||||
`${VARIABLE_SIZES[size || "md"]}`,
|
||||
"--step-gap": variables?.["--step-gap"] || "8px",
|
||||
} as React.CSSProperties
|
||||
}
|
||||
{...rest}
|
||||
>
|
||||
<VerticalContent>{items}</VerticalContent>
|
||||
</div>
|
||||
{orientation === "horizontal" && (
|
||||
<HorizontalContent>{items}</HorizontalContent>
|
||||
)}
|
||||
{footer}
|
||||
</StepperProvider>
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
Stepper.defaultProps = {
|
||||
size: "md",
|
||||
orientation: "horizontal",
|
||||
responsive: true,
|
||||
};
|
||||
|
||||
const VerticalContent = ({ children }: { children: React.ReactNode }) => {
|
||||
const { activeStep } = useStepper();
|
||||
|
||||
const childArr = React.Children.toArray(children);
|
||||
const stepCount = childArr.length;
|
||||
|
||||
return (
|
||||
<>
|
||||
{React.Children.map(children, (child, i) => {
|
||||
const isCompletedStep =
|
||||
(React.isValidElement(child) &&
|
||||
(child.props as any).isCompletedStep) ??
|
||||
i < activeStep;
|
||||
const isLastStep = i === stepCount - 1;
|
||||
const isCurrentStep = i === activeStep;
|
||||
|
||||
const stepProps = {
|
||||
index: i,
|
||||
isCompletedStep,
|
||||
isCurrentStep,
|
||||
isLastStep,
|
||||
};
|
||||
|
||||
if (React.isValidElement(child)) {
|
||||
return React.cloneElement(child, stepProps);
|
||||
}
|
||||
return null;
|
||||
})}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const HorizontalContent = ({ children }: { children: React.ReactNode }) => {
|
||||
const { activeStep } = useStepper();
|
||||
const childArr = React.Children.toArray(children);
|
||||
|
||||
if (activeStep > childArr.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{React.Children.map(childArr[activeStep], (node) => {
|
||||
if (!React.isValidElement(node)) {
|
||||
return null;
|
||||
}
|
||||
return React.Children.map(
|
||||
node.props.children,
|
||||
(childNode) => childNode,
|
||||
);
|
||||
})}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export { Stepper, Step, useStepper };
|
||||
export type { StepProps, StepperProps, StepItem };
|
|
@ -0,0 +1,59 @@
|
|||
import { Button } from "@/components/ui/button";
|
||||
import { cn } from "@/lib/utils";
|
||||
import type { StepSharedProps } from "./types";
|
||||
import { useStepper } from "./use-stepper";
|
||||
|
||||
type StepButtonContainerProps = StepSharedProps & {
|
||||
children?: React.ReactNode;
|
||||
};
|
||||
|
||||
const StepButtonContainer = ({
|
||||
isCurrentStep,
|
||||
isCompletedStep,
|
||||
children,
|
||||
isError,
|
||||
isLoading: isLoadingProp,
|
||||
onClickStep,
|
||||
}: StepButtonContainerProps) => {
|
||||
const {
|
||||
clickable,
|
||||
isLoading: isLoadingContext,
|
||||
variant,
|
||||
styles,
|
||||
} = useStepper();
|
||||
|
||||
const currentStepClickable = clickable || !!onClickStep;
|
||||
|
||||
const isLoading = isLoadingProp || isLoadingContext;
|
||||
|
||||
if (variant === "line") {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<Button
|
||||
variant="ghost"
|
||||
className={cn(
|
||||
"stepper__step-button-container",
|
||||
"rounded-full p-0 pointer-events-none",
|
||||
"w-[var(--step-icon-size)] h-[var(--step-icon-size)]",
|
||||
"border-2 flex rounded-full justify-center items-center",
|
||||
"data-[clickable=true]:pointer-events-auto",
|
||||
"data-[active=true]:bg-primary data-[active=true]:border-primary data-[active=true]:text-primary-foreground",
|
||||
"data-[current=true]:border-primary data-[current=true]:bg-secondary",
|
||||
"data-[invalid=true]:bg-destructive data-[invalid=true]:border-destructive data-[invalid=true]:text-destructive-foreground",
|
||||
styles?.["step-button-container"],
|
||||
)}
|
||||
aria-current={isCurrentStep ? "step" : undefined}
|
||||
data-current={isCurrentStep}
|
||||
data-invalid={isError && (isCurrentStep || isCompletedStep)}
|
||||
data-active={isCompletedStep}
|
||||
data-clickable={currentStepClickable}
|
||||
data-loading={isLoading && (isCurrentStep || isCompletedStep)}
|
||||
>
|
||||
{children}
|
||||
</Button>
|
||||
);
|
||||
};
|
||||
|
||||
export { StepButtonContainer };
|
|
@ -0,0 +1,133 @@
|
|||
/* eslint-disable react/display-name */
|
||||
import { cn } from "@/lib/utils";
|
||||
import { cva } from "class-variance-authority";
|
||||
import { CheckIcon, Loader2, X } from "lucide-react";
|
||||
import * as React from "react";
|
||||
import type { IconType } from "./types";
|
||||
import { useStepper } from "./use-stepper";
|
||||
|
||||
interface StepIconProps {
|
||||
isCompletedStep?: boolean;
|
||||
isCurrentStep?: boolean;
|
||||
isError?: boolean;
|
||||
isLoading?: boolean;
|
||||
isKeepError?: boolean;
|
||||
icon?: IconType;
|
||||
index?: number;
|
||||
checkIcon?: IconType;
|
||||
errorIcon?: IconType;
|
||||
}
|
||||
|
||||
const iconVariants = cva("", {
|
||||
variants: {
|
||||
size: {
|
||||
sm: "size-4",
|
||||
md: "size-4",
|
||||
lg: "size-5",
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
size: "md",
|
||||
},
|
||||
});
|
||||
|
||||
const StepIcon = React.forwardRef<HTMLDivElement, StepIconProps>(
|
||||
(props, ref) => {
|
||||
const { size } = useStepper();
|
||||
|
||||
const {
|
||||
isCompletedStep,
|
||||
isCurrentStep,
|
||||
isError,
|
||||
isLoading,
|
||||
isKeepError,
|
||||
icon: CustomIcon,
|
||||
index,
|
||||
checkIcon: CustomCheckIcon,
|
||||
errorIcon: CustomErrorIcon,
|
||||
} = props;
|
||||
|
||||
const Icon = React.useMemo(
|
||||
() => (CustomIcon ? CustomIcon : null),
|
||||
[CustomIcon],
|
||||
);
|
||||
|
||||
const ErrorIcon = React.useMemo(
|
||||
() => (CustomErrorIcon ? CustomErrorIcon : null),
|
||||
[CustomErrorIcon],
|
||||
);
|
||||
|
||||
const Check = React.useMemo(
|
||||
() => (CustomCheckIcon ? CustomCheckIcon : CheckIcon),
|
||||
[CustomCheckIcon],
|
||||
);
|
||||
|
||||
return React.useMemo(() => {
|
||||
if (isCompletedStep) {
|
||||
if (isError && isKeepError) {
|
||||
return (
|
||||
<div key="icon">
|
||||
<X className={cn(iconVariants({ size }))} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<div key="check-icon">
|
||||
<Check className={cn(iconVariants({ size }))} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
if (isCurrentStep) {
|
||||
if (isError && ErrorIcon) {
|
||||
return (
|
||||
<div key="error-icon">
|
||||
<ErrorIcon className={cn(iconVariants({ size }))} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
if (isError) {
|
||||
return (
|
||||
<div key="icon">
|
||||
<X className={cn(iconVariants({ size }))} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
if (isLoading) {
|
||||
return (
|
||||
<Loader2 className={cn(iconVariants({ size }), "animate-spin")} />
|
||||
);
|
||||
}
|
||||
}
|
||||
if (Icon) {
|
||||
return (
|
||||
<div key="step-icon">
|
||||
<Icon className={cn(iconVariants({ size }))} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<span
|
||||
ref={ref}
|
||||
key="label"
|
||||
className={cn("font-medium text-center text-md")}
|
||||
>
|
||||
{(index || 0) + 1}
|
||||
</span>
|
||||
);
|
||||
}, [
|
||||
isCompletedStep,
|
||||
isCurrentStep,
|
||||
isError,
|
||||
isLoading,
|
||||
Icon,
|
||||
index,
|
||||
Check,
|
||||
ErrorIcon,
|
||||
isKeepError,
|
||||
ref,
|
||||
size,
|
||||
]);
|
||||
},
|
||||
);
|
||||
|
||||
export { StepIcon };
|
|
@ -0,0 +1,90 @@
|
|||
import { cn } from "@/lib/utils";
|
||||
import { cva } from "class-variance-authority";
|
||||
import { useStepper } from "./use-stepper";
|
||||
|
||||
interface StepLabelProps {
|
||||
isCurrentStep?: boolean;
|
||||
opacity: number;
|
||||
label?: string | React.ReactNode;
|
||||
description?: string | null;
|
||||
}
|
||||
|
||||
const labelVariants = cva("", {
|
||||
variants: {
|
||||
size: {
|
||||
sm: "text-sm",
|
||||
md: "text-sm",
|
||||
lg: "text-base",
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
size: "md",
|
||||
},
|
||||
});
|
||||
|
||||
const descriptionVariants = cva("", {
|
||||
variants: {
|
||||
size: {
|
||||
sm: "text-xs",
|
||||
md: "text-xs",
|
||||
lg: "text-sm",
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
size: "md",
|
||||
},
|
||||
});
|
||||
|
||||
const StepLabel = ({
|
||||
isCurrentStep,
|
||||
opacity,
|
||||
label,
|
||||
description,
|
||||
}: StepLabelProps) => {
|
||||
const { variant, styles, size, orientation } = useStepper();
|
||||
const shouldRender = !!label || !!description;
|
||||
|
||||
return shouldRender ? (
|
||||
<div
|
||||
aria-current={isCurrentStep ? "step" : undefined}
|
||||
className={cn(
|
||||
"stepper__step-label-container",
|
||||
"flex-col flex",
|
||||
variant !== "line" ? "ms-2" : orientation === "horizontal" && "my-2",
|
||||
variant === "circle-alt" && "text-center",
|
||||
variant === "circle-alt" && orientation === "horizontal" && "ms-0",
|
||||
variant === "circle-alt" && orientation === "vertical" && "text-start",
|
||||
styles?.["step-label-container"],
|
||||
)}
|
||||
style={{
|
||||
opacity,
|
||||
}}
|
||||
>
|
||||
{!!label && (
|
||||
<span
|
||||
className={cn(
|
||||
"stepper__step-label",
|
||||
labelVariants({ size }),
|
||||
styles?.["step-label"],
|
||||
)}
|
||||
>
|
||||
{label}
|
||||
</span>
|
||||
)}
|
||||
{!!description && (
|
||||
<span
|
||||
className={cn(
|
||||
"stepper__step-description",
|
||||
"text-muted-foreground",
|
||||
descriptionVariants({ size }),
|
||||
styles?.["step-description"],
|
||||
)}
|
||||
>
|
||||
{description}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
) : null;
|
||||
};
|
||||
|
||||
export { StepLabel };
|
|
@ -0,0 +1,76 @@
|
|||
/* eslint-disable react/display-name */
|
||||
import * as React from "react";
|
||||
import { HorizontalStep } from "./horizontal-step";
|
||||
import type { StepProps } from "./types";
|
||||
import { useStepper } from "./use-stepper";
|
||||
import { VerticalStep } from "./vertical-step";
|
||||
|
||||
// Props which shouldn't be passed to to the Step component from the user
|
||||
interface StepInternalConfig {
|
||||
index: number;
|
||||
isCompletedStep?: boolean;
|
||||
isCurrentStep?: boolean;
|
||||
isLastStep?: boolean;
|
||||
}
|
||||
|
||||
interface FullStepProps extends StepProps, StepInternalConfig {}
|
||||
|
||||
const Step = React.forwardRef<HTMLLIElement, StepProps>(
|
||||
(props, ref: React.Ref<any>) => {
|
||||
const {
|
||||
children,
|
||||
description,
|
||||
icon,
|
||||
state,
|
||||
checkIcon,
|
||||
errorIcon,
|
||||
index,
|
||||
isCompletedStep,
|
||||
isCurrentStep,
|
||||
isLastStep,
|
||||
isKeepError,
|
||||
label,
|
||||
onClickStep,
|
||||
} = props as FullStepProps;
|
||||
|
||||
const { isVertical, isError, isLoading, clickable } = useStepper();
|
||||
|
||||
const hasVisited = isCurrentStep || isCompletedStep;
|
||||
|
||||
const sharedProps = {
|
||||
isLastStep,
|
||||
isCompletedStep,
|
||||
isCurrentStep,
|
||||
index,
|
||||
isError,
|
||||
isLoading,
|
||||
clickable,
|
||||
label,
|
||||
description,
|
||||
hasVisited,
|
||||
icon,
|
||||
isKeepError,
|
||||
checkIcon,
|
||||
state,
|
||||
errorIcon,
|
||||
onClickStep,
|
||||
};
|
||||
|
||||
const renderStep = () => {
|
||||
switch (isVertical) {
|
||||
case true:
|
||||
return (
|
||||
<VerticalStep ref={ref} {...sharedProps}>
|
||||
{children}
|
||||
</VerticalStep>
|
||||
);
|
||||
default:
|
||||
return <HorizontalStep ref={ref} {...sharedProps} />;
|
||||
}
|
||||
};
|
||||
|
||||
return renderStep();
|
||||
},
|
||||
);
|
||||
|
||||
export { Step };
|
|
@ -0,0 +1,88 @@
|
|||
import type { LucideIcon } from "lucide-react";
|
||||
|
||||
type IconType = LucideIcon | React.ComponentType<any> | undefined;
|
||||
|
||||
type StepItem = {
|
||||
id?: string;
|
||||
label?: string;
|
||||
description?: string;
|
||||
icon?: IconType;
|
||||
optional?: boolean;
|
||||
};
|
||||
|
||||
interface StepOptions {
|
||||
orientation?: "vertical" | "horizontal";
|
||||
state?: "loading" | "error";
|
||||
responsive?: boolean;
|
||||
checkIcon?: IconType;
|
||||
errorIcon?: IconType;
|
||||
onClickStep?: (step: number, setStep: (step: number) => void) => void;
|
||||
mobileBreakpoint?: string;
|
||||
variant?: "circle" | "circle-alt" | "line";
|
||||
expandVerticalSteps?: boolean;
|
||||
size?: "sm" | "md" | "lg";
|
||||
styles?: {
|
||||
/** Styles for the main container */
|
||||
"main-container"?: string;
|
||||
/** Styles for the horizontal step */
|
||||
"horizontal-step"?: string;
|
||||
/** Styles for the horizontal step container (button and labels) */
|
||||
"horizontal-step-container"?: string;
|
||||
/** Styles for the vertical step */
|
||||
"vertical-step"?: string;
|
||||
/** Styles for the vertical step container (button and labels) */
|
||||
"vertical-step-container"?: string;
|
||||
/** Styles for the vertical step content */
|
||||
"vertical-step-content"?: string;
|
||||
/** Styles for the step button container */
|
||||
"step-button-container"?: string;
|
||||
/** Styles for the label and description container */
|
||||
"step-label-container"?: string;
|
||||
/** Styles for the step label */
|
||||
"step-label"?: string;
|
||||
/** Styles for the step description */
|
||||
"step-description"?: string;
|
||||
};
|
||||
variables?: {
|
||||
"--step-icon-size"?: string;
|
||||
"--step-gap"?: string;
|
||||
};
|
||||
scrollTracking?: boolean;
|
||||
}
|
||||
|
||||
interface StepperProps extends StepOptions {
|
||||
children?: React.ReactNode;
|
||||
className?: string;
|
||||
initialStep: number;
|
||||
steps: StepItem[];
|
||||
}
|
||||
|
||||
interface StepProps extends React.HTMLAttributes<HTMLLIElement> {
|
||||
label?: string | React.ReactNode;
|
||||
description?: string;
|
||||
icon?: IconType;
|
||||
state?: "loading" | "error";
|
||||
checkIcon?: IconType;
|
||||
errorIcon?: IconType;
|
||||
isCompletedStep?: boolean;
|
||||
isKeepError?: boolean;
|
||||
onClickStep?: (step: number, setStep: (step: number) => void) => void;
|
||||
}
|
||||
|
||||
interface StepSharedProps extends StepProps {
|
||||
isLastStep?: boolean;
|
||||
isCurrentStep?: boolean;
|
||||
index?: number;
|
||||
hasVisited: boolean | undefined;
|
||||
isError?: boolean;
|
||||
isLoading?: boolean;
|
||||
}
|
||||
|
||||
export type {
|
||||
IconType,
|
||||
StepItem,
|
||||
StepOptions,
|
||||
StepperProps,
|
||||
StepProps,
|
||||
StepSharedProps,
|
||||
};
|
|
@ -0,0 +1,19 @@
|
|||
import * as React from "react";
|
||||
|
||||
export function useMediaQuery(query: string) {
|
||||
const [value, setValue] = React.useState(false);
|
||||
|
||||
React.useEffect(() => {
|
||||
function onChange(event: MediaQueryListEvent) {
|
||||
setValue(event.matches);
|
||||
}
|
||||
|
||||
const result = matchMedia(query);
|
||||
result.addEventListener("change", onChange);
|
||||
setValue(result.matches);
|
||||
|
||||
return () => result.removeEventListener("change", onChange);
|
||||
}, [query]);
|
||||
|
||||
return value;
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
import * as React from "react";
|
||||
import { StepperContext } from "./context";
|
||||
|
||||
function usePrevious<T>(value: T): T | undefined {
|
||||
const ref = React.useRef<T>();
|
||||
|
||||
React.useEffect(() => {
|
||||
ref.current = value;
|
||||
}, [value]);
|
||||
|
||||
return ref.current;
|
||||
}
|
||||
|
||||
export function useStepper() {
|
||||
const context = React.useContext(StepperContext);
|
||||
|
||||
if (context === undefined) {
|
||||
throw new Error("useStepper must be used within a StepperProvider");
|
||||
}
|
||||
|
||||
const { children, className, ...rest } = context;
|
||||
|
||||
const isLastStep = context.activeStep === context.steps.length - 1;
|
||||
const hasCompletedAllSteps = context.activeStep === context.steps.length;
|
||||
|
||||
const previousActiveStep = usePrevious(context.activeStep);
|
||||
|
||||
const currentStep = context.steps[context.activeStep];
|
||||
const isOptionalStep = !!currentStep?.optional;
|
||||
|
||||
const isDisabledStep = context.activeStep === 0;
|
||||
|
||||
return {
|
||||
...rest,
|
||||
isLastStep,
|
||||
hasCompletedAllSteps,
|
||||
isOptionalStep,
|
||||
isDisabledStep,
|
||||
currentStep,
|
||||
previousActiveStep,
|
||||
};
|
||||
}
|
|
@ -0,0 +1,189 @@
|
|||
/* eslint-disable react/display-name */
|
||||
import { Collapsible, CollapsibleContent } from "@/components/ui/collapsible";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { cva } from "class-variance-authority";
|
||||
import * as React from "react";
|
||||
import { StepButtonContainer } from "./step-button-container";
|
||||
import { StepIcon } from "./step-icon";
|
||||
import { StepLabel } from "./step-label";
|
||||
import type { StepSharedProps } from "./types";
|
||||
import { useStepper } from "./use-stepper";
|
||||
|
||||
type VerticalStepProps = StepSharedProps & {
|
||||
children?: React.ReactNode;
|
||||
};
|
||||
|
||||
const verticalStepVariants = cva(
|
||||
[
|
||||
"flex flex-col relative transition-all duration-200",
|
||||
"data-[completed=true]:[&:not(:last-child)]:after:bg-primary",
|
||||
"data-[invalid=true]:[&:not(:last-child)]:after:bg-destructive",
|
||||
],
|
||||
{
|
||||
variants: {
|
||||
variant: {
|
||||
circle: cn(
|
||||
"[&:not(:last-child)]:pb-[var(--step-gap)] [&:not(:last-child)]:gap-[var(--step-gap)]",
|
||||
"[&:not(:last-child)]:after:content-[''] [&:not(:last-child)]:after:w-[2px] [&:not(:last-child)]:after:bg-border",
|
||||
"[&:not(:last-child)]:after:inset-x-[calc(var(--step-icon-size)/2)]",
|
||||
"[&:not(:last-child)]:after:absolute",
|
||||
"[&:not(:last-child)]:after:top-[calc(var(--step-icon-size)+var(--step-gap))]",
|
||||
"[&:not(:last-child)]:after:bottom-[var(--step-gap)]",
|
||||
"[&:not(:last-child)]:after:transition-all [&:not(:last-child)]:after:duration-200",
|
||||
),
|
||||
line: "flex-1 border-t-0 mb-4",
|
||||
},
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
const VerticalStep = React.forwardRef<HTMLDivElement, VerticalStepProps>(
|
||||
(props, ref) => {
|
||||
const {
|
||||
children,
|
||||
index,
|
||||
isCompletedStep,
|
||||
isCurrentStep,
|
||||
label,
|
||||
description,
|
||||
icon,
|
||||
hasVisited,
|
||||
state,
|
||||
checkIcon: checkIconProp,
|
||||
errorIcon: errorIconProp,
|
||||
onClickStep,
|
||||
} = props;
|
||||
|
||||
const {
|
||||
checkIcon: checkIconContext,
|
||||
errorIcon: errorIconContext,
|
||||
isError,
|
||||
isLoading,
|
||||
variant,
|
||||
onClickStep: onClickStepGeneral,
|
||||
clickable,
|
||||
expandVerticalSteps,
|
||||
styles,
|
||||
scrollTracking,
|
||||
orientation,
|
||||
steps,
|
||||
setStep,
|
||||
isLastStep: isLastStepCurrentStep,
|
||||
previousActiveStep,
|
||||
} = useStepper();
|
||||
|
||||
const opacity = hasVisited ? 1 : 0.8;
|
||||
const localIsLoading = isLoading || state === "loading";
|
||||
const localIsError = isError || state === "error";
|
||||
|
||||
const isLastStep = index === steps.length - 1;
|
||||
|
||||
const active =
|
||||
variant === "line" ? isCompletedStep || isCurrentStep : isCompletedStep;
|
||||
const checkIcon = checkIconProp || checkIconContext;
|
||||
const errorIcon = errorIconProp || errorIconContext;
|
||||
|
||||
const renderChildren = () => {
|
||||
if (!expandVerticalSteps) {
|
||||
return (
|
||||
<Collapsible open={isCurrentStep}>
|
||||
<CollapsibleContent
|
||||
ref={(node: any) => {
|
||||
if (
|
||||
// If the step is the first step and the previous step
|
||||
// was the last step or if the step is not the first step
|
||||
// This prevents initial scrolling when the stepper
|
||||
// is located anywhere other than the top of the view.
|
||||
scrollTracking &&
|
||||
((index === 0 &&
|
||||
previousActiveStep &&
|
||||
previousActiveStep === steps.length) ||
|
||||
(index && index > 0))
|
||||
) {
|
||||
node?.scrollIntoView({
|
||||
behavior: "smooth",
|
||||
block: "center",
|
||||
});
|
||||
}
|
||||
}}
|
||||
className="overflow-hidden data-[state=open]:animate-collapsible-down data-[state=closed]:animate-collapsible-up"
|
||||
>
|
||||
{children}
|
||||
</CollapsibleContent>
|
||||
</Collapsible>
|
||||
);
|
||||
}
|
||||
return children;
|
||||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"stepper__vertical-step",
|
||||
verticalStepVariants({
|
||||
variant: variant?.includes("circle") ? "circle" : "line",
|
||||
}),
|
||||
isLastStepCurrentStep && "gap-[var(--step-gap)]",
|
||||
styles?.["vertical-step"],
|
||||
)}
|
||||
data-optional={steps[index || 0]?.optional}
|
||||
data-completed={isCompletedStep}
|
||||
data-active={active}
|
||||
data-clickable={clickable || !!onClickStep}
|
||||
data-invalid={localIsError}
|
||||
onClick={() =>
|
||||
onClickStep?.(index || 0, setStep) ||
|
||||
onClickStepGeneral?.(index || 0, setStep)
|
||||
}
|
||||
>
|
||||
<div
|
||||
data-vertical={true}
|
||||
data-active={active}
|
||||
className={cn(
|
||||
"stepper__vertical-step-container",
|
||||
"flex items-center",
|
||||
variant === "line" &&
|
||||
"border-s-[3px] data-[active=true]:border-primary py-2 ps-3",
|
||||
styles?.["vertical-step-container"],
|
||||
)}
|
||||
>
|
||||
<StepButtonContainer
|
||||
{...{ isLoading: localIsLoading, isError: localIsError, ...props }}
|
||||
>
|
||||
<StepIcon
|
||||
{...{
|
||||
index,
|
||||
isError: localIsError,
|
||||
isLoading: localIsLoading,
|
||||
isCurrentStep,
|
||||
isCompletedStep,
|
||||
}}
|
||||
icon={icon}
|
||||
checkIcon={checkIcon}
|
||||
errorIcon={errorIcon}
|
||||
/>
|
||||
</StepButtonContainer>
|
||||
<StepLabel
|
||||
label={label}
|
||||
description={description}
|
||||
{...{ isCurrentStep, opacity }}
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
className={cn(
|
||||
"stepper__vertical-step-content",
|
||||
!isLastStep && "min-h-4",
|
||||
variant !== "line" && "ps-[--step-icon-size]",
|
||||
variant === "line" && orientation === "vertical" && "min-h-0",
|
||||
styles?.["vertical-step-content"],
|
||||
)}
|
||||
>
|
||||
{renderChildren()}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
export { VerticalStep };
|
|
@ -0,0 +1,59 @@
|
|||
import * as React from "react"
|
||||
import { cva, type VariantProps } from "class-variance-authority"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const alertVariants = cva(
|
||||
"relative w-full rounded-lg border px-4 py-3 text-sm [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground [&>svg~*]:pl-7",
|
||||
{
|
||||
variants: {
|
||||
variant: {
|
||||
default: "bg-background text-foreground",
|
||||
destructive:
|
||||
"border-destructive/50 text-destructive dark:border-destructive [&>svg]:text-destructive",
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
variant: "default",
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
const Alert = React.forwardRef<
|
||||
HTMLDivElement,
|
||||
React.HTMLAttributes<HTMLDivElement> & VariantProps<typeof alertVariants>
|
||||
>(({ className, variant, ...props }, ref) => (
|
||||
<div
|
||||
ref={ref}
|
||||
role="alert"
|
||||
className={cn(alertVariants({ variant }), className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
Alert.displayName = "Alert"
|
||||
|
||||
const AlertTitle = React.forwardRef<
|
||||
HTMLParagraphElement,
|
||||
React.HTMLAttributes<HTMLHeadingElement>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<h5
|
||||
ref={ref}
|
||||
className={cn("mb-1 font-medium leading-none tracking-tight", className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
AlertTitle.displayName = "AlertTitle"
|
||||
|
||||
const AlertDescription = React.forwardRef<
|
||||
HTMLParagraphElement,
|
||||
React.HTMLAttributes<HTMLParagraphElement>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<div
|
||||
ref={ref}
|
||||
className={cn("text-sm [&_p]:leading-relaxed", className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
AlertDescription.displayName = "AlertDescription"
|
||||
|
||||
export { Alert, AlertTitle, AlertDescription }
|
|
@ -0,0 +1,11 @@
|
|||
"use client"
|
||||
|
||||
import * as CollapsiblePrimitive from "@radix-ui/react-collapsible"
|
||||
|
||||
const Collapsible = CollapsiblePrimitive.Root
|
||||
|
||||
const CollapsibleTrigger = CollapsiblePrimitive.CollapsibleTrigger
|
||||
|
||||
const CollapsibleContent = CollapsiblePrimitive.CollapsibleContent
|
||||
|
||||
export { Collapsible, CollapsibleTrigger, CollapsibleContent }
|
|
@ -41,7 +41,7 @@ export const sideNavItems: GroupedNavItems[] = [
|
|||
icon: Rocket,
|
||||
},
|
||||
{
|
||||
href: "/dashboard/new-analysis",
|
||||
href: "/dashboard/create-new-analysis",
|
||||
title: "Create New Analysis",
|
||||
icon: FlaskConical,
|
||||
},
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
import type { Config } from "tailwindcss"
|
||||
import type { Config } from "tailwindcss";
|
||||
|
||||
const config = {
|
||||
darkMode: ["class"],
|
||||
content: [
|
||||
'./pages/**/*.{ts,tsx}',
|
||||
'./components/**/*.{ts,tsx}',
|
||||
'./app/**/*.{ts,tsx}',
|
||||
'./src/**/*.{ts,tsx}',
|
||||
"./pages/**/*.{ts,tsx}",
|
||||
"./components/**/*.{ts,tsx}",
|
||||
"./app/**/*.{ts,tsx}",
|
||||
"./src/**/*.{ts,tsx}",
|
||||
],
|
||||
prefix: "",
|
||||
theme: {
|
||||
|
@ -67,14 +67,24 @@ const config = {
|
|||
from: { height: "var(--radix-accordion-content-height)" },
|
||||
to: { height: "0" },
|
||||
},
|
||||
"collapsible-down": {
|
||||
from: { height: "0" },
|
||||
to: { height: "var(--radix-collapsible-content-height)" },
|
||||
},
|
||||
"collapsible-up": {
|
||||
from: { height: "var(--radix-collapsible-content-height)" },
|
||||
to: { height: "0" },
|
||||
},
|
||||
},
|
||||
animation: {
|
||||
"accordion-down": "accordion-down 0.2s ease-out",
|
||||
"accordion-up": "accordion-up 0.2s ease-out",
|
||||
"collapsible-down": "collapsible-down 0.2s ease-out",
|
||||
"collapsible-up": "collapsible-up 0.2s ease-out",
|
||||
},
|
||||
},
|
||||
},
|
||||
plugins: [require("tailwindcss-animate")],
|
||||
} satisfies Config
|
||||
} satisfies Config;
|
||||
|
||||
export default config
|
||||
export default config;
|
||||
|
|
Loading…
Reference in New Issue