diff --git a/package.json b/package.json index eac3bbb..3261d17 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,6 @@ "start": "next start" }, "dependencies": { - "@google/genai": "^0.7.0", "@radix-ui/react-accordion": "^1.2.4", "@radix-ui/react-dialog": "^1.1.7", "@radix-ui/react-icons": "^1.3.2", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a1df424..d1391cd 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -8,9 +8,6 @@ importers: .: dependencies: - '@google/genai': - specifier: ^0.7.0 - version: 0.7.0 '@radix-ui/react-accordion': specifier: ^1.2.4 version: 1.2.4(@types/react-dom@18.3.6(@types/react@18.3.20))(@types/react@18.3.20)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -227,10 +224,6 @@ packages: '@floating-ui/utils@0.2.9': resolution: {integrity: sha512-MDWhGtE+eHw5JW7lq4qhc5yRLS11ERl1c7Z6Xd0a58DozHES6EnNNwUWbMiG4J9Cgj053Bhk8zvlhFYKVhULwg==} - '@google/genai@0.7.0': - resolution: {integrity: sha512-r+Fwj/emnXZN5R+4JCxDXboY4AGTmTn7+Wnori5dgyJiStP0P82f9YYL0CVsCnDIumNY2i0UIcZ1zGZdtHJ34w==} - engines: {node: '>=18.0.0'} - '@humanwhocodes/config-array@0.13.0': resolution: {integrity: sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==} engines: {node: '>=10.10.0'} @@ -1149,10 +1142,6 @@ packages: engines: {node: '>=0.4.0'} hasBin: true - agent-base@7.1.3: - resolution: {integrity: sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==} - engines: {node: '>= 14'} - ajv-formats@2.1.1: resolution: {integrity: sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==} peerDependencies: @@ -1284,9 +1273,6 @@ packages: big.js@5.2.2: resolution: {integrity: sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==} - bignumber.js@9.2.1: - resolution: {integrity: sha512-+NzaKgOUvInq9TIUZ1+DRspzf/HApkCwD4btfuasFTdrfnOxqx853TgDpMolp+uv4RpRp7bPcEU2zKr9+fRmyw==} - binary-extensions@2.3.0: resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} engines: {node: '>=8'} @@ -1313,9 +1299,6 @@ packages: resolution: {integrity: sha512-MTxGsqgYTwfshYWTRdmZRC+M7FnG1b4y7RO7p2k3X24Wq0yv1m77Wsj0BzlPzd/IowgESfsruQCUToa7vbOpPQ==} engines: {node: '>=16.20.1'} - buffer-equal-constant-time@1.0.1: - resolution: {integrity: sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==} - buffer-from@1.1.2: resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} @@ -1529,9 +1512,6 @@ packages: eastasianwidth@0.2.0: resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} - ecdsa-sig-formatter@1.0.11: - resolution: {integrity: sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==} - electron-to-chromium@1.5.138: resolution: {integrity: sha512-FWlQc52z1dXqm+9cCJ2uyFgJkESd+16j6dBEjsgDNuHjBpuIzL8/lRc0uvh1k8RNI6waGo6tcy2DvwkTBJOLDg==} @@ -1741,9 +1721,6 @@ packages: resolution: {integrity: sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==} engines: {node: '>=6'} - extend@3.0.2: - resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} - fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} @@ -1844,14 +1821,6 @@ packages: resolution: {integrity: sha512-trLf4SzuuUxfusZADLINj+dE8clK1frKdmqiJNb1Es75fmI5oY6X2mxLVUciLLjxqw/xr72Dhy+lER6dGd02FQ==} engines: {node: '>=10'} - gaxios@6.7.1: - resolution: {integrity: sha512-LDODD4TMYx7XXdpwxAVRAIAuB0bzv0s+ywFonY46k126qzQHT9ygyoa9tncmOiQmmDrik65UYsEkv3lbfqQ3yQ==} - engines: {node: '>=14'} - - gcp-metadata@6.1.1: - resolution: {integrity: sha512-a4tiq7E0/5fTjxPAaH4jpjkSv/uCaU2p5KC6HVGrvl0cDjA8iBZv4vv1gyzlmK0ZUKqwpOyQMKzZQe3lTit77A==} - engines: {node: '>=14'} - geist@1.3.1: resolution: {integrity: sha512-Q4gC1pBVPN+D579pBaz0TRRnGA4p9UK6elDY/xizXdFk/g4EKR5g0I+4p/Kj6gM0SajDBZ/0FvDV9ey9ud7BWw==} peerDependencies: @@ -1920,14 +1889,6 @@ packages: peerDependencies: csstype: ^3.0.10 - google-auth-library@9.15.1: - resolution: {integrity: sha512-Jb6Z0+nvECVz+2lzSMt9u98UsoakXxA2HGHMCxh+so3n90XgYWkq5dur19JAJV7ONiJY22yBTyJB1TSkvPq9Ng==} - engines: {node: '>=14'} - - google-logging-utils@0.0.2: - resolution: {integrity: sha512-NEgUnEcBiP5HrPzufUkBzJOD/Sxsco3rLNo1F1TNf7ieU8ryUzBhqba8r756CjLX7rn3fHl6iLEwPYuqpoKgQQ==} - engines: {node: '>=14'} - gopd@1.2.0: resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} engines: {node: '>= 0.4'} @@ -1938,10 +1899,6 @@ packages: graphemer@1.4.0: resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} - gtoken@7.1.0: - resolution: {integrity: sha512-pCcEwRi+TKpMlxAQObHDQ56KawURgyAf6jtIY046fJ5tIv3zDe/LEIubckAO8fj6JnAxLdmWkUfNyulQ2iKdEw==} - engines: {node: '>=14.0.0'} - has-bigints@1.1.0: resolution: {integrity: sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==} engines: {node: '>= 0.4'} @@ -1969,10 +1926,6 @@ packages: resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} engines: {node: '>= 0.4'} - https-proxy-agent@7.0.6: - resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==} - engines: {node: '>= 14'} - ieee754@1.2.1: resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} @@ -2089,10 +2042,6 @@ packages: resolution: {integrity: sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==} engines: {node: '>= 0.4'} - is-stream@2.0.1: - resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} - engines: {node: '>=8'} - is-string@1.1.1: resolution: {integrity: sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==} engines: {node: '>= 0.4'} @@ -2152,9 +2101,6 @@ packages: resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} hasBin: true - json-bigint@1.0.0: - resolution: {integrity: sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==} - json-buffer@3.0.1: resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} @@ -2183,12 +2129,6 @@ packages: resolution: {integrity: sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==} engines: {node: '>=4.0'} - jwa@2.0.0: - resolution: {integrity: sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA==} - - jws@4.0.0: - resolution: {integrity: sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==} - kareem@2.6.3: resolution: {integrity: sha512-C3iHfuGUXK2u8/ipq9LfjFfXFxAZMQJJq7vLS45r3D9Y2xQ/m4S8zaR4zMLFWh9AsNPXmcFfUDhTEO8UIC/V6Q==} engines: {node: '>=12.0.0'} @@ -2408,15 +2348,6 @@ packages: node-addon-api@7.1.1: resolution: {integrity: sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==} - node-fetch@2.7.0: - resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} - engines: {node: 4.x || >=6.0.0} - peerDependencies: - encoding: ^0.1.0 - peerDependenciesMeta: - encoding: - optional: true - node-releases@2.0.19: resolution: {integrity: sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==} @@ -3116,9 +3047,6 @@ packages: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} - tr46@0.0.3: - resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} - tr46@5.1.1: resolution: {integrity: sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw==} engines: {node: '>=18'} @@ -3215,10 +3143,6 @@ packages: util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} - uuid@9.0.1: - resolution: {integrity: sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==} - hasBin: true - warning@4.0.3: resolution: {integrity: sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==} @@ -3226,9 +3150,6 @@ packages: resolution: {integrity: sha512-TnbFSbcOCcDgjZ4piURLCbJ3nJhznVh9kw6F6iokjiFPl8ONxe9A6nMDVXDiNbrSfLILs6vB07F7wLBrwPYzJw==} engines: {node: '>=10.13.0'} - webidl-conversions@3.0.1: - resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} - webidl-conversions@7.0.0: resolution: {integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==} engines: {node: '>=12'} @@ -3251,9 +3172,6 @@ packages: resolution: {integrity: sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==} engines: {node: '>=18'} - whatwg-url@5.0.0: - resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} - which-boxed-primitive@1.1.1: resolution: {integrity: sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==} engines: {node: '>= 0.4'} @@ -3297,18 +3215,6 @@ packages: wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} - ws@8.18.1: - resolution: {integrity: sha512-RKW2aJZMXeMxVpnZ6bck+RswznaxmzdULiBr6KY7XkTnW8uvt0iT9H5DkHUChXrc+uurzwa0rVI16n/Xzjdz1w==} - engines: {node: '>=10.0.0'} - peerDependencies: - bufferutil: ^4.0.1 - utf-8-validate: '>=5.0.2' - peerDependenciesMeta: - bufferutil: - optional: true - utf-8-validate: - optional: true - y18n@4.0.3: resolution: {integrity: sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==} @@ -3396,16 +3302,6 @@ snapshots: '@floating-ui/utils@0.2.9': {} - '@google/genai@0.7.0': - dependencies: - google-auth-library: 9.15.1 - ws: 8.18.1 - transitivePeerDependencies: - - bufferutil - - encoding - - supports-color - - utf-8-validate - '@humanwhocodes/config-array@0.13.0': dependencies: '@humanwhocodes/object-schema': 2.0.3 @@ -4312,8 +4208,6 @@ snapshots: acorn@8.14.1: {} - agent-base@7.1.3: {} - ajv-formats@2.1.1(ajv@8.17.1): optionalDependencies: ajv: 8.17.1 @@ -4463,8 +4357,6 @@ snapshots: big.js@5.2.2: {} - bignumber.js@9.2.1: {} - binary-extensions@2.3.0: {} bl@4.1.0: @@ -4495,8 +4387,6 @@ snapshots: bson@6.10.3: {} - buffer-equal-constant-time@1.0.1: {} - buffer-from@1.1.2: {} buffer@5.7.1: @@ -4698,10 +4588,6 @@ snapshots: eastasianwidth@0.2.0: {} - ecdsa-sig-formatter@1.0.11: - dependencies: - safe-buffer: 5.2.1 - electron-to-chromium@1.5.138: {} embla-carousel-autoplay@8.6.0(embla-carousel@8.6.0): @@ -4847,8 +4733,8 @@ snapshots: '@typescript-eslint/parser': 8.30.1(eslint@8.57.1)(typescript@5.8.3) eslint: 8.57.1 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.10.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.30.1(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1))(eslint@8.57.1) - eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.30.1(eslint@8.57.1)(typescript@5.8.3))(eslint-import-resolver-typescript@3.10.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.30.1(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1) + eslint-import-resolver-typescript: 3.10.0(eslint-plugin-import@2.31.0)(eslint@8.57.1) + eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.30.1(eslint@8.57.1)(typescript@5.8.3))(eslint-import-resolver-typescript@3.10.0)(eslint@8.57.1) eslint-plugin-jsx-a11y: 6.10.2(eslint@8.57.1) eslint-plugin-react: 7.37.5(eslint@8.57.1) eslint-plugin-react-hooks: 5.0.0-canary-7118f5dd7-20230705(eslint@8.57.1) @@ -4867,7 +4753,7 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-import-resolver-typescript@3.10.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.30.1(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1))(eslint@8.57.1): + eslint-import-resolver-typescript@3.10.0(eslint-plugin-import@2.31.0)(eslint@8.57.1): dependencies: '@nolyfill/is-core-module': 1.0.39 debug: 4.4.0 @@ -4878,22 +4764,22 @@ snapshots: tinyglobby: 0.2.12 unrs-resolver: 1.5.0 optionalDependencies: - eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.30.1(eslint@8.57.1)(typescript@5.8.3))(eslint-import-resolver-typescript@3.10.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.30.1(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1) + eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.30.1(eslint@8.57.1)(typescript@5.8.3))(eslint-import-resolver-typescript@3.10.0)(eslint@8.57.1) transitivePeerDependencies: - supports-color - eslint-module-utils@2.12.0(@typescript-eslint/parser@8.30.1(eslint@8.57.1)(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.30.1(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1): + eslint-module-utils@2.12.0(@typescript-eslint/parser@8.30.1(eslint@8.57.1)(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.0(eslint-plugin-import@2.31.0)(eslint@8.57.1))(eslint@8.57.1): dependencies: debug: 3.2.7 optionalDependencies: '@typescript-eslint/parser': 8.30.1(eslint@8.57.1)(typescript@5.8.3) eslint: 8.57.1 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.10.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.30.1(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1))(eslint@8.57.1) + eslint-import-resolver-typescript: 3.10.0(eslint-plugin-import@2.31.0)(eslint@8.57.1) transitivePeerDependencies: - supports-color - eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.30.1(eslint@8.57.1)(typescript@5.8.3))(eslint-import-resolver-typescript@3.10.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.30.1(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1): + eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.30.1(eslint@8.57.1)(typescript@5.8.3))(eslint-import-resolver-typescript@3.10.0)(eslint@8.57.1): dependencies: '@rtsao/scc': 1.1.0 array-includes: 3.1.8 @@ -4904,7 +4790,7 @@ snapshots: doctrine: 2.1.0 eslint: 8.57.1 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.30.1(eslint@8.57.1)(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.30.1(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1) + eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.30.1(eslint@8.57.1)(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.0(eslint-plugin-import@2.31.0)(eslint@8.57.1))(eslint@8.57.1) hasown: 2.0.2 is-core-module: 2.16.1 is-glob: 4.0.3 @@ -5048,8 +4934,6 @@ snapshots: expand-template@2.0.3: {} - extend@3.0.2: {} - fast-deep-equal@3.1.3: {} fast-glob@3.3.3: @@ -5144,26 +5028,6 @@ snapshots: fuse.js@7.1.0: {} - gaxios@6.7.1: - dependencies: - extend: 3.0.2 - https-proxy-agent: 7.0.6 - is-stream: 2.0.1 - node-fetch: 2.7.0 - uuid: 9.0.1 - transitivePeerDependencies: - - encoding - - supports-color - - gcp-metadata@6.1.1: - dependencies: - gaxios: 6.7.1 - google-logging-utils: 0.0.2 - json-bigint: 1.0.0 - transitivePeerDependencies: - - encoding - - supports-color - geist@1.3.1(next@14.2.28(react-dom@18.3.1(react@18.3.1))(react@18.3.1)): dependencies: next: 14.2.28(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -5251,34 +5115,12 @@ snapshots: dependencies: csstype: 3.1.3 - google-auth-library@9.15.1: - dependencies: - base64-js: 1.5.1 - ecdsa-sig-formatter: 1.0.11 - gaxios: 6.7.1 - gcp-metadata: 6.1.1 - gtoken: 7.1.0 - jws: 4.0.0 - transitivePeerDependencies: - - encoding - - supports-color - - google-logging-utils@0.0.2: {} - gopd@1.2.0: {} graceful-fs@4.2.11: {} graphemer@1.4.0: {} - gtoken@7.1.0: - dependencies: - gaxios: 6.7.1 - jws: 4.0.0 - transitivePeerDependencies: - - encoding - - supports-color - has-bigints@1.1.0: {} has-flag@4.0.0: {} @@ -5301,13 +5143,6 @@ snapshots: dependencies: function-bind: 1.1.2 - https-proxy-agent@7.0.6: - dependencies: - agent-base: 7.1.3 - debug: 4.4.0 - transitivePeerDependencies: - - supports-color - ieee754@1.2.1: {} ignore@5.3.2: {} @@ -5425,8 +5260,6 @@ snapshots: dependencies: call-bound: 1.0.4 - is-stream@2.0.1: {} - is-string@1.1.1: dependencies: call-bound: 1.0.4 @@ -5494,10 +5327,6 @@ snapshots: dependencies: argparse: 2.0.1 - json-bigint@1.0.0: - dependencies: - bignumber.js: 9.2.1 - json-buffer@3.0.1: {} json-parse-even-better-errors@2.3.1: {} @@ -5521,17 +5350,6 @@ snapshots: object.assign: 4.1.7 object.values: 1.2.1 - jwa@2.0.0: - dependencies: - buffer-equal-constant-time: 1.0.1 - ecdsa-sig-formatter: 1.0.11 - safe-buffer: 5.2.1 - - jws@4.0.0: - dependencies: - jwa: 2.0.0 - safe-buffer: 5.2.1 - kareem@2.6.3: {} keyv@4.5.4: @@ -5721,10 +5539,6 @@ snapshots: node-addon-api@7.1.1: {} - node-fetch@2.7.0: - dependencies: - whatwg-url: 5.0.0 - node-releases@2.0.19: {} normalize-path@3.0.0: {} @@ -6444,8 +6258,6 @@ snapshots: dependencies: is-number: 7.0.0 - tr46@0.0.3: {} - tr46@5.1.1: dependencies: punycode: 2.3.1 @@ -6567,8 +6379,6 @@ snapshots: util-deprecate@1.0.2: {} - uuid@9.0.1: {} - warning@4.0.3: dependencies: loose-envify: 1.4.0 @@ -6578,8 +6388,6 @@ snapshots: glob-to-regexp: 0.4.1 graceful-fs: 4.2.11 - webidl-conversions@3.0.1: {} - webidl-conversions@7.0.0: {} webpack-sources@3.2.3: {} @@ -6619,11 +6427,6 @@ snapshots: tr46: 5.1.1 webidl-conversions: 7.0.0 - whatwg-url@5.0.0: - dependencies: - tr46: 0.0.3 - webidl-conversions: 3.0.1 - which-boxed-primitive@1.1.1: dependencies: is-bigint: 1.1.0 @@ -6693,8 +6496,6 @@ snapshots: wrappy@1.0.2: {} - ws@8.18.1: {} - y18n@4.0.3: {} yaml@2.7.1: {} diff --git a/src/app/api/ai-upload/route.ts b/src/app/api/ai-upload/route.ts index 1296fe7..4a702bf 100644 --- a/src/app/api/ai-upload/route.ts +++ b/src/app/api/ai-upload/route.ts @@ -1,31 +1,15 @@ import { NextResponse } from "next/server"; import { PDFDocument } from "pdf-lib"; -import { - campuses, - exams, - semesters, - slots, - years, -} from "@/components/select_options"; import { connectToDatabase } from "@/lib/mongoose"; import cloudinary from "cloudinary"; -import type { - ICourses, - CloudinaryUploadResult, - ExamDetail, - IAdminPaper, -} from "@/interface"; +import type { CloudinaryUploadResult } from "@/interface"; import { PaperAdmin } from "@/db/papers"; -import axios from "axios"; -import processAndAnalyze from "@/util/gemini"; -import Fuse from "fuse.js"; cloudinary.v2.config({ cloud_name: process.env.NEXT_PUBLIC_CLOUDINARY_CLOUD_NAME, api_key: process.env.CLOUDINARY_API_KEY, api_secret: process.env.CLOUDINARY_SECRET, }); -type SemesterType = IAdminPaper["semester"]; const config1 = { cloud_name: process.env.NEXT_PUBLIC_CLOUDINARY_CLOUD_NAME_1, @@ -38,6 +22,7 @@ const config2 = { api_key: process.env.CLOUDINARY_API_KEY_2, api_secret: process.env.CLOUDINARY_SECRET_2, }; + const cloudinaryConfigs = [config1, config2]; export async function POST(req: Request) { @@ -68,66 +53,6 @@ export async function POST(req: Request) { const pdfBuffer = Buffer.from(pdfBytes); pdfData = pdfBuffer.toString("base64"); } - const tags = await processAndAnalyze({ pdfData }); - - console.log("tags generated:", tags); - - const { data } = await axios.get( - `${process.env.SERVER_URL}/api/course-list`, - ); - const courses = data.map((course: { name: string }) => course.name); - - const finalTags = await setTagsFromCurrentLists(tags, courses); - console.log(" tags final:", finalTags); - - const subject = finalTags.subject; - const slot = finalTags.slot; - const exam = finalTags.exam; - const year = finalTags.year; - const campus = formData.get("campus") as string; - const semester = finalTags.semester; - const answerKeyIncluded = finalTags.answerKeyIncluded; - if (!courses.includes(subject)) { - return NextResponse.json( - { message: "The course subject is invalid." }, - { status: 400 }, - ); - } - - if (!slots.includes(slot)) { - return NextResponse.json( - { message: "The slot is invalid." }, - { status: 400 }, - ); - } - - if (!exam.includes(exam)) { - return NextResponse.json( - { message: "The exam type is invalid." }, - { status: 400 }, - ); - } - - if (!years.includes(year)) { - return NextResponse.json( - { message: "The year is invalid." }, - { status: 400 }, - ); - } - - if (!campuses.includes(campus)) { - return NextResponse.json( - { message: `The ${campus} is invalid.` }, - { status: 400 }, - ); - } - - if (!semesters.includes(semester)) { - return NextResponse.json( - { message: "The semester is invalid." }, - { status: 400 }, - ); - } let finalUrl: string | undefined = ""; let public_id_cloudinary: string | undefined = ""; @@ -146,11 +71,15 @@ export async function POST(req: Request) { return; } + console.log("this is happening 1"); + const mergedPdfBytes = await CreatePDF(files); [public_id_cloudinary, finalUrl] = await uploadPDFFile( mergedPdfBytes, uploadPreset, ); + + console.log("this is happening 2"); } catch (error) { console.error("Error creating PDF:", error); return NextResponse.json( @@ -159,12 +88,13 @@ export async function POST(req: Request) { ); } } else { + console.log("this is happening 3"); [public_id_cloudinary, finalUrl] = await uploadPDFFile( files[0]!, uploadPreset, ); } - console.log(finalUrl); + const thumbnailResponse = cloudinary.v2.image(finalUrl!, { format: "jpg", }); @@ -172,20 +102,25 @@ export async function POST(req: Request) { .replace("pdf", "jpg") .replace("upload", "upload/w_400,h_400,c_fill") .replace(//g, ""); + + console.log("this is happening 4"); + const paper = new PaperAdmin({ cloudinary_index: configIndex, public_id_cloudinary, - answerKeyIncluded, finalUrl, thumbnailUrl, - subject, - slot, - year, - exam, - campus, - semester, + subject: null, + slot: null, + year: null, + exam: null, + semester: null, + campus: null, }); + + console.log("this is happening 5"); await paper.save(); + console.log("this is happening 6"); return NextResponse.json({ status: "success" }, { status: 201 }); } catch (error) { console.error(error); @@ -197,6 +132,7 @@ export async function POST(req: Request) { } async function uploadPDFFile(file: File | ArrayBuffer, uploadPreset: string) { + console.log("this is happening 7"); let bytes; if (file instanceof File) { bytes = await file.arrayBuffer(); @@ -212,12 +148,16 @@ async function uploadFile( fileType: string, ) { try { + console.log("this is happening 8"); const buffer = Buffer.from(bytes); + console.log("this is happening 9"); const dataUrl = `data:${fileType};base64,${buffer.toString("base64")}`; + console.log("this is happening 10"); const uploadResult = (await cloudinary.v2.uploader.unsigned_upload( dataUrl, uploadPreset, )) as CloudinaryUploadResult; + console.log("this is happening 11"); return [uploadResult.public_id, uploadResult.secure_url]; } catch (e) { throw e; @@ -252,62 +192,3 @@ async function CreatePDF(orderedFiles: File[]) { const mergedPdfBytes = await pdfDoc.save(); return mergedPdfBytes; } - -// Sets course-name to corresponding course name from our api -async function setTagsFromCurrentLists( - tags: ExamDetail | undefined, - courses: string[], -): Promise { - if (!courses[0] || !slots[0] || !exams[0] || !semesters[0] || !years[0]) { - throw Error("Cannot fetch default value for courses/slot/exam/sem/year!"); - } - - const newTags: ExamDetail = { - subject: courses[0], - slot: slots[0], - "course-code": "notInUse", - exam: exams[0], - semester: semesters[0] as SemesterType, - year: years[0], - answerKeyIncluded: false, - }; - - const coursesFuzy = new Fuse(courses); - if (!tags) { - console.log("Anaylsis failed setting random courses as fields"); - return newTags; - } else { - const subjectSearch = coursesFuzy.search(tags.subject)[0]; - if (subjectSearch) { - newTags.subject = subjectSearch.item; - } - const slotSearchResult = findMatch(slots, tags.slot); - if (slotSearchResult) { - newTags.slot = slotSearchResult; - } - const examSearchResult = findMatch(exams, tags.exam); - if (examSearchResult) { - newTags.exam = examSearchResult; - } - const semesterSearchResult = findMatch(semesters, tags.semester); - if (semesterSearchResult) { - newTags.semester = semesterSearchResult as SemesterType; - } - const yearSearchResult = findMatch(years, tags.year); - - if (yearSearchResult) { - newTags.year = yearSearchResult; - } - const answerkeySearchResults = tags.answerKeyIncluded ?? false; - - if (yearSearchResult) { - newTags.answerKeyIncluded = answerkeySearchResults; - } - } - return newTags; -} -function findMatch(arr: T[], value: string | undefined): T | undefined { - if (!value) return undefined; - const pattern = new RegExp(value, "i"); - return arr.find((item) => pattern.test(String(item))); -} diff --git a/src/app/api/upload/route.ts b/src/app/api/upload/route.ts deleted file mode 100644 index e4a4e9a..0000000 --- a/src/app/api/upload/route.ts +++ /dev/null @@ -1,188 +0,0 @@ -import { NextResponse } from "next/server"; -import { PDFDocument } from "pdf-lib"; -import { campuses, exams, semesters, slots, years } from "@/components/select_options"; -import { connectToDatabase } from "@/lib/mongoose"; -import cloudinary from "cloudinary"; -import { type ICourses, type CloudinaryUploadResult } from "@/interface"; -import Paper, { PaperAdmin } from "@/db/papers"; -import axios from "axios"; - -const cloudinaryConfig1 = cloudinary.v2; -cloudinaryConfig1.config({ - cloud_name: process.env.NEXT_PUBLIC_CLOUDINARY_CLOUD_NAME_1, - api_key: process.env.CLOUDINARY_API_KEY_1, - api_secret: process.env.CLOUDINARY_SECRET_1, -}); - -const cloudinaryConfig2 = cloudinary.v2; -cloudinaryConfig2.config({ - cloud_name: process.env.NEXT_PUBLIC_CLOUDINARY_CLOUD_NAME_2, - api_key: process.env.CLOUDINARY_API_KEY_2, - api_secret: process.env.CLOUDINARY_SECRET_2, -}); -const cloudinaryConfigs = [cloudinaryConfig1, cloudinaryConfig2]; - -export async function POST(req: Request) { - try { - if (!process.env.NEXT_PUBLIC_CLOUDINARY_UPLOAD_PRESET) { - return NextResponse.json({ message: "ServerMisconfig" }, { status: 500 }); - } - const count: number = await Paper.countDocuments(); - - const configIndex = cloudinaryConfigs[count % cloudinaryConfigs.length]; - cloudinary.v2.config(configIndex); - const uploadPreset = process.env.NEXT_PUBLIC_CLOUDINARY_UPLOAD_PRESET; - const formData = await req.formData(); - const files: File[] = formData.getAll("files") as File[]; - - const subject = formData.get("subject") as string; - const slot = formData.get("slot") as string; - const year = formData.get("year") as string; - const exam = formData.get("exam") as string; - const campus = formData.get("campus") as string; - const semester = formData.get("semester") as string; - - const isPdf = formData.get("isPdf") === "true"; - - const { data } = await axios.get(`${process.env.SERVER_URL}/api/course-list`); - const courses = data.map((course: { name: string }) => course.name); - if ( - !( - courses.includes(subject) && - slots.includes(slot) && - years.includes(year) && - exams.includes(exam) && - campuses.includes(campus) && - semesters.includes(semester) - ) - ) { - return NextResponse.json({ message: "Bad Request" }, { status: 400 }); - } - - await connectToDatabase(); - let finalUrl: string | undefined = ""; - let public_id_cloudinary: string | undefined = ""; - let thumbnailUrl: string | undefined = ""; - - if (!files || files.length === 0) { - return NextResponse.json( - { error: "No files received." }, - { status: 400 }, - ); - } - if (!isPdf) { - try { - if (!process.env.NEXT_PUBLIC_CLOUDINARY_UPLOAD_PRESET) { - return; - } - - const mergedPdfBytes = await CreatePDF(files); - [public_id_cloudinary, finalUrl] = await uploadPDFFile( - mergedPdfBytes, - uploadPreset, - ); - } catch (error) { - console.error("Error creating PDF:", error); - return NextResponse.json( - { error: "Failed to process PDF" }, - { status: 500 }, - ); - } - } else { - [public_id_cloudinary, finalUrl] = await uploadPDFFile( - files[0]!, - uploadPreset, - ); - } - - const thumbnailResponse = cloudinary.v2.image(finalUrl!, { - format: "jpg", - }); - thumbnailUrl = thumbnailResponse - .replace("pdf", "jpg") - .replace("upload", "upload/w_400,h_400,c_fill") - .replace(//g, ""); - const paper = new PaperAdmin({ - public_id_cloudinary, - cloudinary_index: configIndex, - finalUrl, - thumbnailUrl, - subject, - slot, - year, - exam, - campus, - semester - }); - await paper.save(); - return NextResponse.json( - { status: "success", url: finalUrl, thumbnailUrl: thumbnailUrl }, - { status: 201 }, - ); - } catch (error) { - console.error(error); - return NextResponse.json( - { message: "Failed to upload papers", error }, - { status: 500 }, - ); - } -} - -async function uploadPDFFile(file: File | ArrayBuffer, uploadPreset: string) { - let bytes; - if (file instanceof File) { - bytes = await file.arrayBuffer(); - } else { - bytes = file; - } - return uploadFile(bytes, uploadPreset, "application/pdf"); -} - -async function uploadFile( - bytes: ArrayBuffer, - uploadPreset: string, - fileType: string, -) { - try { - const buffer = Buffer.from(bytes); - const dataUrl = `data:${fileType};base64,${buffer.toString("base64")}`; - const uploadResult = (await cloudinary.v2.uploader.unsigned_upload( - dataUrl, - uploadPreset, - )) as CloudinaryUploadResult; - return [uploadResult.public_id, uploadResult.secure_url]; - } catch (e) { - throw e; - } -} - -async function CreatePDF(files: File[]) { - const pdfDoc = await PDFDocument.create(); - - const orderedFiles = files; - - for (const file of orderedFiles) { - const fileBlob = new Blob([file]); - const imgBytes = Buffer.from(await fileBlob.arrayBuffer()); - let img; - if (file instanceof File) { - if (file.type === "image/png") { - img = await pdfDoc.embedPng(imgBytes); - } else if (file.type === "image/jpeg" || file.type === "image/jpg") { - img = await pdfDoc.embedJpg(imgBytes); - } else { - continue; - } - const page = pdfDoc.addPage([img.width, img.height]); - page.drawImage(img, { - x: 0, - y: 0, - width: img.width, - height: img.height, - }); - } - } - - const mergedPdfBytes = await pdfDoc.save(); - return mergedPdfBytes; -} diff --git a/src/app/api/user-papers/route.ts b/src/app/api/user-papers/route.ts index 8720214..cb5fad5 100644 --- a/src/app/api/user-papers/route.ts +++ b/src/app/api/user-papers/route.ts @@ -1,6 +1,7 @@ import { NextResponse } from "next/server"; import { connectToDatabase } from "@/lib/mongoose"; import Paper from "@/db/papers"; +import { StoredSubjects } from "@/interface"; export const dynamic = "force-dynamic"; @@ -12,25 +13,35 @@ interface TransformedPaper { export async function POST(req: Request) { try { await connectToDatabase(); - const subjects: string[] = await req.json() as string[]; + const subjects = (await req.json()) as StoredSubjects; const usersPapers = await Paper.find({ subject: { $in: subjects }, }); - const transformedPapers = usersPapers.reduce((acc, paper) => { - const existing = acc.find((item) => item.subject === paper.subject); + const transformedPapers = usersPapers.reduce( + (acc: { subject: string; slots: string[] }[], paper) => { + const existing = acc.find((item) => item.subject === paper.subject); - if (existing) { - existing.slots.push(paper.slot); - } else { - acc.push({ subject: paper.subject, slots: [paper.slot] }); - } + if (existing) { + existing.slots.push(paper.slot); + } else { + acc.push({ subject: paper.subject, slots: [paper.slot] }); + } - return acc; - }, []); + return acc; + }, + [], + ); + + const seenSubjects = new Set(); + const uniquePapers = transformedPapers.filter((paper) => { + if (seenSubjects.has(paper.subject)) return false; + seenSubjects.add(paper.subject); + return true; + }); - return NextResponse.json(transformedPapers, { + return NextResponse.json(uniquePapers, { status: 200, }); } catch (error) { diff --git a/src/app/layout.tsx b/src/app/layout.tsx index f5f1d31..f98319f 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -122,9 +122,8 @@ export default function RootLayout({
- - {children} - {/*
{children}
*/} + {children} +
diff --git a/src/app/paper/[id]/page.tsx b/src/app/paper/[id]/page.tsx index f8a826c..9eb4726 100644 --- a/src/app/paper/[id]/page.tsx +++ b/src/app/paper/[id]/page.tsx @@ -158,14 +158,15 @@ const PaperPage = async ({ params }: { params: { id: string } }) => { ) : ( <> -

+

{paper.subject} {paper.exam} {paper.slot} {paper.year}

diff --git a/src/app/pinned/page.tsx b/src/app/pinned/page.tsx new file mode 100644 index 0000000..51e12a1 --- /dev/null +++ b/src/app/pinned/page.tsx @@ -0,0 +1,25 @@ +import React from "react"; +import SearchBar from "@/components/Searchbar/searchbar"; +import PinnedPapersCarousel from "@/components/PinnedPapersCarousel"; + +const Pinned = () => { + return ( +
+

+ Pinned Papers +

+ +
+
+ +
+
+ +
+

You can pin upto 8 Subjects

+
+
+ ); +}; + +export default Pinned; diff --git a/src/components/AddPapers.tsx b/src/components/AddPapers.tsx new file mode 100644 index 0000000..6acb6d6 --- /dev/null +++ b/src/components/AddPapers.tsx @@ -0,0 +1,14 @@ +const AddPapers = ({ onClick }: { onClick?: () => void }) => { + return ( +
+ + + + +
+ ); +}; + +export default AddPapers; diff --git a/src/components/Card.tsx b/src/components/Card.tsx index 260e9ba..f9c020b 100644 --- a/src/components/Card.tsx +++ b/src/components/Card.tsx @@ -65,13 +65,14 @@ const Card = ({ paper, onSelect, isSelected }: CardProps) => { return (
{paper.subject} {
-
+
{extractBracketContent(paper.subject)}
@@ -115,7 +116,7 @@ const Card = ({ paper, onSelect, isSelected }: CardProps) => {
-
+
{ const [filterOptions, setFilterOptions] = useState(); const [filtersPulled, setFiltersPulled] = useState(false); const [appliedFilters, setAppliedFilters] = useState(false); + const [pinned, setPinned] = useState(false); // Set initial state from searchParams on client-side mount useEffect(() => { setIsMounted(true); if (searchParams) { - setSubject(searchParams.get("subject")); + const currentPinnedSubjects = JSON.parse( + localStorage.getItem("userSubjects") ?? "[]", + ) as StoredSubjects; + const subjectName = searchParams.get("subject"); + setSubject(subjectName); setSelectedExams(searchParams.get("exams")?.split(",") ?? []); setSelectedSlots(searchParams.get("slots")?.split(",") ?? []); setSelectedYears(searchParams.get("years")?.split(",") ?? []); setSelectedCampuses(searchParams.get("campus")?.split(",") ?? []); setSelectedSemesters(searchParams.get("semester")?.split(",") ?? []); setSelectedAnswerKeyIncluded(searchParams.get("answerkey") === "true"); + if (subjectName && Array.isArray(currentPinnedSubjects)) { + if (currentPinnedSubjects.includes(subjectName)) { + setPinned(true); + } else { + setPinned(false); + } + } } - }, [searchParams]); + }, [searchParams, pinned]); const filtersNotPulled = () => { setFiltersPulled(false); }; + const handlePinToggle = () => { + const current = !pinned; + setPinned(current); + + const saved = JSON.parse( + localStorage.getItem("userSubjects") ?? "[]", + ) as string[]; + const updated = current + ? [...new Set([...saved, subject])] + : saved.filter((s) => s !== subject); + + localStorage.setItem("userSubjects", JSON.stringify(updated)); + }; + // Fetch papers and apply filters useEffect(() => { if (!subject || !isMounted) return; @@ -303,11 +331,29 @@ const CatalogueContent = () => { +
+
+

+ {subject?.split("[")[1]?.replace("]", "")} +

+

+ {subject?.split(" [")[0]} +

+
+
+ +
+
+ {loading ? ( ) : papers.length > 0 ? (
{appliedFilters ? ( filteredPapers.length > 0 ? ( diff --git a/src/components/FloatingNavbar.tsx b/src/components/FloatingNavbar.tsx new file mode 100644 index 0000000..65af188 --- /dev/null +++ b/src/components/FloatingNavbar.tsx @@ -0,0 +1,43 @@ +"use client"; + +import { usePathname } from "next/navigation"; +import Link from "next/link"; +import { StarIcon, UploadIcon } from "lucide-react"; +import ModeToggle from "./toggle-theme"; + +interface Props { + onNavigate: () => void; +} + +export default function FloatingNavbar({ onNavigate }: Props) { + const pathname = usePathname(); + + return ( +
+
+ +
+ + + {pathname === "/upload" ? "Search Papers" : "Upload Papers"} + +
+ + + +
+ + Pinned Subjects +
+ + +
+ +
+
+
+ ); +} diff --git a/src/components/Footer.tsx b/src/components/Footer.tsx index 660b13d..b71dcee 100644 --- a/src/components/Footer.tsx +++ b/src/components/Footer.tsx @@ -25,80 +25,82 @@ export default function Footer() { }, [theme]); return ( -