diff --git a/package.json b/package.json index 81edf28e..fbef02bb 100644 --- a/package.json +++ b/package.json @@ -35,10 +35,12 @@ }, "homepage": "https://github.com/pagers-org/react-world#readme", "dependencies": { + "@radix-ui/react-dropdown-menu": "^2.0.5", "@radix-ui/react-slot": "^1.0.2", "clsx": "^2.0.0", "lucide-react": "^0.274.0", "next": "^13.4.19", + "next-themes": "^0.2.1", "react": "^18.2.0", "react-dom": "^18.2.0", "tailwind-merge": "^1.14.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c39967df..11484001 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1,6 +1,9 @@ lockfileVersion: '6.0' dependencies: + '@radix-ui/react-dropdown-menu': + specifier: ^2.0.5 + version: 2.0.5(@types/react@18.2.21)(react-dom@18.2.0)(react@18.2.0) '@radix-ui/react-slot': specifier: ^1.0.2 version: 1.0.2(@types/react@18.2.21)(react@18.2.0) @@ -13,6 +16,9 @@ dependencies: next: specifier: ^13.4.19 version: 13.4.19(@babel/core@7.22.17)(react-dom@18.2.0)(react@18.2.0) + next-themes: + specifier: ^0.2.1 + version: 0.2.1(next@13.4.19)(react-dom@18.2.0)(react@18.2.0) react: specifier: ^18.2.0 version: 18.2.0 @@ -1815,14 +1821,12 @@ packages: resolution: {integrity: sha512-jk3WqquEJRlcyu7997NtR5PibI+y5bi+LS3hPmguVClypenMsCY3CBa3LAQnozRCtCrYWSEtAdiskpamuJRFOQ==} dependencies: '@floating-ui/utils': 0.1.1 - dev: true /@floating-ui/dom@1.5.1: resolution: {integrity: sha512-KwvVcPSXg6mQygvA1TjbN/gh///36kKtllIF8SUm0qpFj8+rvYrpvlYdL1JoA71SHpDqgSSdGOSoQ0Mp3uY5aw==} dependencies: '@floating-ui/core': 1.4.1 '@floating-ui/utils': 0.1.1 - dev: true /@floating-ui/react-dom@2.0.2(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-5qhlDvjaLmAst/rKb3VdlCinwTF4EYMiVxuuc/HVUjs46W0zgtbMmAZ1UTsDrRTxRmUEzl92mOtWbeeXL26lSQ==} @@ -1833,11 +1837,9 @@ packages: '@floating-ui/dom': 1.5.1 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - dev: true /@floating-ui/utils@0.1.1: resolution: {integrity: sha512-m0G6wlnhm/AX0H12IOWtK8gASEMffnX08RtKkCgTdHb9JpHKGloI7icFfLg9ZmQeavcvR0PKmzxClyuFPSjKWw==} - dev: true /@humanwhocodes/config-array@0.11.10: resolution: {integrity: sha512-KVVjQmNUepDVGXNuoRRdmmEjruj0KfiGSbS8LVc12LMsWDQzRXJ0qdhN8L8uUigKpfEHRhlaQFY0ib1tnUbNeQ==} @@ -2315,7 +2317,6 @@ packages: resolution: {integrity: sha512-yQ8oGX2GVsEYMWGxcovu1uGWPCxV5BFfeeYxqPmuAzUyLT9qmaMXSAhXpb0WrspIeqYzdJpkh2vHModJPgRIaw==} dependencies: '@babel/runtime': 7.22.15 - dev: true /@radix-ui/react-arrow@1.0.3(@types/react@18.2.21)(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-wSP+pHsB/jQRaL6voubsQ/ZlrGBHHrOjmBnr19hxYgtS0WvAFwZhK2WP/YY5yF9uKECCEEDGxuLxq1NBK51wFA==} @@ -2335,7 +2336,6 @@ packages: '@types/react': 18.2.21 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - dev: true /@radix-ui/react-collection@1.0.3(@types/react@18.2.21)(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-3SzW+0PW7yBBoQlT8wNcGtaxaD0XSu0uLUFgrtHY08Acx05TaHaOmVLR73c0j/cqpDy53KBMO7s0dx2wmOIDIA==} @@ -2358,7 +2358,6 @@ packages: '@types/react': 18.2.21 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - dev: true /@radix-ui/react-compose-refs@1.0.1(@types/react@18.2.21)(react@18.2.0): resolution: {integrity: sha512-fDSBgd44FKHa1FRMU59qBMPFcl2PZE+2nmqunj+BWFyYYjnhIDWL2ItDs3rrbJDQOtzt5nIebLCQc4QRfz6LJw==} @@ -2385,7 +2384,6 @@ packages: '@babel/runtime': 7.22.15 '@types/react': 18.2.21 react: 18.2.0 - dev: true /@radix-ui/react-direction@1.0.1(@types/react@18.2.21)(react@18.2.0): resolution: {integrity: sha512-RXcvnXgyvYvBEOhCBuddKecVkoMiI10Jcm5cTI7abJRAHYfFxeu+FBQs/DvdxSYucxR5mna0dNsL6QFlds5TMA==} @@ -2399,7 +2397,6 @@ packages: '@babel/runtime': 7.22.15 '@types/react': 18.2.21 react: 18.2.0 - dev: true /@radix-ui/react-dismissable-layer@1.0.4(@types/react@18.2.21)(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-7UpBa/RKMoHJYjie1gkF1DlK8l1fdU/VKDpoS3rCCo8YBJR294GwcEHyxHw72yvphJ7ld0AXEcSLAzY2F/WyCg==} @@ -2423,7 +2420,32 @@ packages: '@types/react': 18.2.21 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - dev: true + + /@radix-ui/react-dropdown-menu@2.0.5(@types/react@18.2.21)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-xdOrZzOTocqqkCkYo8yRPCib5OkTkqN7lqNCdxwPOdE466DOaNl4N8PkUIlsXthQvW5Wwkd+aEmWpfWlBoDPEw==} + 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 + dependencies: + '@babel/runtime': 7.22.15 + '@radix-ui/primitive': 1.0.1 + '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.21)(react@18.2.0) + '@radix-ui/react-context': 1.0.1(@types/react@18.2.21)(react@18.2.0) + '@radix-ui/react-id': 1.0.1(@types/react@18.2.21)(react@18.2.0) + '@radix-ui/react-menu': 2.0.5(@types/react@18.2.21)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-primitive': 1.0.3(@types/react@18.2.21)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.2.21)(react@18.2.0) + '@types/react': 18.2.21 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false /@radix-ui/react-focus-guards@1.0.1(@types/react@18.2.21)(react@18.2.0): resolution: {integrity: sha512-Rect2dWbQ8waGzhMavsIbmSVCgYxkXLxxR3ZvCX79JOglzdEy4JXMb98lq4hPxUbLr77nP0UOGf4rcMU+s1pUA==} @@ -2437,7 +2459,6 @@ packages: '@babel/runtime': 7.22.15 '@types/react': 18.2.21 react: 18.2.0 - dev: true /@radix-ui/react-focus-scope@1.0.3(@types/react@18.2.21)(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-upXdPfqI4islj2CslyfUBNlaJCPybbqRHAi1KER7Isel9Q2AtSJ0zRBZv8mWQiFXD2nyAJ4BhC3yXgZ6kMBSrQ==} @@ -2459,7 +2480,6 @@ packages: '@types/react': 18.2.21 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - dev: true /@radix-ui/react-id@1.0.1(@types/react@18.2.21)(react@18.2.0): resolution: {integrity: sha512-tI7sT/kqYp8p96yGWY1OAnLHrqDgzHefRBKQ2YAkBS5ja7QLcZ9Z/uY7bEjPUatf8RomoXM8/1sMj1IJaE5UzQ==} @@ -2474,7 +2494,43 @@ packages: '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.2.21)(react@18.2.0) '@types/react': 18.2.21 react: 18.2.0 - dev: true + + /@radix-ui/react-menu@2.0.5(@types/react@18.2.21)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-Gw4f9pwdH+w5w+49k0gLjN0PfRDHvxmAgG16AbyJZ7zhwZ6PBHKtWohvnSwfusfnK3L68dpBREHpVkj8wEM7ZA==} + 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 + dependencies: + '@babel/runtime': 7.22.15 + '@radix-ui/primitive': 1.0.1 + '@radix-ui/react-collection': 1.0.3(@types/react@18.2.21)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.21)(react@18.2.0) + '@radix-ui/react-context': 1.0.1(@types/react@18.2.21)(react@18.2.0) + '@radix-ui/react-direction': 1.0.1(@types/react@18.2.21)(react@18.2.0) + '@radix-ui/react-dismissable-layer': 1.0.4(@types/react@18.2.21)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-focus-guards': 1.0.1(@types/react@18.2.21)(react@18.2.0) + '@radix-ui/react-focus-scope': 1.0.3(@types/react@18.2.21)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-id': 1.0.1(@types/react@18.2.21)(react@18.2.0) + '@radix-ui/react-popper': 1.1.2(@types/react@18.2.21)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-portal': 1.0.3(@types/react@18.2.21)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-presence': 1.0.1(@types/react@18.2.21)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-primitive': 1.0.3(@types/react@18.2.21)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-roving-focus': 1.0.4(@types/react@18.2.21)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-slot': 1.0.2(@types/react@18.2.21)(react@18.2.0) + '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.21)(react@18.2.0) + '@types/react': 18.2.21 + aria-hidden: 1.2.3 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + react-remove-scroll: 2.5.5(@types/react@18.2.21)(react@18.2.0) + dev: false /@radix-ui/react-popper@1.1.2(@types/react@18.2.21)(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-1CnGGfFi/bbqtJZZ0P/NQY20xdG3E0LALJaLUEoKwPLwl6PPPfbeiCqMVQnhoFRAxjJj4RpBRJzDmUgsex2tSg==} @@ -2503,7 +2559,6 @@ packages: '@types/react': 18.2.21 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - dev: true /@radix-ui/react-portal@1.0.3(@types/react@18.2.21)(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-xLYZeHrWoPmA5mEKEfZZevoVRK/Q43GfzRXkWV6qawIWWK8t6ifIiLQdd7rmQ4Vk1bmI21XhqF9BN3jWf+phpA==} @@ -2523,7 +2578,27 @@ packages: '@types/react': 18.2.21 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - dev: true + + /@radix-ui/react-presence@1.0.1(@types/react@18.2.21)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-UXLW4UAbIY5ZjcvzjfRFo5gxva8QirC9hF7wRE4U5gz+TP0DbRk+//qyuAQ1McDxBt1xNMBTaciFGvEmJvAZCg==} + 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 + dependencies: + '@babel/runtime': 7.22.15 + '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.21)(react@18.2.0) + '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.2.21)(react@18.2.0) + '@types/react': 18.2.21 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false /@radix-ui/react-primitive@1.0.3(@types/react@18.2.21)(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-yi58uVyoAcK/Nq1inRY56ZSjKypBNKTa/1mcL8qdl6oJeEaDbOldlzrGn7P6Q3Id5d+SYNGc5AJgc4vGhjs5+g==} @@ -2543,7 +2618,6 @@ packages: '@types/react': 18.2.21 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - dev: true /@radix-ui/react-roving-focus@1.0.4(@types/react@18.2.21)(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-2mUg5Mgcu001VkGy+FfzZyzbmuUWzgWkj3rvv4yu+mLw03+mTzbxZHvfcGyFp2b8EkQeMkpRQ5FiA2Vr2O6TeQ==} @@ -2571,7 +2645,6 @@ packages: '@types/react': 18.2.21 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - dev: true /@radix-ui/react-select@1.2.2(@types/react@18.2.21)(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-zI7McXr8fNaSrUY9mZe4x/HC0jTLY9fWNhO1oLWYMQGDXuV4UCivIGTxwioSzO0ZCYX9iSLyWmAh/1TOmX3Cnw==} @@ -2733,7 +2806,6 @@ packages: '@babel/runtime': 7.22.15 '@types/react': 18.2.21 react: 18.2.0 - dev: true /@radix-ui/react-use-controllable-state@1.0.1(@types/react@18.2.21)(react@18.2.0): resolution: {integrity: sha512-Svl5GY5FQeN758fWKrjM6Qb7asvXeiZltlT4U2gVfl8Gx5UAv2sMR0LWo8yhsIZh2oQ0eFdZ59aoOOMV7b47VA==} @@ -2748,7 +2820,6 @@ packages: '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.21)(react@18.2.0) '@types/react': 18.2.21 react: 18.2.0 - dev: true /@radix-ui/react-use-escape-keydown@1.0.3(@types/react@18.2.21)(react@18.2.0): resolution: {integrity: sha512-vyL82j40hcFicA+M4Ex7hVkB9vHgSse1ZWomAqV2Je3RleKGO5iM8KMOEtfoSB0PnIelMd2lATjTGMYqN5ylTg==} @@ -2763,7 +2834,6 @@ packages: '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.21)(react@18.2.0) '@types/react': 18.2.21 react: 18.2.0 - dev: true /@radix-ui/react-use-layout-effect@1.0.1(@types/react@18.2.21)(react@18.2.0): resolution: {integrity: sha512-v/5RegiJWYdoCvMnITBkNNx6bCj20fiaJnWtRkU18yITptraXjffz5Qbn05uOiQnOvi+dbkznkoaMltz1GnszQ==} @@ -2777,7 +2847,6 @@ packages: '@babel/runtime': 7.22.15 '@types/react': 18.2.21 react: 18.2.0 - dev: true /@radix-ui/react-use-previous@1.0.1(@types/react@18.2.21)(react@18.2.0): resolution: {integrity: sha512-cV5La9DPwiQ7S0gf/0qiD6YgNqM5Fk97Kdrlc5yBcrF3jyEZQwm7vYFqMo4IfeHgJXsRaMvLABFtd0OVEmZhDw==} @@ -2806,7 +2875,6 @@ packages: '@radix-ui/rect': 1.0.1 '@types/react': 18.2.21 react: 18.2.0 - dev: true /@radix-ui/react-use-size@1.0.1(@types/react@18.2.21)(react@18.2.0): resolution: {integrity: sha512-ibay+VqrgcaI6veAojjofPATwledXiSmX+C0KrBk/xgpX9rBzPV3OsfwlhQdUOFbh+LKQorLYT+xTXW9V8yd0g==} @@ -2821,7 +2889,6 @@ packages: '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.2.21)(react@18.2.0) '@types/react': 18.2.21 react: 18.2.0 - dev: true /@radix-ui/react-visually-hidden@1.0.3(@types/react@18.2.21)(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-D4w41yN5YRKtu464TLnByKzMDG/JlMPHtfZgQAu9v6mNakUqGUI9vUrfQKz8NK41VMm/xbZbh76NUTVtIYqOMA==} @@ -2847,7 +2914,6 @@ packages: resolution: {integrity: sha512-fyrgCaedtvMg9NK3en0pnOYJdtfwxUcNolezkNPUsoX57X8oQk+NkqcvzHXD2uKNij6GXmWU9NDru2IWjrO4BQ==} dependencies: '@babel/runtime': 7.22.15 - dev: true /@sinclair/typebox@0.27.8: resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==} @@ -4987,7 +5053,6 @@ packages: engines: {node: '>=10'} dependencies: tslib: 2.6.2 - dev: true /aria-query@5.1.3: resolution: {integrity: sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==} @@ -6195,7 +6260,6 @@ packages: /detect-node-es@1.1.0: resolution: {integrity: sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==} - dev: true /detect-package-manager@2.0.1: resolution: {integrity: sha512-j/lJHyoLlWi6G1LDdLgvUtz60Zo5GEj+sVYtTVXnYLDPuzgC3llMxonXym9zIwhhUII8vjdw0LXxavpLqTbl1A==} @@ -7303,7 +7367,6 @@ packages: /get-nonce@1.0.1: resolution: {integrity: sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==} engines: {node: '>=6'} - dev: true /get-npm-tarball-url@2.0.3: resolution: {integrity: sha512-R/PW6RqyaBQNWYaSyfrh54/qtcnOp22FHCCiRhSSZj0FP3KQWCsxxt0DzIdVTbwTqe9CtQfvl/FPD4UIPt4pqw==} @@ -7746,7 +7809,6 @@ packages: resolution: {integrity: sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==} dependencies: loose-envify: 1.4.0 - dev: true /ip@2.0.0: resolution: {integrity: sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==} @@ -9112,6 +9174,18 @@ packages: resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} dev: true + /next-themes@0.2.1(next@13.4.19)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-B+AKNfYNIzh0vqQQKqQItTS8evEouKD7H5Hj3kmuPERwddR2TxvDSFZuTj6T7Jfn1oyeUyJMydPl1Bkxkh0W7A==} + peerDependencies: + next: '*' + react: '*' + react-dom: '*' + dependencies: + next: 13.4.19(@babel/core@7.22.17)(react-dom@18.2.0)(react@18.2.0) + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + /next@13.4.19(@babel/core@7.22.17)(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-HuPSzzAbJ1T4BD8e0bs6B9C1kWQ6gv8ykZoRWs5AQoiIuqbGHHdQO7Ljuvg05Q0Z24E2ABozHe6FxDvI6HfyAw==} engines: {node: '>=16.8.0'} @@ -10108,7 +10182,6 @@ packages: react: 18.2.0 react-style-singleton: 2.2.1(@types/react@18.2.21)(react@18.2.0) tslib: 2.6.2 - dev: true /react-remove-scroll@2.5.5(@types/react@18.2.21)(react@18.2.0): resolution: {integrity: sha512-ImKhrzJJsyXJfBZ4bzu8Bwpka14c/fQt0k+cyFp/PBhTfyDnU5hjOtM4AG/0AMyy8oKzOTR0lDgJIM7pYXI0kw==} @@ -10127,7 +10200,6 @@ packages: tslib: 2.6.2 use-callback-ref: 1.3.0(@types/react@18.2.21)(react@18.2.0) use-sidecar: 1.1.2(@types/react@18.2.21)(react@18.2.0) - dev: true /react-style-singleton@2.2.1(@types/react@18.2.21)(react@18.2.0): resolution: {integrity: sha512-ZWj0fHEMyWkHzKYUr2Bs/4zU6XLmq9HsgBURm7g5pAVfyn49DgUiNgY2d4lXRlYSiCif9YBGpQleewkcqddc7g==} @@ -10144,7 +10216,6 @@ packages: invariant: 2.2.4 react: 18.2.0 tslib: 2.6.2 - dev: true /react@18.2.0: resolution: {integrity: sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==} @@ -11550,7 +11621,6 @@ packages: '@types/react': 18.2.21 react: 18.2.0 tslib: 2.6.2 - dev: true /use-resize-observer@9.1.0(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-R25VqO9Wb3asSD4eqtcxk8sJalvIOYBqS8MNZlpDSQ4l4xMQxC/J7Id9HoTqPq8FwULIn0PVW+OAqF2dyYbjow==} @@ -11577,7 +11647,6 @@ packages: detect-node-es: 1.1.0 react: 18.2.0 tslib: 2.6.2 - dev: true /util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} diff --git a/postcss.config.js b/postcss.config.js new file mode 100644 index 00000000..12a703d9 --- /dev/null +++ b/postcss.config.js @@ -0,0 +1,6 @@ +module.exports = { + plugins: { + tailwindcss: {}, + autoprefixer: {}, + }, +}; diff --git a/src/app/globals.css b/src/app/globals.css index 54a7cf48..b7f454af 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -73,3 +73,16 @@ body, --ring: 0 0% 14.9%; } } + +@layer base { + * { + @apply border-border; + } + body { + @apply bg-background text-foreground; + } +} + +.container { + max-width: 1536px; +} diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 6d5b531a..c60df607 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -1,6 +1,8 @@ +import './globals.css'; import { Metadata } from 'next'; import { ReactNode } from 'react'; -import './globals.css'; +import { Navbar } from '@/components/layout/Navbar'; +import { ThemeProvider } from '@/components/theme/ThemeProvider'; export const metadata: Metadata = { title: 'react world', @@ -9,8 +11,15 @@ export const metadata: Metadata = { export default function RootLayout({ children }: { children: ReactNode }) { return ( - - {children} + + + +
+ + {children} +
+
+ ); } diff --git a/src/app/page.tsx b/src/app/page.tsx index 4272c1a8..6245b4bd 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -1,7 +1,17 @@ import React from 'react'; +import { PostCardList } from '@/components/home/PostCardList'; +import { TagList } from '@/components/home/TagList'; +import { TEMP_TAGS } from '@/constants'; const RootPage = () => { - return
RootPage
; + return ( +
+
+ + +
+
+ ); }; export default RootPage; diff --git a/src/components/home/PostCard/PostCard.stories.tsx b/src/components/home/PostCard/PostCard.stories.tsx new file mode 100644 index 00000000..5e5b9d04 --- /dev/null +++ b/src/components/home/PostCard/PostCard.stories.tsx @@ -0,0 +1,21 @@ +import { Meta, StoryObj } from '@storybook/react'; +import { PostCard } from '.'; +import { PostCardList } from '../PostCardList'; + +const sotryMeta: Meta = { + title: 'components/home/Postcard', + component: PostCard, + parameters: { + nextjs: { + appDirectory: true, + }, + }, +}; + +export default sotryMeta; + +type Story = StoryObj; + +export const Default: Story = { + args: {}, +}; diff --git a/src/components/home/PostCard/PostCard.tsx b/src/components/home/PostCard/PostCard.tsx new file mode 100644 index 00000000..c4fba5a1 --- /dev/null +++ b/src/components/home/PostCard/PostCard.tsx @@ -0,0 +1,29 @@ +import React from 'react'; +import Link from 'next/link'; +import { Badge } from '@/components/ui/Badge/Badge'; +// import Image from 'next/image'; +import { PostCardProps } from './PostCard.type'; +import { TEMP_CONTENT } from '@/constants'; + +export const PostCard = ({ post }: PostCardProps) => { + const { title, content } = post; + return ( +
+ {/* */} +
+
+
+ January 20th + tag +
+ +

{title}

+ + {content} + {TEMP_CONTENT} + + +
+
+ ); +}; diff --git a/src/components/home/PostCard/PostCard.type.ts b/src/components/home/PostCard/PostCard.type.ts new file mode 100644 index 00000000..5f43022f --- /dev/null +++ b/src/components/home/PostCard/PostCard.type.ts @@ -0,0 +1,6 @@ +export interface PostCardProps { + post: { + title: string; + content: string; + }; +} diff --git a/src/components/home/PostCard/index.ts b/src/components/home/PostCard/index.ts new file mode 100644 index 00000000..4add1a6c --- /dev/null +++ b/src/components/home/PostCard/index.ts @@ -0,0 +1 @@ +export * from './PostCard'; diff --git a/src/components/home/PostCardList/PostCardList.tsx b/src/components/home/PostCardList/PostCardList.tsx new file mode 100644 index 00000000..ed030540 --- /dev/null +++ b/src/components/home/PostCardList/PostCardList.tsx @@ -0,0 +1,15 @@ +'use client'; + +import React from 'react'; +import { TEMP_POSTS } from '@/constants'; +import { PostCard } from '../PostCard'; + +export const PostCardList = () => { + return ( +
+ {TEMP_POSTS.map((post, index) => ( + + ))} +
+ ); +}; diff --git a/src/components/home/PostCardList/index.ts b/src/components/home/PostCardList/index.ts new file mode 100644 index 00000000..813de803 --- /dev/null +++ b/src/components/home/PostCardList/index.ts @@ -0,0 +1 @@ +export * from './PostCardList'; diff --git a/src/components/home/TagList/TagList.stories.tsx b/src/components/home/TagList/TagList.stories.tsx new file mode 100644 index 00000000..b9ad89f7 --- /dev/null +++ b/src/components/home/TagList/TagList.stories.tsx @@ -0,0 +1,17 @@ +import { Meta, StoryObj } from '@storybook/react'; +import { TagList } from '.'; +import { TEMP_TAGS } from '@/constants'; + +const sotryMeta: Meta = { + title: 'components/home/TagList', + component: TagList, +}; +export default sotryMeta; + +type Story = StoryObj; + +export const Default: Story = { + args: { + tags: TEMP_TAGS, + }, +}; diff --git a/src/components/home/TagList/TagList.tsx b/src/components/home/TagList/TagList.tsx new file mode 100644 index 00000000..8e846bb2 --- /dev/null +++ b/src/components/home/TagList/TagList.tsx @@ -0,0 +1,18 @@ +'use client'; + +import React from 'react'; +import { Badge } from '@/components/ui/Badge/Badge'; +import { TagListProps } from './TagList.type'; + +export const TagList = ({ tags }: TagListProps) => { + return ( +
+

Popular Tags

+ {tags?.map((tag, index) => ( + + {tag} + + ))} +
+ ); +}; diff --git a/src/components/home/TagList/TagList.type.ts b/src/components/home/TagList/TagList.type.ts new file mode 100644 index 00000000..ee986bc4 --- /dev/null +++ b/src/components/home/TagList/TagList.type.ts @@ -0,0 +1,3 @@ +export interface TagListProps { + tags: string[]; // TODO: tag값 union type으로 변경 +} diff --git a/src/components/home/TagList/index.ts b/src/components/home/TagList/index.ts new file mode 100644 index 00000000..56ef6343 --- /dev/null +++ b/src/components/home/TagList/index.ts @@ -0,0 +1 @@ +export * from './TagList'; diff --git a/src/components/layout/Navbar/Navbar.stories.tsx b/src/components/layout/Navbar/Navbar.stories.tsx new file mode 100644 index 00000000..a7e46b25 --- /dev/null +++ b/src/components/layout/Navbar/Navbar.stories.tsx @@ -0,0 +1,20 @@ +import { Meta, StoryObj } from '@storybook/react'; +import { Navbar } from '.'; + +const sotryMeta: Meta = { + title: 'components/layout/Navbar', + component: Navbar, + parameters: { + nextjs: { + appDirectory: true, + }, + }, +}; + +export default sotryMeta; + +type Story = StoryObj; + +export const Default: Story = { + args: {}, +}; diff --git a/src/components/layout/Navbar/Navbar.tsx b/src/components/layout/Navbar/Navbar.tsx new file mode 100644 index 00000000..f4a6e0fa --- /dev/null +++ b/src/components/layout/Navbar/Navbar.tsx @@ -0,0 +1,32 @@ +'use client'; + +import React, { useState } from 'react'; +import { useRouter } from 'next/navigation'; +import { Button } from '@/components/ui/Button/Button'; +import { ModeToggle } from '@/components/theme/ThemeToggle'; + +export const Navbar = () => { + const router = useRouter(); + const [isLogin, setIsLogin] = useState(false); + + const handleButtonClick = () => { + if (isLogin) { + setIsLogin(false); + } else { + router.push('/sign-in'); + } + }; + + return ( +
+

Logo

+

Henlog

+
+ + +
+
+ ); +}; diff --git a/src/components/layout/Navbar/index.ts b/src/components/layout/Navbar/index.ts new file mode 100644 index 00000000..e8a65623 --- /dev/null +++ b/src/components/layout/Navbar/index.ts @@ -0,0 +1 @@ +export * from './Navbar'; diff --git a/src/components/theme/ThemeProvider.tsx b/src/components/theme/ThemeProvider.tsx new file mode 100644 index 00000000..f0c8a43b --- /dev/null +++ b/src/components/theme/ThemeProvider.tsx @@ -0,0 +1,9 @@ +'use client'; + +import * as React from 'react'; +import { ThemeProvider as NextThemesProvider } from 'next-themes'; +import { type ThemeProviderProps } from 'next-themes/dist/types'; + +export const ThemeProvider = ({ children, ...props }: ThemeProviderProps) => { + return {children}; +}; diff --git a/src/components/theme/ThemeToggle.tsx b/src/components/theme/ThemeToggle.tsx new file mode 100644 index 00000000..5e43a5be --- /dev/null +++ b/src/components/theme/ThemeToggle.tsx @@ -0,0 +1,40 @@ +'use client'; + +import * as React from 'react'; +import { Moon, Sun } from 'lucide-react'; +import { useTheme } from 'next-themes'; + +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuTrigger, +} from '../ui/Dropdown/DropdownMenu'; +import { Button } from '../ui/Button'; + +export function ModeToggle() { + const { setTheme } = useTheme(); + + return ( + + + + + + setTheme('light')}> + Light + + setTheme('dark')}> + Dark + + setTheme('system')}> + System + + + + ); +} diff --git a/src/components/ui/Badge/Badge.stories.tsx b/src/components/ui/Badge/Badge.stories.tsx new file mode 100644 index 00000000..91ce25ad --- /dev/null +++ b/src/components/ui/Badge/Badge.stories.tsx @@ -0,0 +1,47 @@ +import { Meta, StoryObj } from '@storybook/react'; +import { Badge } from './Badge'; + +const sotryMeta: Meta = { + title: 'components/ui/Badge', + component: Badge, + argTypes: { + variant: { + control: { + type: 'select', + options: ['default', 'secondary', 'destructive', 'outline'], + }, + }, + }, +}; + +export default sotryMeta; + +type Story = StoryObj; + +export const Default: Story = { + args: { + children: 'Badge', + variant: 'default', + }, +}; + +export const Secondary: Story = { + args: { + children: 'Badge', + variant: 'secondary', + }, +}; + +export const Destructive: Story = { + args: { + children: 'Badge', + variant: 'destructive', + }, +}; + +export const Outline: Story = { + args: { + children: 'Badge', + variant: 'outline', + }, +}; diff --git a/src/components/ui/Badge/Badge.styles.ts b/src/components/ui/Badge/Badge.styles.ts new file mode 100644 index 00000000..022671a3 --- /dev/null +++ b/src/components/ui/Badge/Badge.styles.ts @@ -0,0 +1,21 @@ +import { cva, type VariantProps } from 'class-variance-authority'; + +export const badgeVariants = cva( + 'inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2', + { + variants: { + variant: { + default: + 'border-transparent bg-primary text-primary-foreground hover:bg-primary/80', + secondary: + 'border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80', + destructive: + 'border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80', + outline: 'text-foreground', + }, + }, + defaultVariants: { + variant: 'default', + }, + }, +); diff --git a/src/components/ui/Badge/Badge.tsx b/src/components/ui/Badge/Badge.tsx new file mode 100644 index 00000000..5754e9f3 --- /dev/null +++ b/src/components/ui/Badge/Badge.tsx @@ -0,0 +1,13 @@ +import * as React from 'react'; + +import { cn } from '@/lib/utils'; +import { badgeVariants } from './Badge.styles'; +import { BadgeProps } from './Badge.type'; + +function Badge({ className, variant, ...props }: BadgeProps) { + return ( +
+ ); +} + +export { Badge, badgeVariants }; diff --git a/src/components/ui/Badge/Badge.type.ts b/src/components/ui/Badge/Badge.type.ts new file mode 100644 index 00000000..f6349065 --- /dev/null +++ b/src/components/ui/Badge/Badge.type.ts @@ -0,0 +1,6 @@ +import { type VariantProps } from 'class-variance-authority'; +import { badgeVariants } from './Badge.styles'; + +export interface BadgeProps + extends React.HTMLAttributes, + VariantProps {} diff --git a/src/components/ui/Button/Button.stories.tsx b/src/components/ui/Button/Button.stories.tsx index 60693211..c9a4baa3 100644 --- a/src/components/ui/Button/Button.stories.tsx +++ b/src/components/ui/Button/Button.stories.tsx @@ -8,7 +8,7 @@ const sotryMeta: Meta = { variant: { control: { type: 'select', - options: ['default', 'outline'], + options: ['default', 'outline', 'ghost'], }, }, size: { @@ -38,6 +38,13 @@ export const OutlineButton: Story = { }, }; +export const GhostButton: Story = { + args: { + variant: 'ghost', + children: 'ghost', + }, +}; + export const SmallButton: Story = { args: { size: 'sm', diff --git a/src/components/ui/Button/Button.styles.ts b/src/components/ui/Button/Button.styles.ts index 49bf11da..391e0f13 100644 --- a/src/components/ui/Button/Button.styles.ts +++ b/src/components/ui/Button/Button.styles.ts @@ -8,11 +8,13 @@ export const buttonVariants = cva( default: 'bg-primary text-primary-foreground hover:bg-primary/90', outline: 'border border-input bg-background hover:bg-accent hover:text-accent-foreground', + ghost: 'hover:bg-accent hover:text-accent-foreground', }, size: { default: 'h-10 px-4 py-2', sm: 'h-9 rounded-md px-3', lg: 'h-11 rounded-md px-8', + icon: 'h-10 w-10', }, }, defaultVariants: { diff --git a/src/components/ui/Button/Button.tsx b/src/components/ui/Button/Button.tsx index 8d1e97cb..c941ff96 100644 --- a/src/components/ui/Button/Button.tsx +++ b/src/components/ui/Button/Button.tsx @@ -4,7 +4,7 @@ import { cn } from '@/lib/utils'; import { ButtonProps } from './Button.type'; import { buttonVariants } from './Button.styles'; -const Button = React.forwardRef( +export const Button = React.forwardRef( ({ className, variant, size, asChild = false, ...props }, ref) => { const Comp = asChild ? Slot : 'button'; return ( @@ -17,5 +17,3 @@ const Button = React.forwardRef( }, ); Button.displayName = 'Button'; - -export { Button, buttonVariants }; diff --git a/src/components/ui/Button/index.ts b/src/components/ui/Button/index.ts new file mode 100644 index 00000000..8b166a86 --- /dev/null +++ b/src/components/ui/Button/index.ts @@ -0,0 +1 @@ +export * from './Button'; diff --git a/src/components/ui/Dropdown/DropdownMenu.tsx b/src/components/ui/Dropdown/DropdownMenu.tsx new file mode 100644 index 00000000..f3749b26 --- /dev/null +++ b/src/components/ui/Dropdown/DropdownMenu.tsx @@ -0,0 +1,200 @@ +'use client'; + +import * as React from 'react'; +import * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu'; +import { Check, ChevronRight, Circle } from 'lucide-react'; + +import { cn } from '@/lib/utils'; + +const DropdownMenu = DropdownMenuPrimitive.Root; + +const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger; + +const DropdownMenuGroup = DropdownMenuPrimitive.Group; + +const DropdownMenuPortal = DropdownMenuPrimitive.Portal; + +const DropdownMenuSub = DropdownMenuPrimitive.Sub; + +const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup; + +const DropdownMenuSubTrigger = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef & { + inset?: boolean; + } +>(({ className, inset, children, ...props }, ref) => ( + + {children} + + +)); +DropdownMenuSubTrigger.displayName = + DropdownMenuPrimitive.SubTrigger.displayName; + +const DropdownMenuSubContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +DropdownMenuSubContent.displayName = + DropdownMenuPrimitive.SubContent.displayName; + +const DropdownMenuContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, sideOffset = 4, ...props }, ref) => ( + + + +)); +DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName; + +const DropdownMenuItem = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef & { + inset?: boolean; + } +>(({ className, inset, ...props }, ref) => ( + +)); +DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName; + +const DropdownMenuCheckboxItem = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, checked, ...props }, ref) => ( + + + + + + + {children} + +)); +DropdownMenuCheckboxItem.displayName = + DropdownMenuPrimitive.CheckboxItem.displayName; + +const DropdownMenuRadioItem = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, ...props }, ref) => ( + + + + + + + {children} + +)); +DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName; + +const DropdownMenuLabel = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef & { + inset?: boolean; + } +>(({ className, inset, ...props }, ref) => ( + +)); +DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName; + +const DropdownMenuSeparator = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName; + +const DropdownMenuShortcut = ({ + className, + ...props +}: React.HTMLAttributes) => { + return ( + + ); +}; +DropdownMenuShortcut.displayName = 'DropdownMenuShortcut'; + +export { + DropdownMenu, + DropdownMenuTrigger, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuCheckboxItem, + DropdownMenuRadioItem, + DropdownMenuLabel, + DropdownMenuSeparator, + DropdownMenuShortcut, + DropdownMenuGroup, + DropdownMenuPortal, + DropdownMenuSub, + DropdownMenuSubContent, + DropdownMenuSubTrigger, + DropdownMenuRadioGroup, +}; diff --git a/src/constants/index.ts b/src/constants/index.ts new file mode 100644 index 00000000..545f2b88 --- /dev/null +++ b/src/constants/index.ts @@ -0,0 +1,11 @@ +export const TEMP_POSTS = [ + { title: 'title1', content: 'content1' }, + { title: 'title2', content: 'content2' }, + { title: 'title3', content: 'content3' }, +]; + +export const TEMP_CONTENT = + 'Lorem ipsum dolor sit amet consectetur adipisicing elit Exercitationem sint soluta laudantium porro inventore sit debitis voluptates, nam perferendis cupiditate dolor minus doloribus quia voluptatibus ab voluptas? Saepe, magnam numquam.Lorem ipsum dolor sit amet consectetur adipisicing elit. Exercitationem sint soluta laudantium porro inventore sit debitis voluptates, nam perferendis cupiditate dolor minus doloribus quia voluptatibus ab voluptas? Saepe, magnam numquam.'; + + export const TEMP_TAGS = ['programming', 'react', 'javascript', 'typescript']; + \ No newline at end of file