diff --git a/client/components.json b/client/components.json
new file mode 100644
index 0000000..597fc69
--- /dev/null
+++ b/client/components.json
@@ -0,0 +1,17 @@
+{
+ "$schema": "https://ui.shadcn.com/schema.json",
+ "style": "default",
+ "rsc": true,
+ "tsx": true,
+ "tailwind": {
+ "config": "tailwind.config.ts",
+ "css": "src/app/globals.css",
+ "baseColor": "slate",
+ "cssVariables": true,
+ "prefix": ""
+ },
+ "aliases": {
+ "components": "~/components",
+ "utils": "~/lib/utils"
+ }
+}
\ No newline at end of file
diff --git a/client/next.config.mjs b/client/next.config.mjs
index 4678774..b78abe2 100644
--- a/client/next.config.mjs
+++ b/client/next.config.mjs
@@ -1,4 +1,13 @@
/** @type {import('next').NextConfig} */
-const nextConfig = {};
+const nextConfig = {
+ images: {
+ remotePatterns: [
+ {
+ protocol: 'https',
+ hostname: 'ui-avatars.com',
+ }
+ ]
+ }
+};
export default nextConfig;
diff --git a/client/package.json b/client/package.json
index c6c38a6..8bb0a01 100644
--- a/client/package.json
+++ b/client/package.json
@@ -9,19 +9,33 @@
"lint": "next lint"
},
"dependencies": {
+ "@clerk/clerk-react": "^4.16.3",
+ "@clerk/nextjs": "^4.29.9",
+ "@radix-ui/react-collapsible": "^1.0.3",
+ "@radix-ui/react-dialog": "^1.0.5",
+ "@radix-ui/react-label": "^2.0.2",
+ "@radix-ui/react-separator": "^1.0.3",
+ "@radix-ui/react-slot": "^1.0.2",
+ "class-variance-authority": "^0.7.0",
+ "clsx": "^2.1.0",
+ "lucide-react": "^0.363.0",
+ "next": "14.1.4",
"react": "^18",
"react-dom": "^18",
- "next": "14.1.4"
+ "react-icons": "^5.0.1",
+ "tailwind-merge": "^2.2.2",
+ "tailwindcss-animate": "^1.0.7",
+ "zod": "^3.22.4"
},
"devDependencies": {
- "typescript": "^5",
- "@types/node": "^20",
- "@types/react": "^18",
+ "@types/node": "^20.11.30",
+ "@types/react": "^18.2.67",
"@types/react-dom": "^18",
"autoprefixer": "^10.0.1",
+ "eslint": "^8",
+ "eslint-config-next": "14.1.4",
"postcss": "^8",
"tailwindcss": "^3.3.0",
- "eslint": "^8",
- "eslint-config-next": "14.1.4"
+ "typescript": "^5.4.3"
}
}
diff --git a/client/pnpm-lock.yaml b/client/pnpm-lock.yaml
index 188c815..28e6a94 100644
--- a/client/pnpm-lock.yaml
+++ b/client/pnpm-lock.yaml
@@ -5,6 +5,36 @@ settings:
excludeLinksFromLockfile: false
dependencies:
+ '@clerk/clerk-react':
+ specifier: ^4.16.3
+ version: 4.30.7(react@18.2.0)
+ '@clerk/nextjs':
+ specifier: ^4.29.9
+ version: 4.29.9(next@14.1.4)(react-dom@18.2.0)(react@18.2.0)
+ '@radix-ui/react-collapsible':
+ specifier: ^1.0.3
+ version: 1.0.3(@types/react-dom@18.2.22)(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0)
+ '@radix-ui/react-dialog':
+ specifier: ^1.0.5
+ version: 1.0.5(@types/react-dom@18.2.22)(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0)
+ '@radix-ui/react-label':
+ specifier: ^2.0.2
+ version: 2.0.2(@types/react-dom@18.2.22)(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0)
+ '@radix-ui/react-separator':
+ specifier: ^1.0.3
+ version: 1.0.3(@types/react-dom@18.2.22)(@types/react@18.2.67)(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.67)(react@18.2.0)
+ class-variance-authority:
+ specifier: ^0.7.0
+ version: 0.7.0
+ clsx:
+ specifier: ^2.1.0
+ version: 2.1.0
+ lucide-react:
+ specifier: ^0.363.0
+ version: 0.363.0(react@18.2.0)
next:
specifier: 14.1.4
version: 14.1.4(react-dom@18.2.0)(react@18.2.0)
@@ -14,13 +44,25 @@ dependencies:
react-dom:
specifier: ^18
version: 18.2.0(react@18.2.0)
+ react-icons:
+ specifier: ^5.0.1
+ version: 5.0.1(react@18.2.0)
+ tailwind-merge:
+ specifier: ^2.2.2
+ version: 2.2.2
+ tailwindcss-animate:
+ specifier: ^1.0.7
+ version: 1.0.7(tailwindcss@3.4.1)
+ zod:
+ specifier: ^3.22.4
+ version: 3.22.4
devDependencies:
'@types/node':
- specifier: ^20
+ specifier: ^20.11.30
version: 20.11.30
'@types/react':
- specifier: ^18
+ specifier: ^18.2.67
version: 18.2.67
'@types/react-dom':
specifier: ^18
@@ -41,7 +83,7 @@ devDependencies:
specifier: ^3.3.0
version: 3.4.1
typescript:
- specifier: ^5
+ specifier: ^5.4.3
version: 5.4.3
packages:
@@ -54,14 +96,99 @@ packages:
/@alloc/quick-lru@5.2.0:
resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==}
engines: {node: '>=10'}
- dev: true
/@babel/runtime@7.24.1:
resolution: {integrity: sha512-+BIznRzyqBf+2wCTxcKE3wDjfGeCoVE61KSHGpkzqrLi8qxqFwBeUFyId2cxkTmm55fzDGnm0+yCxaxygrLUnQ==}
engines: {node: '>=6.9.0'}
dependencies:
regenerator-runtime: 0.14.1
- dev: true
+
+ /@clerk/backend@0.38.3(react@18.2.0):
+ resolution: {integrity: sha512-k14WRljVNETpIYrt99MBP/Zd7KEwkudQKSCEMatQbiRkWgrpwDWE8Czv+JzF1J7sdMiicBI+p2ph9biX1EOFzw==}
+ engines: {node: '>=14'}
+ dependencies:
+ '@clerk/shared': 1.3.3(react@18.2.0)
+ '@clerk/types': 3.62.1
+ '@peculiar/webcrypto': 1.4.1
+ '@types/node': 16.18.6
+ cookie: 0.5.0
+ deepmerge: 4.2.2
+ node-fetch-native: 1.0.1
+ snakecase-keys: 5.4.4
+ tslib: 2.4.1
+ transitivePeerDependencies:
+ - react
+ dev: false
+
+ /@clerk/clerk-react@4.30.7(react@18.2.0):
+ resolution: {integrity: sha512-+6Q1hVteqn66gFLiCKSqqSdz2MBjsEjs1fkGLAEKZC1GdfOKrH6oWcLuSwUdyqRvJWuyjeIgwq15zoHtXKyztA==}
+ engines: {node: '>=14'}
+ peerDependencies:
+ react: '>=16'
+ dependencies:
+ '@clerk/shared': 1.3.3(react@18.2.0)
+ '@clerk/types': 3.62.1
+ react: 18.2.0
+ tslib: 2.4.1
+ dev: false
+
+ /@clerk/clerk-sdk-node@4.13.11(react@18.2.0):
+ resolution: {integrity: sha512-6CiRx61SW0B7i+4STlID537LvwFJvNGWxxQZY96OPHQnvYGYsp+9PdEyY4zaQiyLQBLYJt1+uc7VsdSYY5Omww==}
+ engines: {node: '>=14'}
+ dependencies:
+ '@clerk/backend': 0.38.3(react@18.2.0)
+ '@clerk/shared': 1.3.3(react@18.2.0)
+ '@clerk/types': 3.62.1
+ '@types/cookies': 0.7.7
+ '@types/express': 4.17.14
+ '@types/node-fetch': 2.6.2
+ camelcase-keys: 6.2.2
+ snakecase-keys: 3.2.1
+ tslib: 2.4.1
+ transitivePeerDependencies:
+ - react
+ dev: false
+
+ /@clerk/nextjs@4.29.9(next@14.1.4)(react-dom@18.2.0)(react@18.2.0):
+ resolution: {integrity: sha512-RsOz+lxlPYJi9cBvhBRqAUVUOMBT20R3ppt3eof97DkqCT6YaHJx/S13XcYUuo6ojYRDDJ/nI6XiLcfpqIJO6g==}
+ engines: {node: '>=14'}
+ peerDependencies:
+ next: '>=10'
+ react: ^17.0.2 || ^18.0.0-0
+ react-dom: ^17.0.2 || ^18.0.0-0
+ dependencies:
+ '@clerk/backend': 0.38.3(react@18.2.0)
+ '@clerk/clerk-react': 4.30.7(react@18.2.0)
+ '@clerk/clerk-sdk-node': 4.13.11(react@18.2.0)
+ '@clerk/shared': 1.3.3(react@18.2.0)
+ '@clerk/types': 3.62.1
+ next: 14.1.4(react-dom@18.2.0)(react@18.2.0)
+ path-to-regexp: 6.2.1
+ react: 18.2.0
+ react-dom: 18.2.0(react@18.2.0)
+ tslib: 2.4.1
+ dev: false
+
+ /@clerk/shared@1.3.3(react@18.2.0):
+ resolution: {integrity: sha512-Eein8cK72dlvY6Q1uFuw9K9MJH1OPjU8FzWloMTKklBo+iPiM6+uENGeGwlY5KId3q/kgPwRc2hBQnUoaijxCQ==}
+ peerDependencies:
+ react: '>=16'
+ peerDependenciesMeta:
+ react:
+ optional: true
+ dependencies:
+ glob-to-regexp: 0.4.1
+ js-cookie: 3.0.1
+ react: 18.2.0
+ swr: 2.2.0(react@18.2.0)
+ dev: false
+
+ /@clerk/types@3.62.1:
+ resolution: {integrity: sha512-RmQhWB7EMZw2nE24viQG79VyEUULZYWndYew5oXiZx06DyvysMNCorDyEGRmgBbprv7bnbYhHdOtKmx8Wj0jug==}
+ engines: {node: '>=14'}
+ dependencies:
+ csstype: 3.1.1
+ dev: false
/@eslint-community/eslint-utils@4.4.0(eslint@8.57.0):
resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==}
@@ -130,7 +257,6 @@ packages:
strip-ansi-cjs: /strip-ansi@6.0.1
wrap-ansi: 8.1.0
wrap-ansi-cjs: /wrap-ansi@7.0.0
- dev: true
/@jridgewell/gen-mapping@0.3.5:
resolution: {integrity: sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==}
@@ -139,28 +265,23 @@ packages:
'@jridgewell/set-array': 1.2.1
'@jridgewell/sourcemap-codec': 1.4.15
'@jridgewell/trace-mapping': 0.3.25
- dev: true
/@jridgewell/resolve-uri@3.1.2:
resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==}
engines: {node: '>=6.0.0'}
- dev: true
/@jridgewell/set-array@1.2.1:
resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==}
engines: {node: '>=6.0.0'}
- dev: true
/@jridgewell/sourcemap-codec@1.4.15:
resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==}
- dev: true
/@jridgewell/trace-mapping@0.3.25:
resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==}
dependencies:
'@jridgewell/resolve-uri': 3.1.2
'@jridgewell/sourcemap-codec': 1.4.15
- dev: true
/@next/env@14.1.4:
resolution: {integrity: sha512-e7X7bbn3Z6DWnDi75UWn+REgAbLEqxI8Tq2pkFOFAMpWAWApz/YCUhtWMWn410h8Q2fYiYL7Yg5OlxMOCfFjJQ==}
@@ -259,12 +380,10 @@ packages:
dependencies:
'@nodelib/fs.stat': 2.0.5
run-parallel: 1.2.0
- dev: true
/@nodelib/fs.stat@2.0.5:
resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==}
engines: {node: '>= 8'}
- dev: true
/@nodelib/fs.walk@1.2.8:
resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==}
@@ -272,15 +391,391 @@ packages:
dependencies:
'@nodelib/fs.scandir': 2.1.5
fastq: 1.17.1
- dev: true
+
+ /@peculiar/asn1-schema@2.3.8:
+ resolution: {integrity: sha512-ULB1XqHKx1WBU/tTFIA+uARuRoBVZ4pNdOA878RDrRbBfBGcSzi5HBkdScC6ZbHn8z7L8gmKCgPC1LHRrP46tA==}
+ dependencies:
+ asn1js: 3.0.5
+ pvtsutils: 1.3.5
+ tslib: 2.6.2
+ dev: false
+
+ /@peculiar/json-schema@1.1.12:
+ resolution: {integrity: sha512-coUfuoMeIB7B8/NMekxaDzLhaYmp0HZNPEjYRm9goRou8UZIC3z21s0sL9AWoCw4EG876QyO3kYrc61WNF9B/w==}
+ engines: {node: '>=8.0.0'}
+ dependencies:
+ tslib: 2.6.2
+ dev: false
+
+ /@peculiar/webcrypto@1.4.1:
+ resolution: {integrity: sha512-eK4C6WTNYxoI7JOabMoZICiyqRRtJB220bh0Mbj5RwRycleZf9BPyZoxsTvpP0FpmVS2aS13NKOuh5/tN3sIRw==}
+ engines: {node: '>=10.12.0'}
+ dependencies:
+ '@peculiar/asn1-schema': 2.3.8
+ '@peculiar/json-schema': 1.1.12
+ pvtsutils: 1.3.5
+ tslib: 2.6.2
+ webcrypto-core: 1.7.8
+ dev: false
/@pkgjs/parseargs@0.11.0:
resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==}
engines: {node: '>=14'}
requiresBuild: true
- dev: true
optional: true
+ /@radix-ui/primitive@1.0.1:
+ resolution: {integrity: sha512-yQ8oGX2GVsEYMWGxcovu1uGWPCxV5BFfeeYxqPmuAzUyLT9qmaMXSAhXpb0WrspIeqYzdJpkh2vHModJPgRIaw==}
+ dependencies:
+ '@babel/runtime': 7.24.1
+ dev: false
+
+ /@radix-ui/react-collapsible@1.0.3(@types/react-dom@18.2.22)(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0):
+ resolution: {integrity: sha512-UBmVDkmR6IvDsloHVN+3rtx4Mi5TFvylYXpluuv0f37dtaz3H99bp8No0LGXRigVpl3UAT4l9j6bIchh42S/Gg==}
+ 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.24.1
+ '@radix-ui/primitive': 1.0.1
+ '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.67)(react@18.2.0)
+ '@radix-ui/react-context': 1.0.1(@types/react@18.2.67)(react@18.2.0)
+ '@radix-ui/react-id': 1.0.1(@types/react@18.2.67)(react@18.2.0)
+ '@radix-ui/react-presence': 1.0.1(@types/react-dom@18.2.22)(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0)
+ '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.22)(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0)
+ '@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.2.67)(react@18.2.0)
+ '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.2.67)(react@18.2.0)
+ '@types/react': 18.2.67
+ '@types/react-dom': 18.2.22
+ react: 18.2.0
+ react-dom: 18.2.0(react@18.2.0)
+ dev: false
+
+ /@radix-ui/react-compose-refs@1.0.1(@types/react@18.2.67)(react@18.2.0):
+ resolution: {integrity: sha512-fDSBgd44FKHa1FRMU59qBMPFcl2PZE+2nmqunj+BWFyYYjnhIDWL2ItDs3rrbJDQOtzt5nIebLCQc4QRfz6LJw==}
+ peerDependencies:
+ '@types/react': '*'
+ react: ^16.8 || ^17.0 || ^18.0
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+ dependencies:
+ '@babel/runtime': 7.24.1
+ '@types/react': 18.2.67
+ react: 18.2.0
+ dev: false
+
+ /@radix-ui/react-context@1.0.1(@types/react@18.2.67)(react@18.2.0):
+ resolution: {integrity: sha512-ebbrdFoYTcuZ0v4wG5tedGnp9tzcV8awzsxYph7gXUyvnNLuTIcCk1q17JEbnVhXAKG9oX3KtchwiMIAYp9NLg==}
+ peerDependencies:
+ '@types/react': '*'
+ react: ^16.8 || ^17.0 || ^18.0
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+ dependencies:
+ '@babel/runtime': 7.24.1
+ '@types/react': 18.2.67
+ react: 18.2.0
+ dev: false
+
+ /@radix-ui/react-dialog@1.0.5(@types/react-dom@18.2.22)(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0):
+ resolution: {integrity: sha512-GjWJX/AUpB703eEBanuBnIWdIXg6NvJFCXcNlSZk4xdszCdhrJgBoUd1cGk67vFO+WdA2pfI/plOpqz/5GUP6Q==}
+ 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.24.1
+ '@radix-ui/primitive': 1.0.1
+ '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.67)(react@18.2.0)
+ '@radix-ui/react-context': 1.0.1(@types/react@18.2.67)(react@18.2.0)
+ '@radix-ui/react-dismissable-layer': 1.0.5(@types/react-dom@18.2.22)(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0)
+ '@radix-ui/react-focus-guards': 1.0.1(@types/react@18.2.67)(react@18.2.0)
+ '@radix-ui/react-focus-scope': 1.0.4(@types/react-dom@18.2.22)(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0)
+ '@radix-ui/react-id': 1.0.1(@types/react@18.2.67)(react@18.2.0)
+ '@radix-ui/react-portal': 1.0.4(@types/react-dom@18.2.22)(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0)
+ '@radix-ui/react-presence': 1.0.1(@types/react-dom@18.2.22)(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0)
+ '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.22)(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0)
+ '@radix-ui/react-slot': 1.0.2(@types/react@18.2.67)(react@18.2.0)
+ '@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.2.67)(react@18.2.0)
+ '@types/react': 18.2.67
+ '@types/react-dom': 18.2.22
+ aria-hidden: 1.2.4
+ react: 18.2.0
+ react-dom: 18.2.0(react@18.2.0)
+ react-remove-scroll: 2.5.5(@types/react@18.2.67)(react@18.2.0)
+ dev: false
+
+ /@radix-ui/react-dismissable-layer@1.0.5(@types/react-dom@18.2.22)(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0):
+ resolution: {integrity: sha512-aJeDjQhywg9LBu2t/At58hCvr7pEm0o2Ke1x33B+MhjNmmZ17sy4KImo0KPLgsnc/zN7GPdce8Cnn0SWvwZO7g==}
+ 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.24.1
+ '@radix-ui/primitive': 1.0.1
+ '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.67)(react@18.2.0)
+ '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.22)(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0)
+ '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.67)(react@18.2.0)
+ '@radix-ui/react-use-escape-keydown': 1.0.3(@types/react@18.2.67)(react@18.2.0)
+ '@types/react': 18.2.67
+ '@types/react-dom': 18.2.22
+ 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.67)(react@18.2.0):
+ resolution: {integrity: sha512-Rect2dWbQ8waGzhMavsIbmSVCgYxkXLxxR3ZvCX79JOglzdEy4JXMb98lq4hPxUbLr77nP0UOGf4rcMU+s1pUA==}
+ peerDependencies:
+ '@types/react': '*'
+ react: ^16.8 || ^17.0 || ^18.0
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+ dependencies:
+ '@babel/runtime': 7.24.1
+ '@types/react': 18.2.67
+ react: 18.2.0
+ dev: false
+
+ /@radix-ui/react-focus-scope@1.0.4(@types/react-dom@18.2.22)(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0):
+ resolution: {integrity: sha512-sL04Mgvf+FmyvZeYfNu1EPAaaxD+aw7cYeIB9L9Fvq8+urhltTRaEo5ysKOpHuKPclsZcSUMKlN05x4u+CINpA==}
+ 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.24.1
+ '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.67)(react@18.2.0)
+ '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.22)(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0)
+ '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.67)(react@18.2.0)
+ '@types/react': 18.2.67
+ '@types/react-dom': 18.2.22
+ react: 18.2.0
+ react-dom: 18.2.0(react@18.2.0)
+ dev: false
+
+ /@radix-ui/react-id@1.0.1(@types/react@18.2.67)(react@18.2.0):
+ resolution: {integrity: sha512-tI7sT/kqYp8p96yGWY1OAnLHrqDgzHefRBKQ2YAkBS5ja7QLcZ9Z/uY7bEjPUatf8RomoXM8/1sMj1IJaE5UzQ==}
+ peerDependencies:
+ '@types/react': '*'
+ react: ^16.8 || ^17.0 || ^18.0
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+ dependencies:
+ '@babel/runtime': 7.24.1
+ '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.2.67)(react@18.2.0)
+ '@types/react': 18.2.67
+ react: 18.2.0
+ dev: false
+
+ /@radix-ui/react-label@2.0.2(@types/react-dom@18.2.22)(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0):
+ resolution: {integrity: sha512-N5ehvlM7qoTLx7nWPodsPYPgMzA5WM8zZChQg8nyFJKnDO5WHdba1vv5/H6IO5LtJMfD2Q3wh1qHFGNtK0w3bQ==}
+ 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.24.1
+ '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.22)(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0)
+ '@types/react': 18.2.67
+ '@types/react-dom': 18.2.22
+ react: 18.2.0
+ react-dom: 18.2.0(react@18.2.0)
+ dev: false
+
+ /@radix-ui/react-portal@1.0.4(@types/react-dom@18.2.22)(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0):
+ resolution: {integrity: sha512-Qki+C/EuGUVCQTOTD5vzJzJuMUlewbzuKyUy+/iHM2uwGiru9gZeBJtHAPKAEkB5KWGi9mP/CHKcY0wt1aW45Q==}
+ 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.24.1
+ '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.22)(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0)
+ '@types/react': 18.2.67
+ '@types/react-dom': 18.2.22
+ react: 18.2.0
+ react-dom: 18.2.0(react@18.2.0)
+ dev: false
+
+ /@radix-ui/react-presence@1.0.1(@types/react-dom@18.2.22)(@types/react@18.2.67)(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.24.1
+ '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.67)(react@18.2.0)
+ '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.2.67)(react@18.2.0)
+ '@types/react': 18.2.67
+ '@types/react-dom': 18.2.22
+ react: 18.2.0
+ react-dom: 18.2.0(react@18.2.0)
+ dev: false
+
+ /@radix-ui/react-primitive@1.0.3(@types/react-dom@18.2.22)(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0):
+ resolution: {integrity: sha512-yi58uVyoAcK/Nq1inRY56ZSjKypBNKTa/1mcL8qdl6oJeEaDbOldlzrGn7P6Q3Id5d+SYNGc5AJgc4vGhjs5+g==}
+ 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.24.1
+ '@radix-ui/react-slot': 1.0.2(@types/react@18.2.67)(react@18.2.0)
+ '@types/react': 18.2.67
+ '@types/react-dom': 18.2.22
+ react: 18.2.0
+ react-dom: 18.2.0(react@18.2.0)
+ dev: false
+
+ /@radix-ui/react-separator@1.0.3(@types/react-dom@18.2.22)(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0):
+ resolution: {integrity: sha512-itYmTy/kokS21aiV5+Z56MZB54KrhPgn6eHDKkFeOLR34HMN2s8PaN47qZZAGnvupcjxHaFZnW4pQEh0BvvVuw==}
+ 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.24.1
+ '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.22)(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0)
+ '@types/react': 18.2.67
+ '@types/react-dom': 18.2.22
+ react: 18.2.0
+ react-dom: 18.2.0(react@18.2.0)
+ dev: false
+
+ /@radix-ui/react-slot@1.0.2(@types/react@18.2.67)(react@18.2.0):
+ resolution: {integrity: sha512-YeTpuq4deV+6DusvVUW4ivBgnkHwECUu0BiN43L5UCDFgdhsRUWAghhTF5MbvNTPzmiFOx90asDSUjWuCNapwg==}
+ peerDependencies:
+ '@types/react': '*'
+ react: ^16.8 || ^17.0 || ^18.0
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+ dependencies:
+ '@babel/runtime': 7.24.1
+ '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.67)(react@18.2.0)
+ '@types/react': 18.2.67
+ react: 18.2.0
+ dev: false
+
+ /@radix-ui/react-use-callback-ref@1.0.1(@types/react@18.2.67)(react@18.2.0):
+ resolution: {integrity: sha512-D94LjX4Sp0xJFVaoQOd3OO9k7tpBYNOXdVhkltUbGv2Qb9OXdrg/CpsjlZv7ia14Sylv398LswWBVVu5nqKzAQ==}
+ peerDependencies:
+ '@types/react': '*'
+ react: ^16.8 || ^17.0 || ^18.0
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+ dependencies:
+ '@babel/runtime': 7.24.1
+ '@types/react': 18.2.67
+ react: 18.2.0
+ dev: false
+
+ /@radix-ui/react-use-controllable-state@1.0.1(@types/react@18.2.67)(react@18.2.0):
+ resolution: {integrity: sha512-Svl5GY5FQeN758fWKrjM6Qb7asvXeiZltlT4U2gVfl8Gx5UAv2sMR0LWo8yhsIZh2oQ0eFdZ59aoOOMV7b47VA==}
+ peerDependencies:
+ '@types/react': '*'
+ react: ^16.8 || ^17.0 || ^18.0
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+ dependencies:
+ '@babel/runtime': 7.24.1
+ '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.67)(react@18.2.0)
+ '@types/react': 18.2.67
+ react: 18.2.0
+ dev: false
+
+ /@radix-ui/react-use-escape-keydown@1.0.3(@types/react@18.2.67)(react@18.2.0):
+ resolution: {integrity: sha512-vyL82j40hcFicA+M4Ex7hVkB9vHgSse1ZWomAqV2Je3RleKGO5iM8KMOEtfoSB0PnIelMd2lATjTGMYqN5ylTg==}
+ peerDependencies:
+ '@types/react': '*'
+ react: ^16.8 || ^17.0 || ^18.0
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+ dependencies:
+ '@babel/runtime': 7.24.1
+ '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.67)(react@18.2.0)
+ '@types/react': 18.2.67
+ react: 18.2.0
+ dev: false
+
+ /@radix-ui/react-use-layout-effect@1.0.1(@types/react@18.2.67)(react@18.2.0):
+ resolution: {integrity: sha512-v/5RegiJWYdoCvMnITBkNNx6bCj20fiaJnWtRkU18yITptraXjffz5Qbn05uOiQnOvi+dbkznkoaMltz1GnszQ==}
+ peerDependencies:
+ '@types/react': '*'
+ react: ^16.8 || ^17.0 || ^18.0
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+ dependencies:
+ '@babel/runtime': 7.24.1
+ '@types/react': 18.2.67
+ react: 18.2.0
+ dev: false
+
/@rushstack/eslint-patch@1.8.0:
resolution: {integrity: sha512-0HejFckBN2W+ucM6cUOlwsByTKt9/+0tWhqUffNIcHqCXkthY/mZ7AuYPK/2IIaGWhdl0h+tICDO0ssLMd6XMQ==}
dev: true
@@ -291,25 +786,97 @@ packages:
tslib: 2.6.2
dev: false
+ /@types/body-parser@1.19.5:
+ resolution: {integrity: sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==}
+ dependencies:
+ '@types/connect': 3.4.38
+ '@types/node': 20.11.30
+ dev: false
+
+ /@types/connect@3.4.38:
+ resolution: {integrity: sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==}
+ dependencies:
+ '@types/node': 20.11.30
+ dev: false
+
+ /@types/cookies@0.7.7:
+ resolution: {integrity: sha512-h7BcvPUogWbKCzBR2lY4oqaZbO3jXZksexYJVFvkrFeLgbZjQkU4x8pRq6eg2MHXQhY0McQdqmmsxRWlVAHooA==}
+ dependencies:
+ '@types/connect': 3.4.38
+ '@types/express': 4.17.14
+ '@types/keygrip': 1.0.6
+ '@types/node': 20.11.30
+ dev: false
+
+ /@types/express-serve-static-core@4.17.43:
+ resolution: {integrity: sha512-oaYtiBirUOPQGSWNGPWnzyAFJ0BP3cwvN4oWZQY+zUBwpVIGsKUkpBpSztp74drYcjavs7SKFZ4DX1V2QeN8rg==}
+ dependencies:
+ '@types/node': 20.11.30
+ '@types/qs': 6.9.14
+ '@types/range-parser': 1.2.7
+ '@types/send': 0.17.4
+ dev: false
+
+ /@types/express@4.17.14:
+ resolution: {integrity: sha512-TEbt+vaPFQ+xpxFLFssxUDXj5cWCxZJjIcB7Yg0k0GMHGtgtQgpvx/MUQUeAkNbA9AAGrwkAsoeItdTgS7FMyg==}
+ dependencies:
+ '@types/body-parser': 1.19.5
+ '@types/express-serve-static-core': 4.17.43
+ '@types/qs': 6.9.14
+ '@types/serve-static': 1.15.5
+ dev: false
+
+ /@types/http-errors@2.0.4:
+ resolution: {integrity: sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==}
+ dev: false
+
/@types/json5@0.0.29:
resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==}
dev: true
+ /@types/keygrip@1.0.6:
+ resolution: {integrity: sha512-lZuNAY9xeJt7Bx4t4dx0rYCDqGPW8RXhQZK1td7d4H6E9zYbLoOtjBvfwdTKpsyxQI/2jv+armjX/RW+ZNpXOQ==}
+ dev: false
+
+ /@types/mime@1.3.5:
+ resolution: {integrity: sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==}
+ dev: false
+
+ /@types/mime@3.0.4:
+ resolution: {integrity: sha512-iJt33IQnVRkqeqC7PzBHPTC6fDlRNRW8vjrgqtScAhrmMwe8c4Eo7+fUGTa+XdWrpEgpyKWMYmi2dIwMAYRzPw==}
+ dev: false
+
+ /@types/node-fetch@2.6.2:
+ resolution: {integrity: sha512-DHqhlq5jeESLy19TYhLakJ07kNumXWjcDdxXsLUMJZ6ue8VZJj4kLPQVE/2mdHh3xZziNF1xppu5lwmS53HR+A==}
+ dependencies:
+ '@types/node': 20.11.30
+ form-data: 3.0.1
+ dev: false
+
+ /@types/node@16.18.6:
+ resolution: {integrity: sha512-vmYJF0REqDyyU0gviezF/KHq/fYaUbFhkcNbQCuPGFQj6VTbXuHZoxs/Y7mutWe73C8AC6l9fFu8mSYiBAqkGA==}
+ dev: false
+
/@types/node@20.11.30:
resolution: {integrity: sha512-dHM6ZxwlmuZaRmUPfv1p+KrdD1Dci04FbdEm/9wEMouFqxYoFl5aMkt0VMAUtYRQDyYvD41WJLukhq/ha3YuTw==}
dependencies:
undici-types: 5.26.5
- dev: true
/@types/prop-types@15.7.11:
resolution: {integrity: sha512-ga8y9v9uyeiLdpKddhxYQkxNDrfvuPrlFb0N1qnZZByvcElJaXthF1UhvCh9TLWJBEHeNtdnbysW7Y6Uq8CVng==}
- dev: true
+
+ /@types/qs@6.9.14:
+ resolution: {integrity: sha512-5khscbd3SwWMhFqylJBLQ0zIu7c1K6Vz0uBIt915BI3zV0q1nfjRQD3RqSBcPaO6PHEF4ov/t9y89fSiyThlPA==}
+ dev: false
+
+ /@types/range-parser@1.2.7:
+ resolution: {integrity: sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==}
+ dev: false
/@types/react-dom@18.2.22:
resolution: {integrity: sha512-fHkBXPeNtfvri6gdsMYyW+dW7RXFo6Ad09nLFK0VQWR7yGLai/Cyvyj696gbwYvBnhGtevUG9cET0pmUbMtoPQ==}
dependencies:
'@types/react': 18.2.67
- dev: true
/@types/react@18.2.67:
resolution: {integrity: sha512-vkIE2vTIMHQ/xL0rgmuoECBCkZFZeHr49HeWSc24AptMbNRo7pwSBvj73rlJJs9fGKj0koS+V7kQB1jHS0uCgw==}
@@ -317,11 +884,24 @@ packages:
'@types/prop-types': 15.7.11
'@types/scheduler': 0.16.8
csstype: 3.1.3
- dev: true
/@types/scheduler@0.16.8:
resolution: {integrity: sha512-WZLiwShhwLRmeV6zH+GkbOFT6Z6VklCItrDioxUnv+u4Ll+8vKeFySoFyK/0ctcRpOmwAicELfmys1sDc/Rw+A==}
- dev: true
+
+ /@types/send@0.17.4:
+ resolution: {integrity: sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==}
+ dependencies:
+ '@types/mime': 1.3.5
+ '@types/node': 20.11.30
+ dev: false
+
+ /@types/serve-static@1.15.5:
+ resolution: {integrity: sha512-PDRk21MnK70hja/YF8AHfC7yIsiQHn1rcXx7ijCFBX/k+XQJhQT/gw3xekXKJvx+5SXaMMS8oqQy09Mzvz2TuQ==}
+ dependencies:
+ '@types/http-errors': 2.0.4
+ '@types/mime': 3.0.4
+ '@types/node': 20.11.30
+ dev: false
/@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.4.3):
resolution: {integrity: sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ==}
@@ -417,28 +997,23 @@ packages:
/ansi-regex@5.0.1:
resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==}
engines: {node: '>=8'}
- dev: true
/ansi-regex@6.0.1:
resolution: {integrity: sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==}
engines: {node: '>=12'}
- dev: true
/ansi-styles@4.3.0:
resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}
engines: {node: '>=8'}
dependencies:
color-convert: 2.0.1
- dev: true
/ansi-styles@6.2.1:
resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==}
engines: {node: '>=12'}
- dev: true
/any-promise@1.3.0:
resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==}
- dev: true
/anymatch@3.1.3:
resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==}
@@ -446,16 +1021,21 @@ packages:
dependencies:
normalize-path: 3.0.0
picomatch: 2.3.1
- dev: true
/arg@5.0.2:
resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==}
- dev: true
/argparse@2.0.1:
resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
dev: true
+ /aria-hidden@1.2.4:
+ resolution: {integrity: sha512-y+CcFFwelSXpLZk/7fMB2mUbGtX9lKycf1MWJ7CaTIERyitVlyQx6C+sxcROU2BAJ24OiZyK+8wj2i8AlBoS3A==}
+ engines: {node: '>=10'}
+ dependencies:
+ tslib: 2.6.2
+ dev: false
+
/aria-query@5.3.0:
resolution: {integrity: sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==}
dependencies:
@@ -564,10 +1144,23 @@ packages:
is-shared-array-buffer: 1.0.3
dev: true
+ /asn1js@3.0.5:
+ resolution: {integrity: sha512-FVnvrKJwpt9LP2lAMl8qZswRNm3T4q9CON+bxldk2iwk3FFpuwhx2FfinyitizWHsVYyaY+y5JzDR0rCMV5yTQ==}
+ engines: {node: '>=12.0.0'}
+ dependencies:
+ pvtsutils: 1.3.5
+ pvutils: 1.1.3
+ tslib: 2.6.2
+ dev: false
+
/ast-types-flow@0.0.8:
resolution: {integrity: sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==}
dev: true
+ /asynckit@0.4.0:
+ resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==}
+ dev: false
+
/autoprefixer@10.4.19(postcss@8.4.38):
resolution: {integrity: sha512-BaENR2+zBZ8xXhM4pUaKUxlVdxZ0EZhjvbopwnXmxRUfqDmwSpC2lAi/QXvx7NRdPCo1WKEcEF6mV64si1z4Ew==}
engines: {node: ^10 || ^12 || >=14}
@@ -604,12 +1197,10 @@ packages:
/balanced-match@1.0.2:
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
- dev: true
/binary-extensions@2.3.0:
resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==}
engines: {node: '>=8'}
- dev: true
/brace-expansion@1.1.11:
resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==}
@@ -622,14 +1213,12 @@ packages:
resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==}
dependencies:
balanced-match: 1.0.2
- dev: true
/braces@3.0.2:
resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==}
engines: {node: '>=8'}
dependencies:
fill-range: 7.0.1
- dev: true
/browserslist@4.23.0:
resolution: {integrity: sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==}
@@ -668,7 +1257,20 @@ packages:
/camelcase-css@2.0.1:
resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==}
engines: {node: '>= 6'}
- dev: true
+
+ /camelcase-keys@6.2.2:
+ resolution: {integrity: sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==}
+ engines: {node: '>=8'}
+ dependencies:
+ camelcase: 5.3.1
+ map-obj: 4.3.0
+ quick-lru: 4.0.1
+ dev: false
+
+ /camelcase@5.3.1:
+ resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==}
+ engines: {node: '>=6'}
+ dev: false
/caniuse-lite@1.0.30001599:
resolution: {integrity: sha512-LRAQHZ4yT1+f9LemSMeqdMpMxZcc4RMWdj4tiFe3G8tNkWK+E58g+/tzotb5cU6TbcVJLr4fySiAW7XmxQvZQA==}
@@ -694,32 +1296,56 @@ packages:
readdirp: 3.6.0
optionalDependencies:
fsevents: 2.3.3
- dev: true
+
+ /class-variance-authority@0.7.0:
+ resolution: {integrity: sha512-jFI8IQw4hczaL4ALINxqLEXQbWcNjoSkloa4IaufXCJr6QawJyw7tuRysRsrE8w2p/4gGaxKIt/hX3qz/IbD1A==}
+ dependencies:
+ clsx: 2.0.0
+ dev: false
/client-only@0.0.1:
resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==}
dev: false
+ /clsx@2.0.0:
+ resolution: {integrity: sha512-rQ1+kcj+ttHG0MKVGBUXwayCCF1oh39BF5COIpRzuCEv8Mwjv0XucrI2ExNTOn9IlLifGClWQcU9BrZORvtw6Q==}
+ engines: {node: '>=6'}
+ dev: false
+
+ /clsx@2.1.0:
+ resolution: {integrity: sha512-m3iNNWpd9rl3jvvcBnu70ylMdrXt8Vlq4HYadnU5fwcOtvkSQWPmj7amUcDT2qYI7risszBjI5AUIUox9D16pg==}
+ engines: {node: '>=6'}
+ dev: false
+
/color-convert@2.0.1:
resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
engines: {node: '>=7.0.0'}
dependencies:
color-name: 1.1.4
- dev: true
/color-name@1.1.4:
resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
- dev: true
+
+ /combined-stream@1.0.8:
+ resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==}
+ engines: {node: '>= 0.8'}
+ dependencies:
+ delayed-stream: 1.0.0
+ dev: false
/commander@4.1.1:
resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==}
engines: {node: '>= 6'}
- dev: true
/concat-map@0.0.1:
resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
dev: true
+ /cookie@0.5.0:
+ resolution: {integrity: sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==}
+ engines: {node: '>= 0.6'}
+ dev: false
+
/cross-spawn@7.0.3:
resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==}
engines: {node: '>= 8'}
@@ -727,17 +1353,18 @@ packages:
path-key: 3.1.1
shebang-command: 2.0.0
which: 2.0.2
- dev: true
/cssesc@3.0.0:
resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==}
engines: {node: '>=4'}
hasBin: true
- dev: true
+
+ /csstype@3.1.1:
+ resolution: {integrity: sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==}
+ dev: false
/csstype@3.1.3:
resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==}
- dev: true
/damerau-levenshtein@1.0.8:
resolution: {integrity: sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==}
@@ -797,6 +1424,11 @@ packages:
resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==}
dev: true
+ /deepmerge@4.2.2:
+ resolution: {integrity: sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==}
+ engines: {node: '>=0.10.0'}
+ dev: false
+
/define-data-property@1.1.4:
resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==}
engines: {node: '>= 0.4'}
@@ -815,14 +1447,22 @@ packages:
object-keys: 1.1.1
dev: true
+ /delayed-stream@1.0.0:
+ resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==}
+ engines: {node: '>=0.4.0'}
+ dev: false
+
/dequal@2.0.3:
resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==}
engines: {node: '>=6'}
dev: true
+ /detect-node-es@1.1.0:
+ resolution: {integrity: sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==}
+ dev: false
+
/didyoumean@1.2.2:
resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==}
- dev: true
/dir-glob@3.0.1:
resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==}
@@ -833,7 +1473,6 @@ packages:
/dlv@1.1.3:
resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==}
- dev: true
/doctrine@2.1.0:
resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==}
@@ -849,9 +1488,15 @@ packages:
esutils: 2.0.3
dev: true
+ /dot-case@3.0.4:
+ resolution: {integrity: sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==}
+ dependencies:
+ no-case: 3.0.4
+ tslib: 2.6.2
+ dev: false
+
/eastasianwidth@0.2.0:
resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==}
- dev: true
/electron-to-chromium@1.4.713:
resolution: {integrity: sha512-vDarADhwntXiULEdmWd77g2dV6FrNGa8ecAC29MZ4TwPut2fvosD0/5sJd1qWNNe8HcJFAC+F5Lf9jW1NPtWmw==}
@@ -859,11 +1504,9 @@ packages:
/emoji-regex@8.0.0:
resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
- dev: true
/emoji-regex@9.2.2:
resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==}
- dev: true
/enhanced-resolve@5.16.0:
resolution: {integrity: sha512-O+QWCviPNSSLAD9Ucn8Awv+poAkqn3T1XY5/N7kR7rQO9yfSGWkYZDwpJ+iKF7B8rxaQKWngSqACpgzeapSyoA==}
@@ -1335,7 +1978,6 @@ packages:
glob-parent: 5.1.2
merge2: 1.4.1
micromatch: 4.0.5
- dev: true
/fast-json-stable-stringify@2.1.0:
resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==}
@@ -1349,7 +1991,6 @@ packages:
resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==}
dependencies:
reusify: 1.0.4
- dev: true
/file-entry-cache@6.0.1:
resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==}
@@ -1363,7 +2004,6 @@ packages:
engines: {node: '>=8'}
dependencies:
to-regex-range: 5.0.1
- dev: true
/find-up@5.0.0:
resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==}
@@ -1398,7 +2038,15 @@ packages:
dependencies:
cross-spawn: 7.0.3
signal-exit: 4.1.0
- dev: true
+
+ /form-data@3.0.1:
+ resolution: {integrity: sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==}
+ engines: {node: '>= 6'}
+ dependencies:
+ asynckit: 0.4.0
+ combined-stream: 1.0.8
+ mime-types: 2.1.35
+ dev: false
/fraction.js@4.3.7:
resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==}
@@ -1413,12 +2061,10 @@ packages:
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
os: [darwin]
requiresBuild: true
- dev: true
optional: true
/function-bind@1.1.2:
resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==}
- dev: true
/function.prototype.name@1.1.6:
resolution: {integrity: sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==}
@@ -1445,6 +2091,11 @@ packages:
hasown: 2.0.2
dev: true
+ /get-nonce@1.0.1:
+ resolution: {integrity: sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==}
+ engines: {node: '>=6'}
+ dev: false
+
/get-symbol-description@1.0.2:
resolution: {integrity: sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==}
engines: {node: '>= 0.4'}
@@ -1465,14 +2116,16 @@ packages:
engines: {node: '>= 6'}
dependencies:
is-glob: 4.0.3
- dev: true
/glob-parent@6.0.2:
resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==}
engines: {node: '>=10.13.0'}
dependencies:
is-glob: 4.0.3
- dev: true
+
+ /glob-to-regexp@0.4.1:
+ resolution: {integrity: sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==}
+ dev: false
/glob@10.3.10:
resolution: {integrity: sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==}
@@ -1484,7 +2137,6 @@ packages:
minimatch: 9.0.3
minipass: 7.0.4
path-scurry: 1.10.1
- dev: true
/glob@7.2.3:
resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==}
@@ -1573,7 +2225,6 @@ packages:
engines: {node: '>= 0.4'}
dependencies:
function-bind: 1.1.2
- dev: true
/ignore@5.3.1:
resolution: {integrity: sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==}
@@ -1613,6 +2264,12 @@ packages:
side-channel: 1.0.6
dev: true
+ /invariant@2.2.4:
+ resolution: {integrity: sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==}
+ dependencies:
+ loose-envify: 1.4.0
+ dev: false
+
/is-array-buffer@3.0.4:
resolution: {integrity: sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==}
engines: {node: '>= 0.4'}
@@ -1639,7 +2296,6 @@ packages:
engines: {node: '>=8'}
dependencies:
binary-extensions: 2.3.0
- dev: true
/is-boolean-object@1.1.2:
resolution: {integrity: sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==}
@@ -1658,7 +2314,6 @@ packages:
resolution: {integrity: sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==}
dependencies:
hasown: 2.0.2
- dev: true
/is-data-view@1.0.1:
resolution: {integrity: sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==}
@@ -1677,7 +2332,6 @@ packages:
/is-extglob@2.1.1:
resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==}
engines: {node: '>=0.10.0'}
- dev: true
/is-finalizationregistry@1.0.2:
resolution: {integrity: sha512-0by5vtUJs8iFQb5TYUHHPudOR+qXYIMKtiUzvLIZITZUjknFmziyBJuLhVRc+Ds0dREFlskDNJKYIdIzu/9pfw==}
@@ -1688,7 +2342,6 @@ packages:
/is-fullwidth-code-point@3.0.0:
resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==}
engines: {node: '>=8'}
- dev: true
/is-generator-function@1.0.10:
resolution: {integrity: sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==}
@@ -1702,7 +2355,6 @@ packages:
engines: {node: '>=0.10.0'}
dependencies:
is-extglob: 2.1.1
- dev: true
/is-map@2.0.3:
resolution: {integrity: sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==}
@@ -1724,7 +2376,6 @@ packages:
/is-number@7.0.0:
resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==}
engines: {node: '>=0.12.0'}
- dev: true
/is-path-inside@3.0.3:
resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==}
@@ -1797,7 +2448,6 @@ packages:
/isexe@2.0.0:
resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
- dev: true
/iterator.prototype@1.1.2:
resolution: {integrity: sha512-DR33HMMr8EzwuRL8Y9D3u2BMj8+RqSE850jfGu59kS7tbmPLzGkZmVSfyCFSDxuZiEY6Rzt3T2NA/qU+NwVj1w==}
@@ -1816,12 +2466,15 @@ packages:
'@isaacs/cliui': 8.0.2
optionalDependencies:
'@pkgjs/parseargs': 0.11.0
- dev: true
/jiti@1.21.0:
resolution: {integrity: sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==}
hasBin: true
- dev: true
+
+ /js-cookie@3.0.1:
+ resolution: {integrity: sha512-+0rgsUXZu4ncpPxRL+lNEptWMOWl9etvPHc/koSRp6MPwpRYAhmk0dUG00J4bxVV3r9uUzfo24wW0knS07SKSw==}
+ engines: {node: '>=12'}
+ dev: false
/js-tokens@4.0.0:
resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
@@ -1890,16 +2543,13 @@ packages:
/lilconfig@2.1.0:
resolution: {integrity: sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==}
engines: {node: '>=10'}
- dev: true
/lilconfig@3.1.1:
resolution: {integrity: sha512-O18pf7nyvHTckunPWCV1XUNXU1piu01y2b7ATJ0ppkUkk8ocqVWBrYjJBCwHDjD/ZWcfyrA0P4gKhzWGi5EINQ==}
engines: {node: '>=14'}
- dev: true
/lines-and-columns@1.2.4:
resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==}
- dev: true
/locate-path@6.0.0:
resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==}
@@ -1918,10 +2568,15 @@ packages:
dependencies:
js-tokens: 4.0.0
+ /lower-case@2.0.2:
+ resolution: {integrity: sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==}
+ dependencies:
+ tslib: 2.6.2
+ dev: false
+
/lru-cache@10.2.0:
resolution: {integrity: sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==}
engines: {node: 14 || >=16.14}
- dev: true
/lru-cache@6.0.0:
resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==}
@@ -1930,10 +2585,22 @@ packages:
yallist: 4.0.0
dev: true
+ /lucide-react@0.363.0(react@18.2.0):
+ resolution: {integrity: sha512-AlsfPCsXQyQx7wwsIgzcKOL9LwC498LIMAo+c0Es5PkHJa33xwmYAkkSoKoJWWWSYQEStqu58/jT4tL2gi32uQ==}
+ peerDependencies:
+ react: ^16.5.1 || ^17.0.0 || ^18.0.0
+ dependencies:
+ react: 18.2.0
+ dev: false
+
+ /map-obj@4.3.0:
+ resolution: {integrity: sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==}
+ engines: {node: '>=8'}
+ dev: false
+
/merge2@1.4.1:
resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==}
engines: {node: '>= 8'}
- dev: true
/micromatch@4.0.5:
resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==}
@@ -1941,7 +2608,18 @@ packages:
dependencies:
braces: 3.0.2
picomatch: 2.3.1
- dev: true
+
+ /mime-db@1.52.0:
+ resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==}
+ engines: {node: '>= 0.6'}
+ dev: false
+
+ /mime-types@2.1.35:
+ resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==}
+ engines: {node: '>= 0.6'}
+ dependencies:
+ mime-db: 1.52.0
+ dev: false
/minimatch@3.1.2:
resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==}
@@ -1954,7 +2632,6 @@ packages:
engines: {node: '>=16 || 14 >=14.17'}
dependencies:
brace-expansion: 2.0.1
- dev: true
/minimist@1.2.8:
resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==}
@@ -1963,7 +2640,6 @@ packages:
/minipass@7.0.4:
resolution: {integrity: sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==}
engines: {node: '>=16 || 14 >=14.17'}
- dev: true
/ms@2.1.2:
resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==}
@@ -1979,7 +2655,6 @@ packages:
any-promise: 1.3.0
object-assign: 4.1.1
thenify-all: 1.6.0
- dev: true
/nanoid@3.3.7:
resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==}
@@ -2029,6 +2704,17 @@ packages:
- babel-plugin-macros
dev: false
+ /no-case@3.0.4:
+ resolution: {integrity: sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==}
+ dependencies:
+ lower-case: 2.0.2
+ tslib: 2.6.2
+ dev: false
+
+ /node-fetch-native@1.0.1:
+ resolution: {integrity: sha512-VzW+TAk2wE4X9maiKMlT+GsPU4OMmR1U9CrHSmd3DFLn2IcZ9VJ6M6BBugGfYUnPCLSYxXdZy17M0BEJyhUTwg==}
+ dev: false
+
/node-releases@2.0.14:
resolution: {integrity: sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==}
dev: true
@@ -2036,7 +2722,6 @@ packages:
/normalize-path@3.0.0:
resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==}
engines: {node: '>=0.10.0'}
- dev: true
/normalize-range@0.1.2:
resolution: {integrity: sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==}
@@ -2046,12 +2731,10 @@ packages:
/object-assign@4.1.1:
resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==}
engines: {node: '>=0.10.0'}
- dev: true
/object-hash@3.0.0:
resolution: {integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==}
engines: {node: '>= 6'}
- dev: true
/object-inspect@1.13.1:
resolution: {integrity: sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==}
@@ -2168,11 +2851,9 @@ packages:
/path-key@3.1.1:
resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==}
engines: {node: '>=8'}
- dev: true
/path-parse@1.0.7:
resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==}
- dev: true
/path-scurry@1.10.1:
resolution: {integrity: sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==}
@@ -2180,7 +2861,10 @@ packages:
dependencies:
lru-cache: 10.2.0
minipass: 7.0.4
- dev: true
+
+ /path-to-regexp@6.2.1:
+ resolution: {integrity: sha512-JLyh7xT1kizaEvcaXOQwOc2/Yhw6KZOvPf1S8401UyLk86CU79LN3vl7ztXGm/pZ+YjoyAJ4rxmHwbkBXJX+yw==}
+ dev: false
/path-type@4.0.0:
resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==}
@@ -2193,17 +2877,14 @@ packages:
/picomatch@2.3.1:
resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
engines: {node: '>=8.6'}
- dev: true
/pify@2.3.0:
resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==}
engines: {node: '>=0.10.0'}
- dev: true
/pirates@4.0.6:
resolution: {integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==}
engines: {node: '>= 6'}
- dev: true
/possible-typed-array-names@1.0.0:
resolution: {integrity: sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==}
@@ -2220,7 +2901,6 @@ packages:
postcss-value-parser: 4.2.0
read-cache: 1.0.0
resolve: 1.22.8
- dev: true
/postcss-js@4.0.1(postcss@8.4.38):
resolution: {integrity: sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==}
@@ -2230,7 +2910,6 @@ packages:
dependencies:
camelcase-css: 2.0.1
postcss: 8.4.38
- dev: true
/postcss-load-config@4.0.2(postcss@8.4.38):
resolution: {integrity: sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==}
@@ -2247,7 +2926,6 @@ packages:
lilconfig: 3.1.1
postcss: 8.4.38
yaml: 2.4.1
- dev: true
/postcss-nested@6.0.1(postcss@8.4.38):
resolution: {integrity: sha512-mEp4xPMi5bSWiMbsgoPfcP74lsWLHkQbZc3sY+jWYd65CUwXrUaTp0fmNpa01ZcETKlIgUdFN/MpS2xZtqL9dQ==}
@@ -2257,7 +2935,6 @@ packages:
dependencies:
postcss: 8.4.38
postcss-selector-parser: 6.0.16
- dev: true
/postcss-selector-parser@6.0.16:
resolution: {integrity: sha512-A0RVJrX+IUkVZbW3ClroRWurercFhieevHB38sr2+l9eUClMqome3LmEmnhlNy+5Mr2EYN6B2Kaw9wYdd+VHiw==}
@@ -2265,11 +2942,9 @@ packages:
dependencies:
cssesc: 3.0.0
util-deprecate: 1.0.2
- dev: true
/postcss-value-parser@4.2.0:
resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==}
- dev: true
/postcss@8.4.31:
resolution: {integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==}
@@ -2287,7 +2962,6 @@ packages:
nanoid: 3.3.7
picocolors: 1.0.0
source-map-js: 1.2.0
- dev: true
/prelude-ls@1.2.1:
resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
@@ -2307,9 +2981,24 @@ packages:
engines: {node: '>=6'}
dev: true
+ /pvtsutils@1.3.5:
+ resolution: {integrity: sha512-ARvb14YB9Nm2Xi6nBq1ZX6dAM0FsJnuk+31aUp4TrcZEdKUlSqOqsxJHUPJDNE3qiIp+iUPEIeR6Je/tgV7zsA==}
+ dependencies:
+ tslib: 2.6.2
+ dev: false
+
+ /pvutils@1.1.3:
+ resolution: {integrity: sha512-pMpnA0qRdFp32b1sJl1wOJNxZLQ2cbQx+k6tjNtZ8CpvVhNqEPRgivZ2WOUev2YMajecdH7ctUPDvEe87nariQ==}
+ engines: {node: '>=6.0.0'}
+ dev: false
+
/queue-microtask@1.2.3:
resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
- dev: true
+
+ /quick-lru@4.0.1:
+ resolution: {integrity: sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==}
+ engines: {node: '>=8'}
+ dev: false
/react-dom@18.2.0(react@18.2.0):
resolution: {integrity: sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==}
@@ -2321,10 +3010,70 @@ packages:
scheduler: 0.23.0
dev: false
+ /react-icons@5.0.1(react@18.2.0):
+ resolution: {integrity: sha512-WqLZJ4bLzlhmsvme6iFdgO8gfZP17rfjYEJ2m9RsZjZ+cc4k1hTzknEz63YS1MeT50kVzoa1Nz36f4BEx+Wigw==}
+ peerDependencies:
+ react: '*'
+ dependencies:
+ react: 18.2.0
+ dev: false
+
/react-is@16.13.1:
resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==}
dev: true
+ /react-remove-scroll-bar@2.3.6(@types/react@18.2.67)(react@18.2.0):
+ resolution: {integrity: sha512-DtSYaao4mBmX+HDo5YWYdBWQwYIQQshUV/dVxFxK+KM26Wjwp1gZ6rv6OC3oujI6Bfu6Xyg3TwK533AQutsn/g==}
+ engines: {node: '>=10'}
+ peerDependencies:
+ '@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0
+ react: ^16.8.0 || ^17.0.0 || ^18.0.0
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+ dependencies:
+ '@types/react': 18.2.67
+ react: 18.2.0
+ react-style-singleton: 2.2.1(@types/react@18.2.67)(react@18.2.0)
+ tslib: 2.6.2
+ dev: false
+
+ /react-remove-scroll@2.5.5(@types/react@18.2.67)(react@18.2.0):
+ resolution: {integrity: sha512-ImKhrzJJsyXJfBZ4bzu8Bwpka14c/fQt0k+cyFp/PBhTfyDnU5hjOtM4AG/0AMyy8oKzOTR0lDgJIM7pYXI0kw==}
+ engines: {node: '>=10'}
+ peerDependencies:
+ '@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0
+ react: ^16.8.0 || ^17.0.0 || ^18.0.0
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+ dependencies:
+ '@types/react': 18.2.67
+ react: 18.2.0
+ react-remove-scroll-bar: 2.3.6(@types/react@18.2.67)(react@18.2.0)
+ react-style-singleton: 2.2.1(@types/react@18.2.67)(react@18.2.0)
+ tslib: 2.6.2
+ use-callback-ref: 1.3.2(@types/react@18.2.67)(react@18.2.0)
+ use-sidecar: 1.1.2(@types/react@18.2.67)(react@18.2.0)
+ dev: false
+
+ /react-style-singleton@2.2.1(@types/react@18.2.67)(react@18.2.0):
+ resolution: {integrity: sha512-ZWj0fHEMyWkHzKYUr2Bs/4zU6XLmq9HsgBURm7g5pAVfyn49DgUiNgY2d4lXRlYSiCif9YBGpQleewkcqddc7g==}
+ engines: {node: '>=10'}
+ peerDependencies:
+ '@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0
+ react: ^16.8.0 || ^17.0.0 || ^18.0.0
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+ dependencies:
+ '@types/react': 18.2.67
+ get-nonce: 1.0.1
+ invariant: 2.2.4
+ react: 18.2.0
+ tslib: 2.6.2
+ dev: false
+
/react@18.2.0:
resolution: {integrity: sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==}
engines: {node: '>=0.10.0'}
@@ -2336,14 +3085,12 @@ packages:
resolution: {integrity: sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==}
dependencies:
pify: 2.3.0
- dev: true
/readdirp@3.6.0:
resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==}
engines: {node: '>=8.10.0'}
dependencies:
picomatch: 2.3.1
- dev: true
/reflect.getprototypeof@1.0.6:
resolution: {integrity: sha512-fmfw4XgoDke3kdI6h4xcUz1dG8uaiv5q9gcEwLS4Pnth2kxT+GZ7YehS1JTMGBQmtV7Y4GFGbs2re2NqhdozUg==}
@@ -2360,7 +3107,6 @@ packages:
/regenerator-runtime@0.14.1:
resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==}
- dev: true
/regexp.prototype.flags@1.5.2:
resolution: {integrity: sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==}
@@ -2388,7 +3134,6 @@ packages:
is-core-module: 2.13.1
path-parse: 1.0.7
supports-preserve-symlinks-flag: 1.0.0
- dev: true
/resolve@2.0.0-next.5:
resolution: {integrity: sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==}
@@ -2402,7 +3147,6 @@ packages:
/reusify@1.0.4:
resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==}
engines: {iojs: '>=1.0.0', node: '>=0.10.0'}
- dev: true
/rimraf@3.0.2:
resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==}
@@ -2415,7 +3159,6 @@ packages:
resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==}
dependencies:
queue-microtask: 1.2.3
- dev: true
/safe-array-concat@1.1.2:
resolution: {integrity: sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==}
@@ -2482,12 +3225,10 @@ packages:
engines: {node: '>=8'}
dependencies:
shebang-regex: 3.0.0
- dev: true
/shebang-regex@3.0.0:
resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==}
engines: {node: '>=8'}
- dev: true
/side-channel@1.0.6:
resolution: {integrity: sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==}
@@ -2502,13 +3243,36 @@ packages:
/signal-exit@4.1.0:
resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==}
engines: {node: '>=14'}
- dev: true
/slash@3.0.0:
resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==}
engines: {node: '>=8'}
dev: true
+ /snake-case@3.0.4:
+ resolution: {integrity: sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==}
+ dependencies:
+ dot-case: 3.0.4
+ tslib: 2.6.2
+ dev: false
+
+ /snakecase-keys@3.2.1:
+ resolution: {integrity: sha512-CjU5pyRfwOtaOITYv5C8DzpZ8XA/ieRsDpr93HI2r6e3YInC6moZpSQbmUtg8cTk58tq2x3jcG2gv+p1IZGmMA==}
+ engines: {node: '>=8'}
+ dependencies:
+ map-obj: 4.3.0
+ to-snake-case: 1.0.0
+ dev: false
+
+ /snakecase-keys@5.4.4:
+ resolution: {integrity: sha512-YTywJG93yxwHLgrYLZjlC75moVEX04LZM4FHfihjHe1FCXm+QaLOFfSf535aXOAd0ArVQMWUAe8ZPm4VtWyXaA==}
+ engines: {node: '>=12'}
+ dependencies:
+ map-obj: 4.3.0
+ snake-case: 3.0.4
+ type-fest: 2.19.0
+ dev: false
+
/source-map-js@1.2.0:
resolution: {integrity: sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==}
engines: {node: '>=0.10.0'}
@@ -2525,7 +3289,6 @@ packages:
emoji-regex: 8.0.0
is-fullwidth-code-point: 3.0.0
strip-ansi: 6.0.1
- dev: true
/string-width@5.1.2:
resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==}
@@ -2534,7 +3297,6 @@ packages:
eastasianwidth: 0.2.0
emoji-regex: 9.2.2
strip-ansi: 7.1.0
- dev: true
/string.prototype.matchall@4.0.11:
resolution: {integrity: sha512-NUdh0aDavY2og7IbBPenWqR9exH+E26Sv8e0/eTe1tltDGZL+GtBkDAnnyBtmekfK6/Dq3MkcGtzXFEd1LQrtg==}
@@ -2585,14 +3347,12 @@ packages:
engines: {node: '>=8'}
dependencies:
ansi-regex: 5.0.1
- dev: true
/strip-ansi@7.1.0:
resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==}
engines: {node: '>=12'}
dependencies:
ansi-regex: 6.0.1
- dev: true
/strip-bom@3.0.0:
resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==}
@@ -2633,7 +3393,6 @@ packages:
mz: 2.7.0
pirates: 4.0.6
ts-interface-checker: 0.1.13
- dev: true
/supports-color@7.2.0:
resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==}
@@ -2645,7 +3404,29 @@ packages:
/supports-preserve-symlinks-flag@1.0.0:
resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
engines: {node: '>= 0.4'}
- dev: true
+
+ /swr@2.2.0(react@18.2.0):
+ resolution: {integrity: sha512-AjqHOv2lAhkuUdIiBu9xbuettzAzWXmCEcLONNKJRba87WAefz8Ca9d6ds/SzrPc235n1IxWYdhJ2zF3MNUaoQ==}
+ peerDependencies:
+ react: ^16.11.0 || ^17.0.0 || ^18.0.0
+ dependencies:
+ react: 18.2.0
+ use-sync-external-store: 1.2.0(react@18.2.0)
+ dev: false
+
+ /tailwind-merge@2.2.2:
+ resolution: {integrity: sha512-tWANXsnmJzgw6mQ07nE3aCDkCK4QdT3ThPMCzawoYA2Pws7vSTCvz3Vrjg61jVUGfFZPJzxEP+NimbcW+EdaDw==}
+ dependencies:
+ '@babel/runtime': 7.24.1
+ dev: false
+
+ /tailwindcss-animate@1.0.7(tailwindcss@3.4.1):
+ resolution: {integrity: sha512-bl6mpH3T7I3UFxuvDEXLxy/VuFxBk5bbzplh7tXI68mwMokNYd1t9qPBHlnyTwfa4JGC4zP516I1hYYtQ/vspA==}
+ peerDependencies:
+ tailwindcss: '>=3.0.0 || insiders'
+ dependencies:
+ tailwindcss: 3.4.1
+ dev: false
/tailwindcss@3.4.1:
resolution: {integrity: sha512-qAYmXRfk3ENzuPBakNK0SRrUDipP8NQnEY6772uDhflcQz5EhRdD7JNZxyrFHVQNCwULPBn6FNPp9brpO7ctcA==}
@@ -2676,7 +3457,6 @@ packages:
sucrase: 3.35.0
transitivePeerDependencies:
- ts-node
- dev: true
/tapable@2.2.1:
resolution: {integrity: sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==}
@@ -2692,20 +3472,33 @@ packages:
engines: {node: '>=0.8'}
dependencies:
thenify: 3.3.1
- dev: true
/thenify@3.3.1:
resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==}
dependencies:
any-promise: 1.3.0
- dev: true
+
+ /to-no-case@1.0.2:
+ resolution: {integrity: sha512-Z3g735FxuZY8rodxV4gH7LxClE4H0hTIyHNIHdk+vpQxjLm0cwnKXq/OFVZ76SOQmto7txVcwSCwkU5kqp+FKg==}
+ dev: false
/to-regex-range@5.0.1:
resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
engines: {node: '>=8.0'}
dependencies:
is-number: 7.0.0
- dev: true
+
+ /to-snake-case@1.0.0:
+ resolution: {integrity: sha512-joRpzBAk1Bhi2eGEYBjukEWHOe/IvclOkiJl3DtA91jV6NwQ3MwXA4FHYeqk8BNp/D8bmi9tcNbRu/SozP0jbQ==}
+ dependencies:
+ to-space-case: 1.0.0
+ dev: false
+
+ /to-space-case@1.0.0:
+ resolution: {integrity: sha512-rLdvwXZ39VOn1IxGL3V6ZstoTbwLRckQmn/U8ZDLuWwIXNpuZDhQ3AiRUlhTbOXFVE9C+dR51wM0CBDhk31VcA==}
+ dependencies:
+ to-no-case: 1.0.2
+ dev: false
/ts-api-utils@1.3.0(typescript@5.4.3):
resolution: {integrity: sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==}
@@ -2718,7 +3511,6 @@ packages:
/ts-interface-checker@0.1.13:
resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==}
- dev: true
/tsconfig-paths@3.15.0:
resolution: {integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==}
@@ -2729,6 +3521,10 @@ packages:
strip-bom: 3.0.0
dev: true
+ /tslib@2.4.1:
+ resolution: {integrity: sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==}
+ dev: false
+
/tslib@2.6.2:
resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==}
dev: false
@@ -2745,6 +3541,11 @@ packages:
engines: {node: '>=10'}
dev: true
+ /type-fest@2.19.0:
+ resolution: {integrity: sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==}
+ engines: {node: '>=12.20'}
+ dev: false
+
/typed-array-buffer@1.0.2:
resolution: {integrity: sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==}
engines: {node: '>= 0.4'}
@@ -2806,7 +3607,6 @@ packages:
/undici-types@5.26.5:
resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==}
- dev: true
/update-browserslist-db@1.0.13(browserslist@4.23.0):
resolution: {integrity: sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==}
@@ -2825,9 +3625,57 @@ packages:
punycode: 2.3.1
dev: true
+ /use-callback-ref@1.3.2(@types/react@18.2.67)(react@18.2.0):
+ resolution: {integrity: sha512-elOQwe6Q8gqZgDA8mrh44qRTQqpIHDcZ3hXTLjBe1i4ph8XpNJnO+aQf3NaG+lriLopI4HMx9VjQLfPQ6vhnoA==}
+ engines: {node: '>=10'}
+ peerDependencies:
+ '@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0
+ react: ^16.8.0 || ^17.0.0 || ^18.0.0
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+ dependencies:
+ '@types/react': 18.2.67
+ react: 18.2.0
+ tslib: 2.6.2
+ dev: false
+
+ /use-sidecar@1.1.2(@types/react@18.2.67)(react@18.2.0):
+ resolution: {integrity: sha512-epTbsLuzZ7lPClpz2TyryBfztm7m+28DlEv2ZCQ3MDr5ssiwyOwGH/e5F9CkfWjJ1t4clvI58yF822/GUkjjhw==}
+ engines: {node: '>=10'}
+ peerDependencies:
+ '@types/react': ^16.9.0 || ^17.0.0 || ^18.0.0
+ react: ^16.8.0 || ^17.0.0 || ^18.0.0
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+ dependencies:
+ '@types/react': 18.2.67
+ detect-node-es: 1.1.0
+ react: 18.2.0
+ tslib: 2.6.2
+ dev: false
+
+ /use-sync-external-store@1.2.0(react@18.2.0):
+ resolution: {integrity: sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==}
+ peerDependencies:
+ react: ^16.8.0 || ^17.0.0 || ^18.0.0
+ dependencies:
+ react: 18.2.0
+ dev: false
+
/util-deprecate@1.0.2:
resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
- dev: true
+
+ /webcrypto-core@1.7.8:
+ resolution: {integrity: sha512-eBR98r9nQXTqXt/yDRtInszPMjTaSAMJAFDg2AHsgrnczawT1asx9YNBX6k5p+MekbPF4+s/UJJrr88zsTqkSg==}
+ dependencies:
+ '@peculiar/asn1-schema': 2.3.8
+ '@peculiar/json-schema': 1.1.12
+ asn1js: 3.0.5
+ pvtsutils: 1.3.5
+ tslib: 2.6.2
+ dev: false
/which-boxed-primitive@1.0.2:
resolution: {integrity: sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==}
@@ -2884,7 +3732,6 @@ packages:
hasBin: true
dependencies:
isexe: 2.0.0
- dev: true
/wrap-ansi@7.0.0:
resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==}
@@ -2893,7 +3740,6 @@ packages:
ansi-styles: 4.3.0
string-width: 4.2.3
strip-ansi: 6.0.1
- dev: true
/wrap-ansi@8.1.0:
resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==}
@@ -2902,7 +3748,6 @@ packages:
ansi-styles: 6.2.1
string-width: 5.1.2
strip-ansi: 7.1.0
- dev: true
/wrappy@1.0.2:
resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
@@ -2916,9 +3761,12 @@ packages:
resolution: {integrity: sha512-pIXzoImaqmfOrL7teGUBt/T7ZDnyeGBWyXQBvOVhLkWLN37GXv8NMLK406UY6dS51JfcQHsmcW5cJ441bHg6Lg==}
engines: {node: '>= 14'}
hasBin: true
- dev: true
/yocto-queue@0.1.0:
resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
engines: {node: '>=10'}
dev: true
+
+ /zod@3.22.4:
+ resolution: {integrity: sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg==}
+ dev: false
diff --git a/client/src/app/globals.css b/client/src/app/globals.css
index 875c01e..7d2d81f 100644
--- a/client/src/app/globals.css
+++ b/client/src/app/globals.css
@@ -2,32 +2,75 @@
@tailwind components;
@tailwind utilities;
-:root {
- --foreground-rgb: 0, 0, 0;
- --background-start-rgb: 214, 219, 220;
- --background-end-rgb: 255, 255, 255;
-}
+/*--primary: 45.882 100% 55.9%;*/
+/*--secondary: 211.578 16.4% 47.1%;*/
+
+
+@layer base {
+ :root {
+ --background: 0 0% 100%;
+ --foreground: 20 14.3% 4.1%;
+ --card: 0 0% 100%;
+ --card-foreground: 20 14.3% 4.1%;
+ --popover: 0 0% 100%;
+ --popover-foreground: 20 14.3% 4.1%;
+ --primary: 45.882 100% 55.9%;
+ --primary-foreground: 26 83.3% 14.1%;
+ --secondary: 211.578 16.4% 47.1%;
+ --secondary-foreground: 24 9.8% 10%;
+ --muted: 60 4.8% 95.9%;
+ --muted-foreground: 25 5.3% 44.7%;
+ --accent: 60 4.8% 95.9%;
+ --accent-foreground: 24 9.8% 10%;
+ --destructive: 0 84.2% 60.2%;
+ --destructive-foreground: 60 9.1% 97.8%;
+ --border: 20 5.9% 90%;
+ --input: 20 5.9% 90%;
+ --ring: 20 14.3% 4.1%;
+ --radius: 0.5rem;
+ }
-@media (prefers-color-scheme: dark) {
- :root {
- --foreground-rgb: 255, 255, 255;
- --background-start-rgb: 0, 0, 0;
- --background-end-rgb: 0, 0, 0;
- }
+ .dark {
+ --background: 20 14.3% 4.1%;
+ --foreground: 60 9.1% 97.8%;
+ --card: 20 14.3% 4.1%;
+ --card-foreground: 60 9.1% 97.8%;
+ --popover: 20 14.3% 4.1%;
+ --popover-foreground: 60 9.1% 97.8%;
+ --primary: 47.9 95.8% 53.1%;
+ --primary-foreground: 26 83.3% 14.1%;
+ --secondary: 12 6.5% 15.1%;
+ --secondary-foreground: 60 9.1% 97.8%;
+ --muted: 12 6.5% 15.1%;
+ --muted-foreground: 24 5.4% 63.9%;
+ --accent: 12 6.5% 15.1%;
+ --accent-foreground: 60 9.1% 97.8%;
+ --destructive: 0 62.8% 30.6%;
+ --destructive-foreground: 60 9.1% 97.8%;
+ --border: 12 6.5% 15.1%;
+ --input: 12 6.5% 15.1%;
+ --ring: 35.5 91.7% 32.9%;
+ }
}
-body {
- color: rgb(var(--foreground-rgb));
- background: linear-gradient(
- to bottom,
- transparent,
- rgb(var(--background-end-rgb))
- )
- rgb(var(--background-start-rgb));
+
+@layer base {
+ * {
+ @apply border-border;
+ }
+
+ body {
+ @apply bg-background text-foreground;
+ }
}
-@layer utilities {
- .text-balance {
- text-wrap: balance;
- }
+::-webkit-scrollbar {
+ width: .60rem;
+ background-color: rgba(20, 20, 20, 0.301);
+ border-radius: 5rem;
}
+
+::-webkit-scrollbar-thumb {
+ background: rgba(122, 128, 138, 0.8);
+ border-radius: .75rem;
+}
\ No newline at end of file
diff --git a/client/src/app/layout.tsx b/client/src/app/layout.tsx
index 3314e47..53860a3 100644
--- a/client/src/app/layout.tsx
+++ b/client/src/app/layout.tsx
@@ -1,22 +1,43 @@
-import type { Metadata } from "next";
-import { Inter } from "next/font/google";
+import type {Metadata} from "next";
+import {Inter} from "next/font/google";
+import Header from "~/components/core/header";
+import SideBar from "~/components/core/side-bar";
+import RecentPosts from "~/components/core/recent-posts";
import "./globals.css";
+import {Separator} from "~/components/ui/separator";
+import {ClerkProvider} from "@clerk/nextjs";
+import Posts from "~/components/posts/posts";
-const inter = Inter({ subsets: ["latin"] });
+const inter = Inter({subsets: ["latin"]});
export const metadata: Metadata = {
- title: "Create Next App",
- description: "Generated by create next app",
+ title: "Create Next App",
+ description: "Generated by create next app",
};
export default function RootLayout({
- children,
-}: Readonly<{
- children: React.ReactNode;
+ children,
+ }: Readonly<{
+ children: React.ReactNode;
}>) {
- return (
-
-
{children}
-
- );
+ return (
+
+
+
+
+
+
+
+
+
+ );
}
diff --git a/client/src/app/page.tsx b/client/src/app/page.tsx
index b81507d..6303b10 100644
--- a/client/src/app/page.tsx
+++ b/client/src/app/page.tsx
@@ -3,111 +3,7 @@ import Image from "next/image";
export default function Home() {
return (
-
-
- Get started by editing
- src/app/page.tsx
-
-
-
-
-
-
-
-
);
}
diff --git a/client/src/components/core/header.tsx b/client/src/components/core/header.tsx
new file mode 100644
index 0000000..43bbce3
--- /dev/null
+++ b/client/src/components/core/header.tsx
@@ -0,0 +1,130 @@
+'use client'
+
+import {Input} from "~/components/ui/input"
+import React, {useState} from "react";
+import {FaArrowDown, FaBars, FaPlus} from "react-icons/fa6";
+import {FaHome, FaSearch} from "react-icons/fa";
+import {FaRocket} from "react-icons/fa";
+import {Separator} from "~/components/ui/separator"
+import { UserButton, useClerk } from "@clerk/nextjs";
+
+// import {Button} from "~/components/ui/button";
+import {
+ Sheet,
+ SheetContent,
+} from "~/components/ui/sheet"
+
+import {
+ Collapsible,
+ CollapsibleContent,
+ CollapsibleTrigger,
+} from "~/components/ui/collapsible"
+
+import Link from "next/link";
+import {Button} from "~/components/ui/button";
+import Image from "next/image";
+
+
+export default function Header() {
+ const [searchValue, setSearchValue] = useState('');
+ const [open, setOpen] = useState(false)
+ const {openSignIn, openSignUp} = useClerk()
+
+ const handleChange = (event: React.ChangeEvent) => {
+ setSearchValue(event.target.value)
+ }
+
+ const handleSearch: React.KeyboardEventHandler = (event) => {
+ if (event.key === 'Enter') {
+ console.log(searchValue)
+ setSearchValue('')
+ }
+ }
+
+ const handleShow = () => {
+ setOpen(!open)
+ }
+ return (
+
+
+
+ Logo
+
+
+ Search
+
+
+
+
+
+
+
+
+
+
+
+ {/**/}
+
+ openSignIn({
+ afterSignInUrl: '/'
+ })}>Sign In
+ openSignUp({})}>Sign Up
+
+
+
+
+
+
+
+
+
+
+ Home
+
+
+
+ Trending
+
+
+
+
+
+
+ Create Channel
+
+
+
+
+
+
+
+
+ {/*TODO Top communities */}
+ Python
+
+
+
+
+
+
+
+
+ )
+}
diff --git a/client/src/components/core/recent-posts.tsx b/client/src/components/core/recent-posts.tsx
new file mode 100644
index 0000000..18897f2
--- /dev/null
+++ b/client/src/components/core/recent-posts.tsx
@@ -0,0 +1,13 @@
+import {Separator} from "~/components/ui/separator";
+import React from "react";
+
+export default function RecentPosts() {
+ return (
+
+ )
+}
\ No newline at end of file
diff --git a/client/src/components/core/side-bar.tsx b/client/src/components/core/side-bar.tsx
new file mode 100644
index 0000000..fad6238
--- /dev/null
+++ b/client/src/components/core/side-bar.tsx
@@ -0,0 +1,52 @@
+import React from "react";
+import Link from "next/link";
+import {FaArrowDown, FaPlus} from "react-icons/fa6";
+import {FaHome} from "react-icons/fa";
+import {FaRocket} from "react-icons/fa";
+import {Separator} from "~/components/ui/separator"
+import {Button} from "~/components/ui/button";
+import {Collapsible, CollapsibleContent, CollapsibleTrigger} from "~/components/ui/collapsible";
+
+export default function SideBar() {
+ return (
+
+
+
+
+
+ Home
+
+
+
+ Popular
+
+
+
+
+
+ Create Channel
+
+
+
+
+
+
+
+ {/*TODO Top communities */}
+ Python
+
+
+
+
+
+
+
+
+ )
+}
diff --git a/client/src/components/posts/posts.tsx b/client/src/components/posts/posts.tsx
new file mode 100644
index 0000000..5008d5d
--- /dev/null
+++ b/client/src/components/posts/posts.tsx
@@ -0,0 +1,5 @@
+export default function Posts() {
+ return (
+ {/* TODO Create a filter tab */}
+
)
+}
\ No newline at end of file
diff --git a/client/src/components/ui/button.tsx b/client/src/components/ui/button.tsx
new file mode 100644
index 0000000..d754ca0
--- /dev/null
+++ b/client/src/components/ui/button.tsx
@@ -0,0 +1,56 @@
+import * as React from "react"
+import { Slot } from "@radix-ui/react-slot"
+import { cva, type VariantProps } from "class-variance-authority"
+
+import { cn } from "~/lib/utils"
+
+const buttonVariants = cva(
+ "inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",
+ {
+ variants: {
+ variant: {
+ default: "bg-primary text-primary-foreground hover:bg-primary/90",
+ destructive:
+ "bg-destructive text-destructive-foreground hover:bg-destructive/90",
+ outline:
+ "border border-input bg-background hover:bg-accent hover:text-accent-foreground",
+ secondary:
+ "bg-secondary text-secondary-foreground hover:bg-secondary/80",
+ ghost: "hover:bg-accent hover:text-accent-foreground",
+ link: "text-primary underline-offset-4 hover:underline",
+ },
+ 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: {
+ variant: "default",
+ size: "default",
+ },
+ }
+)
+
+export interface ButtonProps
+ extends React.ButtonHTMLAttributes,
+ VariantProps {
+ asChild?: boolean
+}
+
+const Button = React.forwardRef(
+ ({ className, variant, size, asChild = false, ...props }, ref) => {
+ const Comp = asChild ? Slot : "button"
+ return (
+
+ )
+ }
+)
+Button.displayName = "Button"
+
+export { Button, buttonVariants }
diff --git a/client/src/components/ui/collapsible.tsx b/client/src/components/ui/collapsible.tsx
new file mode 100644
index 0000000..9fa4894
--- /dev/null
+++ b/client/src/components/ui/collapsible.tsx
@@ -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 }
diff --git a/client/src/components/ui/form.tsx b/client/src/components/ui/form.tsx
new file mode 100644
index 0000000..7b52676
--- /dev/null
+++ b/client/src/components/ui/form.tsx
@@ -0,0 +1,176 @@
+import * as React from "react"
+import type * as LabelPrimitive from "@radix-ui/react-label"
+import { Slot } from "@radix-ui/react-slot"
+import {
+ Controller,
+ type ControllerProps,
+ type FieldPath,
+ type FieldValues,
+ FormProvider,
+ useFormContext,
+} from "react-hook-form"
+
+import { cn } from "~/lib/utils"
+import { Label } from "~/components/ui/label"
+
+const Form = FormProvider
+
+type FormFieldContextValue<
+ TFieldValues extends FieldValues = FieldValues,
+ TName extends FieldPath = FieldPath
+> = {
+ name: TName
+}
+
+const FormFieldContext = React.createContext(
+ {} as FormFieldContextValue
+)
+
+const FormField = <
+ TFieldValues extends FieldValues = FieldValues,
+ TName extends FieldPath = FieldPath
+>({
+ ...props
+}: ControllerProps) => {
+ return (
+
+
+
+ )
+}
+
+const useFormField = () => {
+ const fieldContext = React.useContext(FormFieldContext)
+ const itemContext = React.useContext(FormItemContext)
+ const { getFieldState, formState } = useFormContext()
+
+ const fieldState = getFieldState(fieldContext.name, formState)
+
+ if (!fieldContext) {
+ throw new Error("useFormField should be used within ")
+ }
+
+ const { id } = itemContext
+
+ return {
+ id,
+ name: fieldContext.name,
+ formItemId: `${id}-form-item`,
+ formDescriptionId: `${id}-form-item-description`,
+ formMessageId: `${id}-form-item-message`,
+ ...fieldState,
+ }
+}
+
+type FormItemContextValue = {
+ id: string
+}
+
+const FormItemContext = React.createContext(
+ {} as FormItemContextValue
+)
+
+const FormItem = React.forwardRef<
+ HTMLDivElement,
+ React.HTMLAttributes
+>(({ className, ...props }, ref) => {
+ const id = React.useId()
+
+ return (
+
+
+
+ )
+})
+FormItem.displayName = "FormItem"
+
+const FormLabel = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => {
+ const { error, formItemId } = useFormField()
+
+ return (
+
+ )
+})
+FormLabel.displayName = "FormLabel"
+
+const FormControl = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ ...props }, ref) => {
+ const { error, formItemId, formDescriptionId, formMessageId } = useFormField()
+
+ return (
+
+ )
+})
+FormControl.displayName = "FormControl"
+
+const FormDescription = React.forwardRef<
+ HTMLParagraphElement,
+ React.HTMLAttributes
+>(({ className, ...props }, ref) => {
+ const { formDescriptionId } = useFormField()
+
+ return (
+
+ )
+})
+FormDescription.displayName = "FormDescription"
+
+const FormMessage = React.forwardRef<
+ HTMLParagraphElement,
+ React.HTMLAttributes
+>(({ className, children, ...props }, ref) => {
+ const { error, formMessageId } = useFormField()
+ const body = error ? String(error?.message) : children
+
+ if (!body) {
+ return null
+ }
+
+ return (
+
+ {body}
+
+ )
+})
+FormMessage.displayName = "FormMessage"
+
+export {
+ useFormField,
+ Form,
+ FormItem,
+ FormLabel,
+ FormControl,
+ FormDescription,
+ FormMessage,
+ FormField,
+}
diff --git a/client/src/components/ui/input.tsx b/client/src/components/ui/input.tsx
new file mode 100644
index 0000000..b818b79
--- /dev/null
+++ b/client/src/components/ui/input.tsx
@@ -0,0 +1,24 @@
+import * as React from "react"
+
+import { cn } from "~/lib/utils"
+
+export type InputProps = React.InputHTMLAttributes
+
+const Input = React.forwardRef(
+ ({ className, type, ...props }, ref) => {
+ return (
+
+ )
+ }
+)
+Input.displayName = "Input"
+
+export { Input }
diff --git a/client/src/components/ui/label.tsx b/client/src/components/ui/label.tsx
new file mode 100644
index 0000000..8f40738
--- /dev/null
+++ b/client/src/components/ui/label.tsx
@@ -0,0 +1,26 @@
+"use client"
+
+import * as React from "react"
+import * as LabelPrimitive from "@radix-ui/react-label"
+import { cva, type VariantProps } from "class-variance-authority"
+
+import { cn } from "~/lib/utils"
+
+const labelVariants = cva(
+ "text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
+)
+
+const Label = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef &
+ VariantProps
+>(({ className, ...props }, ref) => (
+
+))
+Label.displayName = LabelPrimitive.Root.displayName
+
+export { Label }
diff --git a/client/src/components/ui/separator.tsx b/client/src/components/ui/separator.tsx
new file mode 100644
index 0000000..49d5182
--- /dev/null
+++ b/client/src/components/ui/separator.tsx
@@ -0,0 +1,31 @@
+"use client"
+
+import * as React from "react"
+import * as SeparatorPrimitive from "@radix-ui/react-separator"
+
+import { cn } from "~/lib/utils"
+
+const Separator = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(
+ (
+ { className, orientation = "horizontal", decorative = true, ...props },
+ ref
+ ) => (
+
+ )
+)
+Separator.displayName = SeparatorPrimitive.Root.displayName
+
+export { Separator }
diff --git a/client/src/components/ui/sheet.tsx b/client/src/components/ui/sheet.tsx
new file mode 100644
index 0000000..74625ae
--- /dev/null
+++ b/client/src/components/ui/sheet.tsx
@@ -0,0 +1,140 @@
+"use client"
+
+import * as React from "react"
+import * as SheetPrimitive from "@radix-ui/react-dialog"
+import { cva, type VariantProps } from "class-variance-authority"
+import { FaTimes as X } from "react-icons/fa";
+
+import { cn } from "~/lib/utils"
+
+const Sheet = SheetPrimitive.Root
+
+const SheetTrigger = SheetPrimitive.Trigger
+
+const SheetClose = SheetPrimitive.Close
+
+const SheetPortal = SheetPrimitive.Portal
+
+const SheetOverlay = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+))
+SheetOverlay.displayName = SheetPrimitive.Overlay.displayName
+
+const sheetVariants = cva(
+ "fixed z-50 gap-4 bg-background p-6 shadow-lg transition ease-in-out data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:duration-300 data-[state=open]:duration-500",
+ {
+ variants: {
+ side: {
+ top: "inset-x-0 top-0 border-b data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top",
+ bottom:
+ "inset-x-0 bottom-0 border-t data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom",
+ left: "inset-y-0 left-0 h-full w-3/4 border-r data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left sm:max-w-sm",
+ right:
+ "inset-y-0 right-0 h-full w-3/4 border-l data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right sm:max-w-sm",
+ },
+ },
+ defaultVariants: {
+ side: "right",
+ },
+ }
+)
+
+interface SheetContentProps
+ extends React.ComponentPropsWithoutRef,
+ VariantProps {}
+
+const SheetContent = React.forwardRef<
+ React.ElementRef,
+ SheetContentProps
+>(({ side = "right", className, children, ...props }, ref) => (
+
+
+
+ {children}
+
+
+ Close
+
+
+
+))
+SheetContent.displayName = SheetPrimitive.Content.displayName
+
+const SheetHeader = ({
+ className,
+ ...props
+}: React.HTMLAttributes) => (
+
+)
+SheetHeader.displayName = "SheetHeader"
+
+const SheetFooter = ({
+ className,
+ ...props
+}: React.HTMLAttributes) => (
+
+)
+SheetFooter.displayName = "SheetFooter"
+
+const SheetTitle = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+))
+SheetTitle.displayName = SheetPrimitive.Title.displayName
+
+const SheetDescription = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+))
+SheetDescription.displayName = SheetPrimitive.Description.displayName
+
+export {
+ Sheet,
+ SheetPortal,
+ SheetOverlay,
+ SheetTrigger,
+ SheetClose,
+ SheetContent,
+ SheetHeader,
+ SheetFooter,
+ SheetTitle,
+ SheetDescription,
+}
diff --git a/client/src/lib/utils.ts b/client/src/lib/utils.ts
new file mode 100644
index 0000000..d084cca
--- /dev/null
+++ b/client/src/lib/utils.ts
@@ -0,0 +1,6 @@
+import { type ClassValue, clsx } from "clsx"
+import { twMerge } from "tailwind-merge"
+
+export function cn(...inputs: ClassValue[]) {
+ return twMerge(clsx(inputs))
+}
diff --git a/client/src/middleware.ts b/client/src/middleware.ts
new file mode 100644
index 0000000..eca7067
--- /dev/null
+++ b/client/src/middleware.ts
@@ -0,0 +1,25 @@
+import { authMiddleware } from "@clerk/nextjs";
+
+// See https://clerk.com/docs/references/nextjs/auth-middleware
+// for more information about configuring your Middleware
+
+export default authMiddleware({
+ // Allow signed out users to access the specified routes:
+ // publicRoutes: ['/anyone-can-visit-this-route'],
+ // Prevent the specified routes from accessing
+ // authentication information:
+ // ignoredRoutes: ['/no-auth-in-this-route'],
+ publicRoutes: ['/'],
+ ignoredRoutes: ['/api', '/trpc'],
+});
+
+export const config = {
+ matcher: [
+ // Exclude files with a "." followed by an extension, which are typically static files.
+ // Exclude files in the _next directory, which are Next.js internals.
+
+ "/((?!.+\\.[\\w]+$|_next).*)",
+ // Re-include any files in the api or trpc folders that might have an extension
+ "/(api|trpc)(.*)"
+ ]
+};
\ No newline at end of file
diff --git a/client/tailwind.config.ts b/client/tailwind.config.ts
index e9a0944..84287e8 100644
--- a/client/tailwind.config.ts
+++ b/client/tailwind.config.ts
@@ -1,20 +1,80 @@
-import type { Config } from "tailwindcss";
+import type { Config } from "tailwindcss"
-const config: Config = {
+const config = {
+ darkMode: ["class"],
content: [
- "./src/pages/**/*.{js,ts,jsx,tsx,mdx}",
- "./src/components/**/*.{js,ts,jsx,tsx,mdx}",
- "./src/app/**/*.{js,ts,jsx,tsx,mdx}",
- ],
+ './pages/**/*.{ts,tsx}',
+ './components/**/*.{ts,tsx}',
+ './app/**/*.{ts,tsx}',
+ './src/**/*.{ts,tsx}',
+ ],
+ prefix: "",
theme: {
+ container: {
+ center: true,
+ padding: "2rem",
+ screens: {
+ "2xl": "1400px",
+ },
+ },
extend: {
- backgroundImage: {
- "gradient-radial": "radial-gradient(var(--tw-gradient-stops))",
- "gradient-conic":
- "conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))",
+ colors: {
+ border: "hsl(var(--border))",
+ input: "hsl(var(--input))",
+ ring: "hsl(var(--ring))",
+ background: "hsl(var(--background))",
+ foreground: "hsl(var(--foreground))",
+ primary: {
+ DEFAULT: "hsl(var(--primary))",
+ foreground: "hsl(var(--primary-foreground))",
+ },
+ secondary: {
+ DEFAULT: "hsl(var(--secondary))",
+ foreground: "hsl(var(--secondary-foreground))",
+ },
+ destructive: {
+ DEFAULT: "hsl(var(--destructive))",
+ foreground: "hsl(var(--destructive-foreground))",
+ },
+ muted: {
+ DEFAULT: "hsl(var(--muted))",
+ foreground: "hsl(var(--muted-foreground))",
+ },
+ accent: {
+ DEFAULT: "hsl(var(--accent))",
+ foreground: "hsl(var(--accent-foreground))",
+ },
+ popover: {
+ DEFAULT: "hsl(var(--popover))",
+ foreground: "hsl(var(--popover-foreground))",
+ },
+ card: {
+ DEFAULT: "hsl(var(--card))",
+ foreground: "hsl(var(--card-foreground))",
+ },
+ },
+ borderRadius: {
+ lg: "var(--radius)",
+ md: "calc(var(--radius) - 2px)",
+ sm: "calc(var(--radius) - 4px)",
+ },
+ keyframes: {
+ "accordion-down": {
+ from: { height: "0" },
+ to: { height: "var(--radix-accordion-content-height)" },
+ },
+ "accordion-up": {
+ from: { height: "var(--radix-accordion-content-height)" },
+ to: { height: "0" },
+ },
+ },
+ animation: {
+ "accordion-down": "accordion-down 0.2s ease-out",
+ "accordion-up": "accordion-up 0.2s ease-out",
},
},
},
- plugins: [],
-};
-export default config;
+ plugins: [require("tailwindcss-animate")],
+} satisfies Config
+
+export default config
\ No newline at end of file
diff --git a/server/package.json b/server/package.json
index 05871ba..597e92e 100644
--- a/server/package.json
+++ b/server/package.json
@@ -19,7 +19,8 @@
"test:watch": "jest --watch",
"test:cov": "jest --coverage",
"test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand",
- "test:e2e": "jest --config ./test/jest-e2e.json"
+ "test:e2e": "jest --config ./test/jest-e2e.json",
+ "prisma:seed": "ts-node prisma/seeds/seeds"
},
"dependencies": {
"@clerk/clerk-sdk-node": "^4.13.11",
@@ -38,9 +39,11 @@
"passport-jwt": "^4.0.1",
"reflect-metadata": "^0.2.0",
"rxjs": "^7.8.1",
+ "svix": "^1.21.0",
"swagger-ui-express": "^5.0.0"
},
"devDependencies": {
+ "@faker-js/faker": "^8.4.1",
"@nestjs/cli": "^10.0.0",
"@nestjs/schematics": "^10.0.0",
"@nestjs/testing": "^10.0.0",
diff --git a/server/pnpm-lock.yaml b/server/pnpm-lock.yaml
index a6318be..3866fb8 100644
--- a/server/pnpm-lock.yaml
+++ b/server/pnpm-lock.yaml
@@ -53,11 +53,17 @@ dependencies:
rxjs:
specifier: ^7.8.1
version: 7.8.1
+ svix:
+ specifier: ^1.21.0
+ version: 1.21.0
swagger-ui-express:
specifier: ^5.0.0
version: 5.0.0(express@4.18.3)
devDependencies:
+ '@faker-js/faker':
+ specifier: ^8.4.1
+ version: 8.4.1
'@nestjs/cli':
specifier: ^10.0.0
version: 10.3.2
@@ -622,6 +628,11 @@ packages:
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
dev: true
+ /@faker-js/faker@8.4.1:
+ resolution: {integrity: sha512-XQ3cU+Q8Uqmrbf2e0cIC/QN43sTBSC8KF12u29Mb47tWrt2hAgBXSgpZMj4Ao8Uk0iJcU99QsOCaIL8934obCg==}
+ engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0, npm: '>=6.14.13'}
+ dev: true
+
/@humanwhocodes/config-array@0.11.14:
resolution: {integrity: sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==}
engines: {node: '>=10.10.0'}
@@ -1310,6 +1321,10 @@ packages:
'@sinonjs/commons': 3.0.1
dev: true
+ /@stablelib/base64@1.0.1:
+ resolution: {integrity: sha512-1bnPQqSxSuc3Ii6MhBysoWCg58j97aUjuCSZrGSmDxNqtytIi0k8utUenAwTZN4V5mXXYGsVUI9zeBqy+jBOSQ==}
+ dev: false
+
/@tsconfig/node10@1.0.9:
resolution: {integrity: sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==}
dev: true
@@ -2658,6 +2673,10 @@ packages:
resolution: {integrity: sha512-7nOqkomXZEaxUDJw21XZNtRk739QvrPSoZoRtbsEfcii00vdzZUh6zh1CQwHhrib8MdEtJfv5rJiGeb4KuV/vw==}
dev: true
+ /es6-promise@4.2.8:
+ resolution: {integrity: sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==}
+ dev: false
+
/escalade@3.1.2:
resolution: {integrity: sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==}
engines: {node: '>=6'}
@@ -2945,6 +2964,10 @@ packages:
/fast-safe-stringify@2.1.1:
resolution: {integrity: sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==}
+ /fast-sha256@1.3.0:
+ resolution: {integrity: sha512-n11RGP/lrWEFI/bWdygLxhI+pVeo1ZYIVwvvPkW7azl/rOy+F3HYRZ2K5zeE9mmkhQppyv9sQFx0JM9UabnpPQ==}
+ dev: false
+
/fastq@1.17.1:
resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==}
dependencies:
@@ -4707,6 +4730,10 @@ packages:
side-channel: 1.0.6
dev: true
+ /querystringify@2.2.0:
+ resolution: {integrity: sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==}
+ dev: false
+
/queue-microtask@1.2.3:
resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
dev: true
@@ -4798,6 +4825,10 @@ packages:
engines: {node: '>=0.10.0'}
dev: true
+ /requires-port@1.0.0:
+ resolution: {integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==}
+ dev: false
+
/resolve-cwd@3.0.0:
resolution: {integrity: sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==}
engines: {node: '>=8'}
@@ -5199,6 +5230,27 @@ packages:
engines: {node: '>= 0.4'}
dev: true
+ /svix-fetch@3.0.0:
+ resolution: {integrity: sha512-rcADxEFhSqHbraZIsjyZNh4TF6V+koloX1OzZ+AQuObX9mZ2LIMhm1buZeuc5BIZPftZpJCMBsSiBaeszo9tRw==}
+ dependencies:
+ node-fetch: 2.7.0
+ whatwg-fetch: 3.6.20
+ transitivePeerDependencies:
+ - encoding
+ dev: false
+
+ /svix@1.21.0:
+ resolution: {integrity: sha512-aKZVf1Jc962frT/Hpz064mtpDgu80dBK1B/+qVY5PKYdYIzOpvdiWn3pqQNjCTN8T4vwg9oc4xl1xTd1ka3agQ==}
+ dependencies:
+ '@stablelib/base64': 1.0.1
+ es6-promise: 4.2.8
+ fast-sha256: 1.3.0
+ svix-fetch: 3.0.0
+ url-parse: 1.5.10
+ transitivePeerDependencies:
+ - encoding
+ dev: false
+
/swagger-ui-dist@5.11.2:
resolution: {integrity: sha512-jQG0cRgJNMZ7aCoiFofnoojeSaa/+KgWaDlfgs8QN+BXoGMpxeMVY5OEnjq4OlNvF3yjftO8c9GRAgcHlO+u7A==}
dev: false
@@ -5570,6 +5622,13 @@ packages:
punycode: 2.3.1
dev: true
+ /url-parse@1.5.10:
+ resolution: {integrity: sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==}
+ dependencies:
+ querystringify: 2.2.0
+ requires-port: 1.0.0
+ dev: false
+
/use-sync-external-store@1.2.0(react@18.2.0):
resolution: {integrity: sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==}
peerDependencies:
@@ -5734,6 +5793,10 @@ packages:
- uglify-js
dev: true
+ /whatwg-fetch@3.6.20:
+ resolution: {integrity: sha512-EqhiFU6daOA8kpjOWTL0olhVOF3i7OrFzSYiGsEMB8GcXS+RrzauAERX65xMeNWVqxA6HXH2m69Z9LaKKdisfg==}
+ dev: false
+
/whatwg-url@5.0.0:
resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==}
dependencies:
diff --git a/server/prisma/schema.prisma b/server/prisma/schema.prisma
index 70227a6..14d13bb 100644
--- a/server/prisma/schema.prisma
+++ b/server/prisma/schema.prisma
@@ -23,10 +23,10 @@ datasource db {
model User {
id String @id @default(cuid())
username String @unique
- passwordHash String
+ password String
avatarUrl String?
reputation Int @default(0)
- role ROLE
+ role ROLE @default(user)
lastLogin DateTime?
email String @unique
emailVerified Boolean @default(false)
@@ -133,6 +133,37 @@ model Post {
@@index([title, userId, forumId, slug])
}
+model Attachment {
+ id String @id @default(cuid())
+ name String
+ type String
+ url String
+ created_at DateTime @default(now())
+ updated_at DateTime @updatedAt
+ postAttachments PostAttachment[]
+ commentAttachments CommentAttachment[]
+}
+
+model PostAttachment {
+ id String @unique @default(cuid())
+ postId String
+ attachmentId String
+ post Post @relation("PostAttachments", fields: [postId], references: [id])
+ attachment Attachment @relation(fields: [attachmentId], references: [id])
+
+ @@id([postId, attachmentId])
+}
+
+model CommentAttachment {
+ id String @unique @default(cuid())
+ commentId String
+ attachmentId String
+ comment Comment @relation("CommentAttachments", fields: [commentId], references: [id])
+ attachment Attachment @relation(fields: [attachmentId], references: [id])
+
+ @@id([commentId, attachmentId])
+}
+
model Comment {
// when anyone post comment, it will send notification to the post owner and parrent post/comment
id String @id @default(cuid())
@@ -178,37 +209,6 @@ model CommentVotes {
@@unique([userId, commentId])
}
-model Attachment {
- id String @id @default(cuid())
- name String
- type String
- url String
- created_at DateTime @default(now())
- updated_at DateTime @updatedAt
- postAttachments PostAttachment[]
- commentAttachments CommentAttachment[]
-}
-
-model PostAttachment {
- id String @unique @default(cuid())
- postId String
- attachmentId String
- post Post @relation("PostAttachments", fields: [postId], references: [id])
- attachment Attachment @relation(fields: [attachmentId], references: [id])
-
- @@id([postId, attachmentId])
-}
-
-model CommentAttachment {
- id String @unique @default(cuid())
- commentId String
- attachmentId String
- comment Comment @relation("CommentAttachments", fields: [commentId], references: [id])
- attachment Attachment @relation(fields: [attachmentId], references: [id])
-
- @@id([commentId, attachmentId])
-}
-
model UserFollows {
follower_id String
following_id String
@@ -276,6 +276,7 @@ model Report {
status String
actionTaken String?
createdAt DateTime @default(now())
+ updatedAt DateTime @updatedAt
reporter User @relation("ReporterUser", fields: [reporterId], references: [id])
post Post? @relation("ReportPost", fields: [postId], references: [id])
comment Comment? @relation("ReportComment", fields: [commentId], references: [id])
diff --git a/server/prisma/seeds/comment.seeder.ts b/server/prisma/seeds/comment.seeder.ts
new file mode 100644
index 0000000..d72c4bd
--- /dev/null
+++ b/server/prisma/seeds/comment.seeder.ts
@@ -0,0 +1,73 @@
+// comment.seeder.ts
+import { PrismaClient } from '@prisma/client';
+import { faker } from '@faker-js/faker';
+
+interface User {
+ id: string;
+ username: string;
+ password: string;
+ avatarUrl: string | null;
+ reputation: number;
+ role: 'admin' | 'user';
+ lastLogin: Date | null;
+ email: string;
+ emailVerified: boolean;
+ verificationToken: string | null;
+ country: string | null;
+ city: string | null;
+ phone: string | null;
+ website: string | null;
+ aboutMe: string | null;
+ createdAt: Date;
+ updatedAt: Date;
+ deletedAt: Date | null;
+ PostCount: number;
+ CommentCount: number;
+ followersCount: number;
+ followingCount: number;
+ subscribedForumsCount: number;
+}
+
+interface Post {
+ id: string;
+ title: string;
+ content: string;
+ userId: string;
+ forumId: string;
+ isPinned: boolean;
+ isVisible: boolean;
+ slug: string;
+ createdAt: Date;
+ updatedAt: Date;
+ commentsCount: number;
+ viewsCount: number;
+ votesCount: number;
+}
+
+
+const prisma = new PrismaClient();
+export async function seedComments(users: User[], posts: Post[]) {
+ for (let i = 0; i < posts.length; i++) {
+ const post = posts[i];
+ for (let j = 0; j < 3; j++) {
+ const comment = await prisma.comment.create({
+ data: {
+ content: faker.lorem.paragraphs(2),
+ userId: users[j % users.length].id, // Cycle through users
+ postId: post.id,
+ },
+ });
+
+ for (let k = 0; k < 2; k++) {
+ await prisma.comment.create({
+ data: {
+ content: faker.lorem.paragraphs(1),
+ userId: users[(j + k + 1) % users.length].id, // Cycle through users
+ postId: post.id,
+ parentId: comment.id, // Set the parent comment id for replies
+ },
+ });
+ }
+ }
+ }
+}
diff --git a/server/prisma/seeds/forum.seeder.ts b/server/prisma/seeds/forum.seeder.ts
new file mode 100644
index 0000000..baa6236
--- /dev/null
+++ b/server/prisma/seeds/forum.seeder.ts
@@ -0,0 +1,47 @@
+// forum.seeder.ts
+import { PrismaClient } from '@prisma/client';
+import { faker } from '@faker-js/faker';
+
+const prisma = new PrismaClient();
+
+export async function seedForums(users) {
+ console.log("------------ Starting to seed forums...");
+ const forums = [];
+ for (let i = 0; i < 5; i++) {
+ const forum = await prisma.forum.create({
+ data: {
+ name: faker.lorem.words(3),
+ slug: faker.lorem.slug(),
+ description: faker.lorem.sentences(3),
+ ownerUserId: users[i].id,
+ logo: faker.image.url(),
+ banner: faker.image.url(),
+ created_at: new Date(),
+ updated_at: new Date(),
+ postsCount: faker.number.int({ min: 0, max: 100 }),
+ viewsCount: faker.number.int({ min: 0, max: 1000 }),
+ subscribersCount: faker.number.int({ min: 0, max: 500 }),
+ },
+ });
+ console.log(`Forum with id ${forum.id} created.`);
+
+ const ownerAsModerator = await prisma.forumModerator.create({
+ data: {
+ userId: users[i].id,
+ forumId: forum.id,
+ },
+ });
+
+ const otherModerator = await prisma.forumModerator.create({
+ data: {
+ userId: users[i + 5].id,
+ forumId: forum.id,
+ },
+ });
+
+ forums.push({ ...forum, moderators: [ownerAsModerator, otherModerator] });
+ }
+
+ console.log("------------ Finished seeding forums.");
+ return forums;
+}
diff --git a/server/prisma/seeds/notification.seeder.ts b/server/prisma/seeds/notification.seeder.ts
new file mode 100644
index 0000000..89757af
--- /dev/null
+++ b/server/prisma/seeds/notification.seeder.ts
@@ -0,0 +1,9 @@
+// notification.seeder.ts
+import { PrismaClient } from '@prisma/client';
+import { faker } from '@faker-js/faker';
+
+const prisma = new PrismaClient();
+
+export async function seedNotifications(users) {
+ // your code to seed notifications here
+}
diff --git a/server/prisma/seeds/post.seeder.ts b/server/prisma/seeds/post.seeder.ts
new file mode 100644
index 0000000..e95e2ac
--- /dev/null
+++ b/server/prisma/seeds/post.seeder.ts
@@ -0,0 +1,123 @@
+// post.seeder.ts
+import { PrismaClient } from '@prisma/client';
+import { faker } from '@faker-js/faker';
+
+const prisma = new PrismaClient();
+
+export async function seedPosts(users, forums) {
+ console.log("------------ Starting to seed posts...");
+ const posts = [];
+ for (let i = 0; i < forums.length; i++) {
+ const forum = forums[i];
+ const ownerId = forum.ownerUserId;
+ const moderator = forum.moderators.find(moderator => moderator.userId !== ownerId);
+ const otherUsers = users.filter(user => user.id !== ownerId && user.id !== moderator.userId);
+
+ const ownerAttachment = await prisma.attachment.create({
+ data: {
+ name: faker.system.fileName(),
+ type: faker.system.commonFileType(),
+ url: faker.internet.url(),
+ },
+ });
+
+ const ownerPost = await prisma.post.create({
+ data: {
+ title: faker.lorem.sentence(),
+ content: faker.lorem.paragraphs(3),
+ userId: ownerId,
+ forumId: forum.id,
+ isPinned: true,
+ isVisible: true,
+ slug: faker.lorem.slug(),
+ createdAt: new Date(),
+ updatedAt: new Date(),
+ commentsCount: faker.number.int({ min: 0, max: 100 }),
+ viewsCount: faker.number.int({ min: 0, max: 1000 }),
+ votesCount: faker.number.int({ min: 0, max: 500 }),
+ },
+ });
+ console.log(`------------ Post with id ${ownerPost.id} created by owner.`);
+
+ await prisma.postAttachment.create({
+ data: {
+ postId: ownerPost.id,
+ attachmentId: ownerAttachment.id,
+ },
+ });
+
+ const moderatorAttachment = await prisma.attachment.create({
+ data: {
+ name: faker.system.fileName(),
+ type: faker.system.commonFileType(),
+ url: faker.internet.url(),
+ },
+ });
+
+ const moderatorPost = await prisma.post.create({
+ data: {
+ title: faker.lorem.sentence(),
+ content: faker.lorem.paragraphs(3),
+ userId: moderator.userId,
+ forumId: forum.id,
+ isPinned: true,
+ isVisible: true,
+ slug: faker.lorem.slug(),
+ createdAt: new Date(),
+ updatedAt: new Date(),
+ commentsCount: faker.number.int({ min: 0, max: 100 }),
+ viewsCount: faker.number.int({ min: 0, max: 1000 }),
+ votesCount: faker.number.int({ min: 0, max: 500 }),
+ },
+ });
+ console.log(`------------ Post with id ${moderatorPost.id} created by moderator.`);
+
+ await prisma.postAttachment.create({
+ data: {
+ postId: moderatorPost.id,
+ attachmentId: moderatorAttachment.id,
+ },
+ });
+
+ for (let j = 0; j < 3; j++) {
+ const userAttachment = await prisma.attachment.create({
+ data: {
+ name: faker.system.fileName(),
+ type: faker.system.commonFileType(),
+ url: faker.internet.url(),
+ },
+ });
+
+ const userPost = await prisma.post.create({
+ data: {
+ title: faker.lorem.sentence(),
+ content: faker.lorem.paragraphs(3),
+ userId: otherUsers[j].id,
+ forumId: forum.id,
+ isPinned: false,
+ isVisible: true,
+ slug: faker.lorem.slug(),
+ createdAt: new Date(),
+ updatedAt: new Date(),
+ commentsCount: faker.number.int({ min: 0, max: 100 }),
+ viewsCount: faker.number.int({ min: 0, max: 1000 }),
+ votesCount: faker.number.int({ min: 0, max: 500 }),
+ },
+ });
+ console.log(`------------ Post with id ${userPost.id} created by user.`);
+
+ await prisma.postAttachment.create({
+ data: {
+ postId: userPost.id,
+ attachmentId: userAttachment.id,
+ },
+ });
+
+ posts.push(userPost);
+ }
+ posts.push(ownerPost, moderatorPost);
+ }
+
+ console.log("------------ Finished seeding posts.");
+ return posts;
+}
diff --git a/server/prisma/seeds/seeds.ts b/server/prisma/seeds/seeds.ts
new file mode 100644
index 0000000..4d6620c
--- /dev/null
+++ b/server/prisma/seeds/seeds.ts
@@ -0,0 +1,43 @@
+// seed.ts
+import { PrismaClient } from '@prisma/client';
+import { seedUsers } from './user.seeder';
+import { seedForums } from './forum.seeder';
+import { seedPosts } from './post.seeder';
+import { seedComments } from './comment.seeder';
+import { seedNotifications } from './notification.seeder';
+
+const prisma = new PrismaClient();
+
+async function cleanDatabase() {
+ console.log("Cleaning database...");
+
+ // Delete all records from your tables
+ await prisma.postAttachment.deleteMany();
+ await prisma.attachment.deleteMany();
+ await prisma.post.deleteMany();
+ await prisma.forumModerator.deleteMany();
+ await prisma.forum.deleteMany();
+ await prisma.user.deleteMany();
+
+ console.log("Finished cleaning database.");
+}
+
+async function main() {
+ await cleanDatabase();
+ const users = await seedUsers();
+ const forums = await seedForums(users);
+ const posts = await seedPosts(users, forums);
+ //await seedComments(users, posts);
+ //await seedNotifications(users);
+
+ // Add code to seed other entities here
+}
+
+main()
+ .catch((e) => {
+ console.error(e);
+ process.exit(1);
+ })
+ .finally(async () => {
+ await prisma.$disconnect();
+ });
diff --git a/server/prisma/seeds/user.seeder.ts b/server/prisma/seeds/user.seeder.ts
new file mode 100644
index 0000000..0be735d
--- /dev/null
+++ b/server/prisma/seeds/user.seeder.ts
@@ -0,0 +1,39 @@
+// user.seeder.ts
+import { PrismaClient } from '@prisma/client';
+import { faker } from '@faker-js/faker';
+
+const prisma = new PrismaClient();
+
+export async function seedUsers() {
+ console.log("------------ Starting to seed users...");
+ const users = [];
+ for (let i = 0; i < 10; i++) {
+ const user = await prisma.user.create({
+ data: {
+ username: faker.internet.userName(),
+ email: faker.internet.email(),
+ password: faker.internet.password(),
+ avatarUrl: faker.image.avatar(),
+ reputation: faker.number.int({ min: 0, max: 100 }),
+ role: 'user',
+ lastLogin: faker.date.past(),
+ emailVerified: faker.datatype.boolean(),
+ country: faker.location.country(),
+ city: faker.location.city(),
+ phone: faker.phone.number(),
+ website: faker.internet.url(),
+ aboutMe: faker.lorem.paragraph(),
+ PostCount: faker.number.int({ min: 0, max: 100 }),
+ CommentCount: faker.number.int({ min: 0, max: 100 }),
+ followersCount: faker.number.int({ min: 0, max: 100 }),
+ followingCount: faker.number.int({ min: 0, max: 100 }),
+ subscribedForumsCount: faker.number.int({ min: 0, max: 100 }),
+ },
+ });
+ console.log(`------------ User with id ${user.id} created.`);
+ users.push(user);
+ }
+
+ console.log("------------ Finished seeding users.");
+ return users;
+}
diff --git a/server/src/main.ts b/server/src/main.ts
index f581f40..c6aee4a 100644
--- a/server/src/main.ts
+++ b/server/src/main.ts
@@ -9,9 +9,12 @@ import { AppModule } from './modules/app/app.module';
import { API_PREFIX } from './shared/constants/global.constants';
import { SwaggerConfig } from './configs/config.interface';
import { GLOBAL_CONFIG } from './configs/global.config';
+import type { NestExpressApplication } from '@nestjs/platform-express';
async function bootstrap() {
- const app = await NestFactory.create(AppModule, {
+ const app = await NestFactory.create(AppModule, {
+ bodyParser: true,
+ rawBody: true,
logger: ['error', 'error', 'warn'],
});
diff --git a/server/src/modules/app/app.module.ts b/server/src/modules/app/app.module.ts
index 699776d..3d12e29 100644
--- a/server/src/modules/app/app.module.ts
+++ b/server/src/modules/app/app.module.ts
@@ -3,19 +3,21 @@ import { ConfigModule, ConfigService } from '@nestjs/config';
import { UserModule } from '../user/user.module';
import { PostModule } from '../post/post.module';
-import { AuthModule } from '../auth/auth.module';
+//import { AuthModule } from '../auth/auth.module';
import { PrismaModule } from '../prisma/prisma.module';
import { GLOBAL_CONFIG } from '../../configs/global.config';
import { AppService } from './app.service';
import { AppController } from './app.controller';
import { ClerkModule } from '../clerk/clerk.module';
+import { WebhookModule } from '../webhook/webhook.module';
@Module({
imports: [
PrismaModule,
- AuthModule,
+ //AuthModule,
UserModule,
PostModule,
+ WebhookModule,
ConfigModule.forRoot({ isGlobal: true, load: [() => GLOBAL_CONFIG] }),
ClerkModule.forRootAsync({
imports: [ConfigModule],
diff --git a/server/src/modules/auth/auth.dto.ts b/server/src/modules/auth/auth.dto.ts
index b9d9ebd..1645126 100644
--- a/server/src/modules/auth/auth.dto.ts
+++ b/server/src/modules/auth/auth.dto.ts
@@ -1,11 +1,18 @@
-import { User } from '@prisma/client';
+//import { User } from '@prisma/client';
import { IsEmail, IsNotEmpty, IsString } from 'class-validator';
import { ApiProperty } from '@nestjs/swagger';
import { INVALID_EMAIL } from '../../shared/constants/strings';
+export class UserResponseDTO {
+ id: string;
+ username: string;
+ email: string;
+ password?: string;
+}
+
export class AuthResponseDTO {
- user: User;
+ user: UserResponseDTO;
accessToken: string;
}
@@ -16,7 +23,7 @@ export class RegisterUserDTO {
@IsString()
@ApiProperty()
- name: string;
+ username: string;
@IsString()
@ApiProperty()
diff --git a/server/src/modules/auth/auth.module.ts b/server/src/modules/auth/auth.module.ts
index d890579..9d067f0 100644
--- a/server/src/modules/auth/auth.module.ts
+++ b/server/src/modules/auth/auth.module.ts
@@ -1,3 +1,4 @@
+//auth.module.ts
import { Module } from '@nestjs/common';
import { JwtModule } from '@nestjs/jwt';
diff --git a/server/src/modules/auth/auth.service.ts b/server/src/modules/auth/auth.service.ts
index 77acf3a..1993349 100644
--- a/server/src/modules/auth/auth.service.ts
+++ b/server/src/modules/auth/auth.service.ts
@@ -6,7 +6,7 @@ import { UserService } from '../user/user.service';
import { PrismaService } from '../prisma/prisma.service';
import { AuthHelpers } from '../../shared/helpers/auth.helpers';
import { GLOBAL_CONFIG } from '../../configs/global.config';
-
+import { ROLES_ENUM } from '../../shared/constants/global.constants';
import { AuthResponseDTO, LoginUserDTO, RegisterUserDTO } from './auth.dto';
@Injectable()
@@ -37,7 +37,7 @@ export class AuthService {
const payload = {
id: userData.id,
- name: userData.name,
+ username: userData.username,
email: userData.email,
password: null,
// role: userData.role,
@@ -53,6 +53,10 @@ export class AuthService {
};
}
public async register(user: RegisterUserDTO): Promise {
- return this.userService.createUser(user);
+ const newUser = {
+ ...user,
+ role: ROLES_ENUM.USER,
+ };
+ return this.userService.createUser(newUser);
}
}
diff --git a/server/src/modules/post/post.controller.ts b/server/src/modules/post/post.controller.ts
index 5abd0a4..4dea197 100644
--- a/server/src/modules/post/post.controller.ts
+++ b/server/src/modules/post/post.controller.ts
@@ -1,18 +1,18 @@
import {
- Body,
+ //Body,
Controller,
- Delete,
+ //Delete,
Get,
- Param,
- Post,
- Put,
+ //Param,
+ //Post,
+ //Put,
} from '@nestjs/common';
import { Post as PostModel } from '@prisma/client';
-import { ApiTags, ApiBody } from '@nestjs/swagger';
-import { UseGuards } from '@nestjs/common';
-import { AuthGuard } from '@nestjs/passport';
+import { ApiTags /*, ApiBody*/ } from '@nestjs/swagger';
+//import { UseGuards } from '@nestjs/common';
+//import { AuthGuard } from '@nestjs/passport';
import { PostService } from './post.service';
-import { CreatePostDTO } from './post.dto';
+//import { CreatePostDTO } from './post.dto';
@ApiTags('posts')
@Controller('/posts')
export class PostController {
@@ -23,15 +23,15 @@ export class PostController {
return this.postService.findAll({});
}
- @Get('post/:id')
+ /*@Get('post/:id')
async getPostById(@Param('id') id: string): Promise {
- return this.postService.findOne({ id: Number(id) });
+ return this.postService.findOne({ id: id });
}
@Get('feed')
async getPublishedPosts(): Promise {
return this.postService.findAll({
- where: { published: true },
+ where: { isVisible: true },
});
}
@@ -80,5 +80,5 @@ export class PostController {
@Delete('post/:id')
async deletePost(@Param('id') id: string): Promise {
return this.postService.delete({ id: Number(id) });
- }
+ }*/
}
diff --git a/server/src/modules/user/user.controller.ts b/server/src/modules/user/user.controller.ts
index 8484762..f948273 100644
--- a/server/src/modules/user/user.controller.ts
+++ b/server/src/modules/user/user.controller.ts
@@ -19,7 +19,7 @@ export class UserController {
@Post('user')
async signupUser(
- @Body() userData: { name?: string; email: string; password: string },
+ @Body() userData: { username: string; email: string; password: string },
): Promise {
return this.userService.createUser(userData);
}
diff --git a/server/src/modules/webhook/svix.middleware.ts b/server/src/modules/webhook/svix.middleware.ts
new file mode 100644
index 0000000..286181a
--- /dev/null
+++ b/server/src/modules/webhook/svix.middleware.ts
@@ -0,0 +1,39 @@
+// svix.middleware.ts
+import { Injectable, NestMiddleware, RawBodyRequest } from '@nestjs/common';
+import { Request, Response, NextFunction } from 'express';
+import { Webhook, WebhookVerificationError } from 'svix';
+
+@Injectable()
+export class SvixMiddleware implements NestMiddleware {
+ use(req: RawBodyRequest, res: Response, next: NextFunction) {
+ const wh = new Webhook(process.env.SVIX_WEBHOOK_SECRET);
+ try {
+ const payload = req.rawBody.toString();
+ console.log(payload);
+ const signature = Array.isArray(req.headers['svix-signature'])
+ ? req.headers['svix-signature'][0]
+ : req.headers['svix-signature'];
+ const timestamp = Array.isArray(req.headers['svix-timestamp'])
+ ? req.headers['svix-timestamp'][0]
+ : req.headers['svix-timestamp'];
+ const id = Array.isArray(req.headers['svix-id'])
+ ? req.headers['svix-id'][0]
+ : req.headers['svix-id'];
+ console.log(signature, timestamp, id);
+ const msg = wh.verify(payload, {
+ 'svix-signature': signature,
+ 'svix-timestamp': timestamp,
+ 'svix-id': id,
+ });
+ req.body = msg;
+ next();
+ } catch (err) {
+ if (err instanceof WebhookVerificationError) {
+ console.error(err);
+ res.status(403).send();
+ } else {
+ throw err;
+ }
+ }
+ }
+}
diff --git a/server/src/modules/webhook/webhook.controller.ts b/server/src/modules/webhook/webhook.controller.ts
new file mode 100644
index 0000000..450d2c6
--- /dev/null
+++ b/server/src/modules/webhook/webhook.controller.ts
@@ -0,0 +1,34 @@
+import {
+ Controller,
+ Post,
+ Get,
+ HttpCode,
+ Req,
+ RawBodyRequest,
+} from '@nestjs/common';
+import { WebhookService } from './webhook.service';
+import { Request } from 'express';
+
+@Controller('webhook')
+export class WebhookController {
+ constructor(private readonly webhookService: WebhookService) {}
+
+ @Get()
+ checkLive() {
+ console.log('Webhook is live');
+ return { success: true, message: 'Webhook is live' };
+ }
+
+ @Post()
+ @HttpCode(200)
+ async handleWebhook(@Req() req: RawBodyRequest) {
+ const rawBody = req.rawBody;
+
+ try {
+ await this.webhookService.handleWebhook(rawBody);
+ return { success: true, message: 'Webhook received' };
+ } catch (err) {
+ return { success: false, message: err.message };
+ }
+ }
+}
diff --git a/server/src/modules/webhook/webhook.dto.ts b/server/src/modules/webhook/webhook.dto.ts
new file mode 100644
index 0000000..7c9d66e
--- /dev/null
+++ b/server/src/modules/webhook/webhook.dto.ts
@@ -0,0 +1,13 @@
+// webhook.dto.ts
+import { IsString, IsObject } from 'class-validator';
+
+export class WebhookDto {
+ @IsString()
+ id: string;
+
+ @IsObject()
+ attributes: any;
+
+ @IsString()
+ type: string;
+}
diff --git a/server/src/modules/webhook/webhook.module.ts b/server/src/modules/webhook/webhook.module.ts
new file mode 100644
index 0000000..0f623f0
--- /dev/null
+++ b/server/src/modules/webhook/webhook.module.ts
@@ -0,0 +1,24 @@
+// webhook.module.ts
+import {
+ Module,
+ NestModule,
+ MiddlewareConsumer,
+ RequestMethod,
+} from '@nestjs/common';
+import { WebhookController } from './webhook.controller';
+import { WebhookService } from './webhook.service';
+import { UserModule } from '../user/user.module';
+import { SvixMiddleware } from './svix.middleware';
+
+@Module({
+ imports: [UserModule],
+ controllers: [WebhookController],
+ providers: [WebhookService],
+})
+export class WebhookModule implements NestModule {
+ configure(consumer: MiddlewareConsumer) {
+ consumer
+ .apply(SvixMiddleware)
+ .forRoutes({ path: 'webhook', method: RequestMethod.POST });
+ }
+}
diff --git a/server/src/modules/webhook/webhook.service.ts b/server/src/modules/webhook/webhook.service.ts
new file mode 100644
index 0000000..c44816f
--- /dev/null
+++ b/server/src/modules/webhook/webhook.service.ts
@@ -0,0 +1,28 @@
+// webhook.service.ts
+
+import { Injectable } from '@nestjs/common';
+import { UserService } from '../user/user.service';
+
+@Injectable()
+export class WebhookService {
+ constructor(private readonly userService: UserService) {}
+
+ async handleWebhook(message) {
+ const { id, type, data } = message;
+ console.log(data);
+ if (type === 'user.created') {
+ console.log(`User ${id} was ${type}`);
+ // const firstName = data.first_name;
+ // const lastName = data.last_name;
+
+ await this.userService.createUser({
+ id: id,
+ username: 'x',
+ password: 'xx',
+ email: 'xxx',
+ });
+
+ console.log('User saved to database');
+ }
+ }
+}