From e1a521778b3694d8676ce4c6e209277dce9bae83 Mon Sep 17 00:00:00 2001 From: Nate Barbettini Date: Tue, 18 Mar 2025 17:19:51 -0700 Subject: [PATCH 1/4] Add coming soon tools with tiny signup form --- .vscode/settings.json | 2 +- package.json | 1 + pnpm-lock.yaml | 396 +++++++++++++ .../custom/Toolkits/ComingSoonContext.tsx | 26 + .../custom/Toolkits/ComingSoonModal.tsx | 157 +++++ src/components/custom/Toolkits/ToolCard.tsx | 161 +++++- src/components/custom/Toolkits/Toolkits.tsx | 196 ++++--- .../custom/Toolkits/toolkits-config.ts | 547 +++++++++++++++++- 8 files changed, 1364 insertions(+), 122 deletions(-) create mode 100644 src/components/custom/Toolkits/ComingSoonContext.tsx create mode 100644 src/components/custom/Toolkits/ComingSoonModal.tsx diff --git a/.vscode/settings.json b/.vscode/settings.json index 2115f93a6..9f78396be 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,5 +1,5 @@ { - "cSpell.words": ["httpx", "nextra", "toolkits"], + "cSpell.words": ["httpx", "nextra", "posthog", "toolkits"], "editor.wordWrap": "bounded", "editor.wordWrapColumn": 120, "editor.formatOnSave": false, diff --git a/package.json b/package.json index 8cddad0b4..782957fe2 100644 --- a/package.json +++ b/package.json @@ -27,6 +27,7 @@ "homepage": "https://arcade.dev/", "dependencies": { "@icons-pack/react-simple-icons": "^10.2.0", + "@radix-ui/react-dialog": "^1.1.6", "@radix-ui/react-slot": "^1.1.1", "@uidotdev/usehooks": "^2.4.1", "class-variance-authority": "^0.7.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d75b01520..bf612f205 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -19,6 +19,9 @@ importers: '@icons-pack/react-simple-icons': specifier: ^10.2.0 version: 10.2.0(react@19.0.0) + '@radix-ui/react-dialog': + specifier: ^1.1.6 + version: 1.1.6(@types/react-dom@19.0.3(@types/react@19.0.7))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) '@radix-ui/react-slot': specifier: ^1.1.1 version: 1.1.1(@types/react@19.0.7)(react@19.0.0) @@ -818,6 +821,9 @@ packages: resolution: {integrity: sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==} engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} + '@radix-ui/primitive@1.1.1': + resolution: {integrity: sha512-SJ31y+Q/zAyShtXJc8x83i9TYdbAfHZ++tUZnvjJJqFjzsdUnKsxPL6IEtBlxKkU7yzer//GQtZSV4GbldL3YA==} + '@radix-ui/react-compose-refs@1.1.1': resolution: {integrity: sha512-Y9VzoRDSJtgFMUCoiZBDVo084VQ5hfpXxVE+NgkdNsjiDBByiImMZKKhxMwCbdHvhlENG6a833CbFkOQvTricw==} peerDependencies: @@ -827,6 +833,111 @@ packages: '@types/react': optional: true + '@radix-ui/react-context@1.1.1': + resolution: {integrity: sha512-UASk9zi+crv9WteK/NU4PLvOoL3OuE6BWVKNF6hPRBtYBDXQ2u5iu3O59zUlJiTVvkyuycnqrztsHVJwcK9K+Q==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-dialog@1.1.6': + resolution: {integrity: sha512-/IVhJV5AceX620DUJ4uYVMymzsipdKBzo3edo+omeskCKGm9FRHM0ebIdbPnlQVJqyuHbuBltQUOG2mOTq2IYw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-dismissable-layer@1.1.5': + resolution: {integrity: sha512-E4TywXY6UsXNRhFrECa5HAvE5/4BFcGyfTyK36gP+pAW1ed7UTK4vKwdr53gAJYwqbfCWC6ATvJa3J3R/9+Qrg==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-focus-guards@1.1.1': + resolution: {integrity: sha512-pSIwfrT1a6sIoDASCSpFwOasEwKTZWDw/iBdtnqKO7v6FeOzYJ7U53cPzYFVR3geGGXgVHaH+CdngrrAzqUGxg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-focus-scope@1.1.2': + resolution: {integrity: sha512-zxwE80FCU7lcXUGWkdt6XpTTCKPitG1XKOwViTxHVKIJhZl9MvIl2dVHeZENCWD9+EdWv05wlaEkRXUykU27RA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-id@1.1.0': + resolution: {integrity: sha512-EJUrI8yYh7WOjNOqpoJaf1jlFIH2LvtgAl+YcFqNCa+4hj64ZXmPkAKOFs/ukjz3byN6bdb/AVUqHkI8/uWWMA==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-portal@1.1.4': + resolution: {integrity: sha512-sn2O9k1rPFYVyKd5LAJfo96JlSGVFpa1fS6UuBJfrZadudiw5tAmru+n1x7aMRQ84qDM71Zh1+SzK5QwU0tJfA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-presence@1.1.2': + resolution: {integrity: sha512-18TFr80t5EVgL9x1SwF/YGtfG+l0BS0PRAlCWBDoBEiDQjeKgnNZRVJp/oVBl24sr3Gbfwc/Qpj4OcWTQMsAEg==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-primitive@2.0.2': + resolution: {integrity: sha512-Ec/0d38EIuvDF+GZjcMU/Ze6MxntVJYO/fRlCPhCaVUyPY9WTalHJw54tp9sXeJo3tlShWpy41vQRgLRGOuz+w==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + '@radix-ui/react-slot@1.1.1': resolution: {integrity: sha512-RApLLOcINYJA+dMVbOju7MYv1Mb2EBp2nH4HdDzXTSyaR5optlm6Otrz1euW3HbdOR8UmmFK06TD+A9frYWv+g==} peerDependencies: @@ -836,6 +947,51 @@ packages: '@types/react': optional: true + '@radix-ui/react-slot@1.1.2': + resolution: {integrity: sha512-YAKxaiGsSQJ38VzKH86/BPRC4rh+b1Jpa+JneA5LRE7skmLPNAyeG8kPJj/oo4STLvlrs8vkf/iYyc3A5stYCQ==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-callback-ref@1.1.0': + resolution: {integrity: sha512-CasTfvsy+frcFkbXtSJ2Zu9JHpN8TYKxkgJGWbjiZhFivxaeW7rMeZt7QELGVLaYVfFMsKHjb7Ak0nMEe+2Vfw==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-controllable-state@1.1.0': + resolution: {integrity: sha512-MtfMVJiSr2NjzS0Aa90NPTnvTSg6C/JLCV7ma0W6+OMV78vd8OyRpID+Ng9LxzsPbLeuBnWBA1Nq30AtBIDChw==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-escape-keydown@1.1.0': + resolution: {integrity: sha512-L7vwWlR1kTTQ3oh7g1O0CBF3YCyyTj8NmhLR+phShpyA50HCfBFKVJTpshm9PzLiKmehsrQzTYTpX9HvmC9rhw==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-layout-effect@1.1.0': + resolution: {integrity: sha512-+FPE0rOdziWSrH9athwI1R0HDVbWlEhd+FR+aSDk4uWGmSJ9Z54sdZVDQPZAinJhJXwfT+qnj969mCsT2gfm5w==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@react-aria/focus@3.19.1': resolution: {integrity: sha512-bix9Bu1Ue7RPcYmjwcjhB14BMu2qzfJ3tMQLqDc9pweJA66nOw8DThy3IfVr8Z7j2PHktOLf9kcbiZpydKHqzg==} peerDependencies: @@ -1306,6 +1462,10 @@ packages: argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + aria-hidden@1.2.4: + resolution: {integrity: sha512-y+CcFFwelSXpLZk/7fMB2mUbGtX9lKycf1MWJ7CaTIERyitVlyQx6C+sxcROU2BAJ24OiZyK+8wj2i8AlBoS3A==} + engines: {node: '>=10'} + aria-query@5.3.2: resolution: {integrity: sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==} engines: {node: '>= 0.4'} @@ -1879,6 +2039,9 @@ packages: resolution: {integrity: sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==} engines: {node: '>=8'} + detect-node-es@1.1.0: + resolution: {integrity: sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==} + devlop@1.1.0: resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==} @@ -2338,6 +2501,10 @@ packages: resolution: {integrity: sha512-VW6Pxhsrk0KAOqs3WEd0klDiF/+V7gQOpAvY1jVU/LHmaD/kQO4523aiJuikX/QAKYiW6x8Jh+RJej1almdtCA==} engines: {node: '>= 0.4'} + get-nonce@1.0.1: + resolution: {integrity: sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==} + engines: {node: '>=6'} + get-proto@1.0.1: resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} engines: {node: '>= 0.4'} @@ -3706,6 +3873,36 @@ packages: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-remove-scroll-bar@2.3.8: + resolution: {integrity: sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + + react-remove-scroll@2.6.3: + resolution: {integrity: sha512-pnAi91oOk8g8ABQKGF5/M9qxmmOPxaAnopyTHYfqYEwJhyFrbbBtHuSgtKEoH0jpcxx5o3hXqH1mNd9/Oi+8iQ==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + react-style-singleton@2.2.3: + resolution: {integrity: sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + react-syntax-highlighter@15.6.1: resolution: {integrity: sha512-OqJ2/vL7lEeV5zTJyG7kmARppUjiB9h9udl4qHQjjgEos66z00Ia0OckwYfRxCSFrW8RJIBnsBwQsHZbVPspqg==} peerDependencies: @@ -4425,6 +4622,26 @@ packages: uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + use-callback-ref@1.3.3: + resolution: {integrity: sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + use-sidecar@1.1.3: + resolution: {integrity: sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} @@ -5201,12 +5418,108 @@ snapshots: '@pkgr/core@0.1.1': {} + '@radix-ui/primitive@1.1.1': {} + '@radix-ui/react-compose-refs@1.1.1(@types/react@19.0.7)(react@19.0.0)': dependencies: react: 19.0.0 optionalDependencies: '@types/react': 19.0.7 + '@radix-ui/react-context@1.1.1(@types/react@19.0.7)(react@19.0.0)': + dependencies: + react: 19.0.0 + optionalDependencies: + '@types/react': 19.0.7 + + '@radix-ui/react-dialog@1.1.6(@types/react-dom@19.0.3(@types/react@19.0.7))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + dependencies: + '@radix-ui/primitive': 1.1.1 + '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.0.7)(react@19.0.0) + '@radix-ui/react-context': 1.1.1(@types/react@19.0.7)(react@19.0.0) + '@radix-ui/react-dismissable-layer': 1.1.5(@types/react-dom@19.0.3(@types/react@19.0.7))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-focus-guards': 1.1.1(@types/react@19.0.7)(react@19.0.0) + '@radix-ui/react-focus-scope': 1.1.2(@types/react-dom@19.0.3(@types/react@19.0.7))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-id': 1.1.0(@types/react@19.0.7)(react@19.0.0) + '@radix-ui/react-portal': 1.1.4(@types/react-dom@19.0.3(@types/react@19.0.7))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-presence': 1.1.2(@types/react-dom@19.0.3(@types/react@19.0.7))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-primitive': 2.0.2(@types/react-dom@19.0.3(@types/react@19.0.7))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-slot': 1.1.2(@types/react@19.0.7)(react@19.0.0) + '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@19.0.7)(react@19.0.0) + aria-hidden: 1.2.4 + react: 19.0.0 + react-dom: 19.0.0(react@19.0.0) + react-remove-scroll: 2.6.3(@types/react@19.0.7)(react@19.0.0) + optionalDependencies: + '@types/react': 19.0.7 + '@types/react-dom': 19.0.3(@types/react@19.0.7) + + '@radix-ui/react-dismissable-layer@1.1.5(@types/react-dom@19.0.3(@types/react@19.0.7))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + dependencies: + '@radix-ui/primitive': 1.1.1 + '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.0.7)(react@19.0.0) + '@radix-ui/react-primitive': 2.0.2(@types/react-dom@19.0.3(@types/react@19.0.7))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@19.0.7)(react@19.0.0) + '@radix-ui/react-use-escape-keydown': 1.1.0(@types/react@19.0.7)(react@19.0.0) + react: 19.0.0 + react-dom: 19.0.0(react@19.0.0) + optionalDependencies: + '@types/react': 19.0.7 + '@types/react-dom': 19.0.3(@types/react@19.0.7) + + '@radix-ui/react-focus-guards@1.1.1(@types/react@19.0.7)(react@19.0.0)': + dependencies: + react: 19.0.0 + optionalDependencies: + '@types/react': 19.0.7 + + '@radix-ui/react-focus-scope@1.1.2(@types/react-dom@19.0.3(@types/react@19.0.7))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.0.7)(react@19.0.0) + '@radix-ui/react-primitive': 2.0.2(@types/react-dom@19.0.3(@types/react@19.0.7))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@19.0.7)(react@19.0.0) + react: 19.0.0 + react-dom: 19.0.0(react@19.0.0) + optionalDependencies: + '@types/react': 19.0.7 + '@types/react-dom': 19.0.3(@types/react@19.0.7) + + '@radix-ui/react-id@1.1.0(@types/react@19.0.7)(react@19.0.0)': + dependencies: + '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@19.0.7)(react@19.0.0) + react: 19.0.0 + optionalDependencies: + '@types/react': 19.0.7 + + '@radix-ui/react-portal@1.1.4(@types/react-dom@19.0.3(@types/react@19.0.7))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + dependencies: + '@radix-ui/react-primitive': 2.0.2(@types/react-dom@19.0.3(@types/react@19.0.7))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@19.0.7)(react@19.0.0) + react: 19.0.0 + react-dom: 19.0.0(react@19.0.0) + optionalDependencies: + '@types/react': 19.0.7 + '@types/react-dom': 19.0.3(@types/react@19.0.7) + + '@radix-ui/react-presence@1.1.2(@types/react-dom@19.0.3(@types/react@19.0.7))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.0.7)(react@19.0.0) + '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@19.0.7)(react@19.0.0) + react: 19.0.0 + react-dom: 19.0.0(react@19.0.0) + optionalDependencies: + '@types/react': 19.0.7 + '@types/react-dom': 19.0.3(@types/react@19.0.7) + + '@radix-ui/react-primitive@2.0.2(@types/react-dom@19.0.3(@types/react@19.0.7))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + dependencies: + '@radix-ui/react-slot': 1.1.2(@types/react@19.0.7)(react@19.0.0) + react: 19.0.0 + react-dom: 19.0.0(react@19.0.0) + optionalDependencies: + '@types/react': 19.0.7 + '@types/react-dom': 19.0.3(@types/react@19.0.7) + '@radix-ui/react-slot@1.1.1(@types/react@19.0.7)(react@19.0.0)': dependencies: '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.0.7)(react@19.0.0) @@ -5214,6 +5527,39 @@ snapshots: optionalDependencies: '@types/react': 19.0.7 + '@radix-ui/react-slot@1.1.2(@types/react@19.0.7)(react@19.0.0)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.0.7)(react@19.0.0) + react: 19.0.0 + optionalDependencies: + '@types/react': 19.0.7 + + '@radix-ui/react-use-callback-ref@1.1.0(@types/react@19.0.7)(react@19.0.0)': + dependencies: + react: 19.0.0 + optionalDependencies: + '@types/react': 19.0.7 + + '@radix-ui/react-use-controllable-state@1.1.0(@types/react@19.0.7)(react@19.0.0)': + dependencies: + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@19.0.7)(react@19.0.0) + react: 19.0.0 + optionalDependencies: + '@types/react': 19.0.7 + + '@radix-ui/react-use-escape-keydown@1.1.0(@types/react@19.0.7)(react@19.0.0)': + dependencies: + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@19.0.7)(react@19.0.0) + react: 19.0.0 + optionalDependencies: + '@types/react': 19.0.7 + + '@radix-ui/react-use-layout-effect@1.1.0(@types/react@19.0.7)(react@19.0.0)': + dependencies: + react: 19.0.0 + optionalDependencies: + '@types/react': 19.0.7 + '@react-aria/focus@3.19.1(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': dependencies: '@react-aria/interactions': 3.23.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0) @@ -5849,6 +6195,10 @@ snapshots: argparse@2.0.1: {} + aria-hidden@1.2.4: + dependencies: + tslib: 2.8.1 + aria-query@5.3.2: {} array-buffer-byte-length@1.0.2: @@ -6436,6 +6786,8 @@ snapshots: detect-libc@2.0.3: {} + detect-node-es@1.1.0: {} + devlop@1.1.0: dependencies: dequal: 2.0.3 @@ -7084,6 +7436,8 @@ snapshots: hasown: 2.0.2 math-intrinsics: 1.1.0 + get-nonce@1.0.1: {} + get-proto@1.0.1: dependencies: dunder-proto: 1.0.1 @@ -8844,6 +9198,33 @@ snapshots: react: 19.0.0 react-dom: 19.0.0(react@19.0.0) + react-remove-scroll-bar@2.3.8(@types/react@19.0.7)(react@19.0.0): + dependencies: + react: 19.0.0 + react-style-singleton: 2.2.3(@types/react@19.0.7)(react@19.0.0) + tslib: 2.8.1 + optionalDependencies: + '@types/react': 19.0.7 + + react-remove-scroll@2.6.3(@types/react@19.0.7)(react@19.0.0): + dependencies: + react: 19.0.0 + react-remove-scroll-bar: 2.3.8(@types/react@19.0.7)(react@19.0.0) + react-style-singleton: 2.2.3(@types/react@19.0.7)(react@19.0.0) + tslib: 2.8.1 + use-callback-ref: 1.3.3(@types/react@19.0.7)(react@19.0.0) + use-sidecar: 1.1.3(@types/react@19.0.7)(react@19.0.0) + optionalDependencies: + '@types/react': 19.0.7 + + react-style-singleton@2.2.3(@types/react@19.0.7)(react@19.0.0): + dependencies: + get-nonce: 1.0.1 + react: 19.0.0 + tslib: 2.8.1 + optionalDependencies: + '@types/react': 19.0.7 + react-syntax-highlighter@15.6.1(react@19.0.0): dependencies: '@babel/runtime': 7.26.0 @@ -9832,6 +10213,21 @@ snapshots: dependencies: punycode: 2.3.1 + use-callback-ref@1.3.3(@types/react@19.0.7)(react@19.0.0): + dependencies: + react: 19.0.0 + tslib: 2.8.1 + optionalDependencies: + '@types/react': 19.0.7 + + use-sidecar@1.1.3(@types/react@19.0.7)(react@19.0.0): + dependencies: + detect-node-es: 1.1.0 + react: 19.0.0 + tslib: 2.8.1 + optionalDependencies: + '@types/react': 19.0.7 + util-deprecate@1.0.2: {} uuid@3.3.2: {} diff --git a/src/components/custom/Toolkits/ComingSoonContext.tsx b/src/components/custom/Toolkits/ComingSoonContext.tsx new file mode 100644 index 000000000..e850772cd --- /dev/null +++ b/src/components/custom/Toolkits/ComingSoonContext.tsx @@ -0,0 +1,26 @@ +import React, { createContext, useContext, useState } from "react"; + +interface ComingSoonContextType { + email: string; + // eslint-disable-next-line no-unused-vars + setEmail: (email: string) => void; +} + +const ComingSoonContext = createContext({ + email: "", + setEmail: () => {}, +}); + +export const ComingSoonProvider: React.FC<{ children: React.ReactNode }> = ({ + children, +}) => { + const [email, setEmail] = useState(""); + + return ( + + {children} + + ); +}; + +export const useComingSoon = () => useContext(ComingSoonContext); diff --git a/src/components/custom/Toolkits/ComingSoonModal.tsx b/src/components/custom/Toolkits/ComingSoonModal.tsx new file mode 100644 index 000000000..a648f9bdf --- /dev/null +++ b/src/components/custom/Toolkits/ComingSoonModal.tsx @@ -0,0 +1,157 @@ +import React, { useState, useEffect } from "react"; +import * as Dialog from "@radix-ui/react-dialog"; +import { Button } from "@/components/ui/button"; +import { Input } from "@/components/ui/input"; +import { X } from "lucide-react"; +import { usePostHog } from "posthog-js/react"; +import { useComingSoon } from "./ComingSoonContext"; + +interface ComingSoonModalProps { + isOpen: boolean; + onClose: () => void; + toolkitName: string; +} + +export function ComingSoonModal({ + isOpen, + onClose, + toolkitName, +}: ComingSoonModalProps) { + const { email, setEmail } = useComingSoon(); + const [isSubmitting, setIsSubmitting] = useState(false); + const [isSubmitted, setIsSubmitted] = useState(false); + const [error, setError] = useState(""); + + // Reset form state when modal opens/closes + useEffect(() => { + if (!isOpen) { + setIsSubmitted(false); + setError(""); + } + }, [isOpen]); + + const posthog = usePostHog(); + + const trackNotifyMeClick = (toolkitName: string, email: string) => { + posthog?.capture("Notify me clicked", { + toolkit_name: toolkitName, + notify_email: email, + }); + }; + + const handleSubmit = async (e: React.FormEvent) => { + e.preventDefault(); + + if (!email || !email.includes("@")) { + setError("Please enter a valid email address"); + return; + } + + setIsSubmitting(true); + setError(""); + + try { + trackNotifyMeClick(toolkitName, email); + console.log("Notify me clicked", { + toolkit_name: toolkitName, + notify_email: email, + }); + setIsSubmitted(true); + } catch { + setError("Failed to submit. Please try again."); + } finally { + setIsSubmitting(false); + } + }; + + // Ensure we always call onClose when dialog state changes + const handleOpenChange = (open: boolean) => { + if (!open) { + onClose(); + } + }; + + return ( + + + + + + {toolkitName} is coming soon + + {!isSubmitted && ( + + This toolkit is coming to Arcade soon. Sign up to be notified when + it's available. + + )} + + {!isSubmitted ? ( +
+
+ setEmail(e.target.value)} + className="w-full bg-gray-800/50 text-white" + required + /> + {error &&

{error}

} +
+ +
+ +
+
+ ) : ( +
+
+ + + +
+

+ Thanks for your interest! +

+

+ We'll notify you when the {toolkitName} toolkit becomes + available. +

+ +
+ )} + + + + +
+
+
+ ); +} diff --git a/src/components/custom/Toolkits/ToolCard.tsx b/src/components/custom/Toolkits/ToolCard.tsx index f790cece3..ee3f3e8a5 100644 --- a/src/components/custom/Toolkits/ToolCard.tsx +++ b/src/components/custom/Toolkits/ToolCard.tsx @@ -1,9 +1,16 @@ -import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; +import { + Card, + CardContent as CardContentUI, + CardHeader, + CardTitle, +} from "@/components/ui/card"; +import { Badge } from "@/components/ui/badge"; import { cn } from "@/lib/utils"; import { BadgeCheck, CheckCircle, Key, Users } from "lucide-react"; import Image from "next/image"; import Link from "next/link"; -import React from "react"; +import React, { useState } from "react"; +import { ComingSoonModal } from "./ComingSoonModal"; type ToolkitType = "arcade" | "verified" | "community" | "auth"; @@ -13,6 +20,7 @@ interface ToolCardProps { summary: string; link: string; type: ToolkitType; + isComingSoon?: boolean; } const typeConfig: Record< @@ -55,45 +63,140 @@ export const ToolCard: React.FC = ({ summary, link, type, + isComingSoon = false, }) => { + const [isModalOpen, setIsModalOpen] = useState(false); + const [imageError, setImageError] = useState(false); const { className, label, icon: Icon, color } = typeConfig[type]; - return ( - - - -
-
-
+ const handleCardClick = (e: React.MouseEvent) => { + if (isComingSoon) { + e.preventDefault(); + setIsModalOpen(true); + } + }; + + const handleModalClose = () => { + setIsModalOpen(false); + }; + + const handleImageError = () => { + setImageError(true); + }; + + // Generate a consistent color based on the tool name + const getColorFromName = (name: string) => { + // Predefined attractive colors (tailwind colors at 500-600 level) + const colors = [ + "bg-red-500", + "bg-orange-500", + "bg-amber-500", + "bg-yellow-500", + "bg-lime-500", + "bg-green-500", + "bg-emerald-500", + "bg-teal-500", + "bg-cyan-500", + "bg-sky-500", + "bg-blue-500", + "bg-indigo-500", + "bg-violet-500", + "bg-purple-500", + "bg-fuchsia-500", + "bg-pink-500", + "bg-rose-500", + ]; + + // Simple hash function to get a number from the name + let hash = 0; + for (let i = 0; i < name.length; i++) { + hash = (hash << 5) - hash + name.charCodeAt(i); + hash = hash & hash; // Convert to 32bit integer + } + + // Use absolute value to ensure positive index + const index = Math.abs(hash) % colors.length; + return colors[index]; + }; + + // Get the first two letters of the name + const firstTwoChars = name.substring(0, 2).toUpperCase(); + + // Get color based on the name + const bgColor = getColorFromName(name); + + const cardContent = ( + + +
+
+
+ {!image || imageError ? ( +
+ {firstTwoChars} +
+ ) : ( {`${name} -
-
- {name} -
- - {label} -
+ )} +
+
+ {name} +
+ + {label}
- - -
{summary}
-
- - + {isComingSoon && ( + + Coming Soon + + )} +
+
+ +
{summary}
+
+
+ ); + + return ( + <> + {isComingSoon ? ( +
+ {cardContent} +
+ ) : ( + {cardContent} + )} + + {isComingSoon && ( + + )} + ); }; diff --git a/src/components/custom/Toolkits/Toolkits.tsx b/src/components/custom/Toolkits/Toolkits.tsx index a3526b726..805cb5b81 100644 --- a/src/components/custom/Toolkits/Toolkits.tsx +++ b/src/components/custom/Toolkits/Toolkits.tsx @@ -6,6 +6,7 @@ import { cn } from "@/lib/utils"; import { useDebounce } from "@uidotdev/usehooks"; import { BadgeCheck, CheckCircle, Key, Search, Users, X } from "lucide-react"; import React, { useCallback, useMemo, useState } from "react"; +import { ComingSoonProvider } from "./ComingSoonContext"; export type ToolkitType = "arcade" | "verified" | "community" | "auth"; @@ -58,12 +59,21 @@ export default function Toolkits({ tools, categories }: ToolkitsProps) { .includes(debouncedSearchQuery.toLowerCase())), ); - // Sort alphabetically and prioritize Arcade toolkits + // Sort with multiple priorities: available first, then by type, then alphabetically return filtered.sort((a, b) => { - if (a.type === "arcade" && b.type !== "arcade") return -1; - if (b.type === "arcade" && a.type !== "arcade") return 1; - if (a.type === "verified" && b.type !== "verified") return -1; - if (b.type === "verified" && a.type !== "verified") return 1; + // First prioritize available tools over coming soon tools + if (a.isComingSoon && !b.isComingSoon) return 1; + if (!a.isComingSoon && b.isComingSoon) return -1; + + // Within each availability group, prioritize by type (arcade > verified > others) + if (!a.isComingSoon && !b.isComingSoon) { + if (a.type === "arcade" && b.type !== "arcade") return -1; + if (b.type === "arcade" && a.type !== "arcade") return 1; + if (a.type === "verified" && b.type !== "verified") return -1; + if (b.type === "verified" && a.type !== "verified") return 1; + } + + // Finally sort alphabetically within each group return a.name.localeCompare(b.name); }); }, [tools, selectedCategory, debouncedSearchQuery]); @@ -76,101 +86,105 @@ export default function Toolkits({ tools, categories }: ToolkitsProps) { ); return ( -
-
-
-

- Integrations -

-

- There are 4 designations for Arcade integrations: -

-
- {Object.entries(typeConfig).map( - ([key, { label, icon: Icon, color }]) => ( -
-
- -
-
-

- {label} -

-

- {key === "arcade" && - "Official integrations developed and maintained by Arcade."} - {key === "verified" && - "Community-created integrations, thoroughly tested and verified by Arcade."} - {key === "community" && - "Created and maintained by the Arcade community, offering a wide range of integrations."} - {key === "auth" && - "Auth integrations allow you to develop custom tools that connect your agent APIs and services."} -

+ +
+
+
+

+ Integrations +

+

+ There are 4 designations for Arcade integrations: +

+
+ {Object.entries(typeConfig).map( + ([key, { label, icon: Icon, color }]) => ( +
+
+ +
+
+

+ {label} +

+

+ {key === "arcade" && + "Official integrations developed and maintained by Arcade."} + {key === "verified" && + "Community-created integrations, thoroughly tested and verified by Arcade."} + {key === "community" && + "Created and maintained by the Arcade community, offering a wide range of integrations."} + {key === "auth" && + "Auth integrations allow you to develop custom tools that connect your agent APIs and services."} +

+
-
- ), - )} -
-
-
-
-
-
-
- - - {searchQuery && ( - + ), )}
-

- {filteredTools.length} result(s) found -

-
-
-
- {categories.map((category) => ( -
+
+
+
+
+ + + {searchQuery && ( + - ))} + + + )} +
+

+ {filteredTools.length} result(s) found +

+
+
+
+
+ {categories.map((category) => ( + + ))} +
+
+
+ {filteredTools.map((tool) => ( + + ))} +
+
-
-
- {filteredTools.map((tool) => ( - - ))} -
-
-
+ ); } diff --git a/src/components/custom/Toolkits/toolkits-config.ts b/src/components/custom/Toolkits/toolkits-config.ts index 991c22476..45227f546 100644 --- a/src/components/custom/Toolkits/toolkits-config.ts +++ b/src/components/custom/Toolkits/toolkits-config.ts @@ -6,6 +6,7 @@ export interface Tool { link: string; type: ToolkitType; category: string; + isComingSoon?: boolean; } export interface Category { @@ -22,7 +23,8 @@ export const categories: Category[] = [ { id: "search", name: "Search" }, ]; -export const tools: Tool[] = [ +// Available tools +const availableTools: Tool[] = [ { name: "Gmail", image: "gmail", @@ -287,3 +289,546 @@ export const tools: Tool[] = [ type: "auth", }, ]; + +// Coming soon tools +const comingSoonTools: Tool[] = [ + { + name: "ADP Workforce Now", + image: "adp", + summary: "Manage payroll, HR, and workforce data with your agents.", + link: "/toolkits/productivity/adp", + category: "productivity", + type: "arcade", + isComingSoon: true, + }, + { + name: "Aha", + image: "aha", + summary: "Manage product roadmaps and strategy with your agents.", + link: "/toolkits/productivity/aha", + category: "productivity", + type: "arcade", + isComingSoon: true, + }, + { + name: "Airtable", + image: "airtable", + summary: "Create, edit, and manage Airtable bases with your agents.", + link: "/toolkits/productivity/airtable", + category: "productivity", + type: "arcade", + isComingSoon: true, + }, + { + name: "Amplitude", + image: "amplitude", + summary: "Analyze user behavior and product analytics with your agents.", + link: "/toolkits/productivity/amplitude", + category: "productivity", + type: "arcade", + isComingSoon: true, + }, + { + name: "Asana", + image: "asana", + summary: "Manage projects, tasks, and more in Asana with your agents.", + link: "/toolkits/productivity/asana", + category: "productivity", + type: "arcade", + isComingSoon: true, + }, + { + name: "Ashby", + image: "ashby", + summary: "Manage recruiting and hiring processes with your agents.", + link: "/toolkits/productivity/ashby", + category: "productivity", + type: "arcade", + isComingSoon: true, + }, + { + name: "Auth0", + image: "auth0", + summary: "Manage authentication and authorization with your agents.", + link: "/toolkits/development/auth0", + category: "development", + type: "arcade", + isComingSoon: true, + }, + { + name: "BambooHR", + image: "bamboohr", + summary: "Manage employee data and HR processes with your agents.", + link: "/toolkits/productivity/bamboohr", + category: "productivity", + type: "arcade", + isComingSoon: true, + }, + { + name: "Basecamp", + image: "basecamp", + summary: "Manage projects, tasks, and team communication with your agents.", + link: "/toolkits/productivity/basecamp", + category: "productivity", + type: "arcade", + isComingSoon: true, + }, + { + name: "Bill.com", + image: "bill", + summary: "Manage invoices and payments with your agents.", + link: "/toolkits/productivity/bill", + category: "productivity", + type: "arcade", + isComingSoon: true, + }, + { + name: "Bitbucket", + image: "bitbucket", + summary: + "Manage repositories, pull requests, and pipelines with your agents.", + link: "/toolkits/development/bitbucket", + category: "development", + type: "arcade", + isComingSoon: true, + }, + { + name: "Box", + image: "box", + summary: "Manage files and folders in Box with your agents.", + link: "/toolkits/productivity/box", + category: "productivity", + type: "arcade", + isComingSoon: true, + }, + { + name: "Braze", + image: "braze", + summary: "Manage customer engagement campaigns with your agents.", + link: "/toolkits/productivity/braze", + category: "productivity", + type: "arcade", + isComingSoon: true, + }, + { + name: "Brex", + image: "brex", + summary: "Manage business expenses and cards with your agents.", + link: "/toolkits/productivity/brex", + category: "productivity", + type: "arcade", + isComingSoon: true, + }, + { + name: "Buffer", + image: "buffer", + summary: "Schedule and manage social media posts with your agents.", + link: "/toolkits/social-communication/buffer", + category: "social", + type: "arcade", + isComingSoon: true, + }, + { + name: "Calendly", + image: "calendly", + summary: "Manage scheduling and appointments with your agents.", + link: "/toolkits/productivity/calendly", + category: "productivity", + type: "arcade", + isComingSoon: true, + }, + { + name: "ClickUp", + image: "clickup", + summary: "Manage projects, tasks, and documents with your agents.", + link: "/toolkits/productivity/clickup", + category: "productivity", + type: "arcade", + isComingSoon: true, + }, + { + name: "Coinbase", + image: "coinbase", + summary: "Manage cryptocurrency transactions and wallets with your agents.", + link: "/toolkits/productivity/coinbase", + category: "productivity", + type: "arcade", + isComingSoon: true, + }, + { + name: "Datadog", + image: "datadog", + summary: "Monitor applications and infrastructure with your agents.", + link: "/toolkits/development/datadog", + category: "development", + type: "arcade", + isComingSoon: true, + }, + { + name: "DigitalOcean", + image: "digitalocean", + summary: "Manage cloud servers and infrastructure with your agents.", + link: "/toolkits/development/digitalocean", + category: "development", + type: "arcade", + isComingSoon: true, + }, + { + name: "Dropbox", + image: "dropbox", + summary: "Manage Dropbox files and folders with your agents", + link: "/toolkits/productivity/dropbox", + category: "productivity", + type: "auth", + isComingSoon: true, + }, + { + name: "eBay", + image: "ebay", + summary: "Manage listings, orders, and inventory on eBay with your agents.", + link: "/toolkits/productivity/ebay", + category: "productivity", + type: "arcade", + isComingSoon: true, + }, + { + name: "Evernote", + image: "evernote", + summary: "Create and manage notes with your agents.", + link: "/toolkits/productivity/evernote", + category: "productivity", + type: "arcade", + isComingSoon: true, + }, + { + name: "Factorial", + image: "factorial", + summary: "Manage HR processes and employee data with your agents.", + link: "/toolkits/productivity/factorial", + category: "productivity", + type: "arcade", + isComingSoon: true, + }, + { + name: "Figma", + image: "figma", + summary: "Access design files and collaborate on designs with your agents.", + link: "/toolkits/productivity/figma", + category: "productivity", + type: "arcade", + isComingSoon: true, + }, + { + name: "GitLab", + image: "gitlab", + summary: + "Manage repositories, issues, and merge requests with your agents.", + link: "/toolkits/development/gitlab", + category: "development", + type: "arcade", + isComingSoon: true, + }, + { + name: "Heroku", + image: "heroku", + summary: "Deploy and manage applications on Heroku with your agents.", + link: "/toolkits/development/heroku", + category: "development", + type: "arcade", + isComingSoon: true, + }, + { + name: "Hootsuite", + image: "hootsuite", + summary: "Manage and schedule social media content with your agents.", + link: "/toolkits/social-communication/hootsuite", + category: "social", + type: "arcade", + isComingSoon: true, + }, + { + name: "HubSpot", + image: "hubspot", + summary: + "Manage contacts, deals, and marketing campaigns in HubSpot with your agents.", + link: "/toolkits/productivity/hubspot", + category: "productivity", + type: "arcade", + isComingSoon: true, + }, + { + name: "Intercom", + image: "intercom", + summary: "Manage customer communications and support with your agents.", + link: "/toolkits/social-communication/intercom", + category: "social", + type: "arcade", + isComingSoon: true, + }, + { + name: "Linear", + image: "linear", + summary: "Manage issues and projects with your agents.", + link: "/toolkits/productivity/linear", + category: "productivity", + type: "arcade", + isComingSoon: true, + }, + { + name: "Mailchimp", + image: "mailchimp", + summary: "Manage email campaigns and subscribers with your agents.", + link: "/toolkits/productivity/mailchimp", + category: "productivity", + type: "arcade", + isComingSoon: true, + }, + { + name: "Microsoft Dynamics", + image: "msft_dynamics", + summary: "Manage CRM and ERP processes with your agents.", + link: "/toolkits/productivity/microsoft_dynamics", + category: "productivity", + type: "arcade", + isComingSoon: true, + }, + { + name: "Model Context Protocol (MCP)", + image: "mcp", + summary: "Manage context and improve AI interactions with your agents.", + link: "/toolkits/development/mcp", + category: "development", + type: "arcade", + isComingSoon: true, + }, + { + name: "Miro", + image: "miro", + summary: "Create and collaborate on visual boards with your agents.", + link: "/toolkits/productivity/miro", + category: "productivity", + type: "arcade", + isComingSoon: true, + }, + { + name: "Monday", + image: "monday", + summary: "Manage projects and workflows with your agents.", + link: "/toolkits/productivity/monday", + category: "productivity", + type: "arcade", + isComingSoon: true, + }, + { + name: "Netsuite", + image: "netsuite", + summary: "Manage financial and business operations with your agents.", + link: "/toolkits/productivity/netsuite", + category: "productivity", + type: "arcade", + isComingSoon: true, + }, + { + name: "Okta", + image: "okta", + summary: "Manage identity and access with your agents.", + link: "/toolkits/productivity/okta", + category: "productivity", + type: "arcade", + isComingSoon: true, + }, + { + name: "Pinecone", + image: "pinecone", + summary: "Manage vector databases and similarity search with your agents.", + link: "/toolkits/development/pinecone", + category: "development", + type: "arcade", + isComingSoon: true, + }, + { + name: "Pinterest", + image: "pinterest", + summary: "Create and manage pins and boards with your agents.", + link: "/toolkits/social-communication/pinterest", + category: "social", + type: "arcade", + isComingSoon: true, + }, + { + name: "Plaid", + image: "plaid", + summary: + "Connect with financial accounts and manage financial data with your agents.", + link: "/toolkits/productivity/plaid", + category: "productivity", + type: "arcade", + isComingSoon: true, + }, + { + name: "Pipedrive", + image: "pipedrive", + summary: "Manage sales pipelines and leads with your agents.", + link: "/toolkits/productivity/pipedrive", + category: "productivity", + type: "arcade", + isComingSoon: true, + }, + { + name: "QuickBooks", + image: "quickbooks", + summary: "Manage accounting and finances with your agents.", + link: "/toolkits/productivity/quickbooks", + category: "productivity", + type: "arcade", + isComingSoon: true, + }, + { + name: "Salesforce", + image: "salesforce", + summary: "Manage customer relationships and sales with your agents.", + link: "/toolkits/productivity/salesforce", + category: "productivity", + type: "arcade", + isComingSoon: true, + }, + { + name: "Shopify", + image: "shopify", + summary: "Manage e-commerce stores and products with your agents.", + link: "/toolkits/productivity/shopify", + category: "productivity", + type: "arcade", + isComingSoon: true, + }, + { + name: "SingleStore", + image: "singlestore", + summary: "Manage databases and data operations with your agents.", + link: "/toolkits/development/singlestore", + category: "development", + type: "arcade", + isComingSoon: true, + }, + { + name: "Snowflake", + image: "snowflake", + summary: "Manage data warehouses and analytics with your agents.", + link: "/toolkits/development/snowflake", + category: "development", + type: "arcade", + isComingSoon: true, + }, + { + name: "Splunk", + image: "splunk", + summary: "Monitor and analyze machine data with your agents.", + link: "/toolkits/development/splunk", + category: "development", + type: "arcade", + isComingSoon: true, + }, + { + name: "Square", + image: "square", + summary: + "Process payments and manage business operations with your agents.", + link: "/toolkits/productivity/square", + category: "productivity", + type: "arcade", + isComingSoon: true, + }, + { + name: "Squarespace", + image: "squarespace", + summary: "Manage websites and online presence with your agents.", + link: "/toolkits/productivity/squarespace", + category: "productivity", + type: "arcade", + isComingSoon: true, + }, + { + name: "Stripe", + image: "stripe", + summary: "Process payments and manage subscriptions with your agents.", + link: "/toolkits/productivity/stripe", + category: "productivity", + type: "arcade", + isComingSoon: true, + }, + { + name: "TikTok", + image: "tiktok", + summary: "Create and manage TikTok content with your agents.", + link: "/toolkits/social-communication/tiktok", + category: "social", + type: "arcade", + isComingSoon: true, + }, + { + name: "Trello", + image: "trello", + summary: "Manage boards, cards, and lists with your agents.", + link: "/toolkits/productivity/trello", + category: "productivity", + type: "arcade", + isComingSoon: true, + }, + { + name: "Vercel", + image: "vercel", + summary: "Deploy and manage web applications with your agents.", + link: "/toolkits/development/vercel", + category: "development", + type: "arcade", + isComingSoon: true, + }, + { + name: "Weaviate", + image: "weaviate", + summary: "Manage vector databases and semantic search with your agents.", + link: "/toolkits/development/weaviate", + category: "development", + type: "arcade", + isComingSoon: true, + }, + { + name: "Workday", + image: "workday", + summary: "Manage HR, finance, and planning with your agents.", + link: "/toolkits/productivity/workday", + category: "productivity", + type: "arcade", + isComingSoon: true, + }, + { + name: "Wrike", + image: "wrike", + summary: "Manage projects and collaborate with your agents.", + link: "/toolkits/productivity/wrike", + category: "productivity", + type: "arcade", + isComingSoon: true, + }, + { + name: "Xero", + image: "xero", + summary: "Manage accounting and finances with your agents.", + link: "/toolkits/productivity/xero", + category: "productivity", + type: "arcade", + isComingSoon: true, + }, + { + name: "Zendesk", + image: "zendesk", + summary: "Manage customer support and service with your agents.", + link: "/toolkits/productivity/zendesk", + category: "productivity", + type: "arcade", + isComingSoon: true, + }, +]; + +// Merge and export all tools +export const tools: Tool[] = [...comingSoonTools, ...availableTools]; From dbb8662cc2f792fb2841f019ca2668abb80168dd Mon Sep 17 00:00:00 2001 From: Nate Barbettini Date: Tue, 18 Mar 2025 17:52:49 -0700 Subject: [PATCH 2/4] Fix duplicated dropbox --- src/components/custom/Toolkits/toolkits-config.ts | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/components/custom/Toolkits/toolkits-config.ts b/src/components/custom/Toolkits/toolkits-config.ts index 45227f546..1775075e3 100644 --- a/src/components/custom/Toolkits/toolkits-config.ts +++ b/src/components/custom/Toolkits/toolkits-config.ts @@ -473,15 +473,6 @@ const comingSoonTools: Tool[] = [ type: "arcade", isComingSoon: true, }, - { - name: "Dropbox", - image: "dropbox", - summary: "Manage Dropbox files and folders with your agents", - link: "/toolkits/productivity/dropbox", - category: "productivity", - type: "auth", - isComingSoon: true, - }, { name: "eBay", image: "ebay", From 43ca0cc6a25b15872f46e728176d622d927b2c4a Mon Sep 17 00:00:00 2001 From: Nate Barbettini Date: Tue, 18 Mar 2025 18:09:22 -0700 Subject: [PATCH 3/4] Add Bluesky by popular demand --- src/components/custom/Toolkits/toolkits-config.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/components/custom/Toolkits/toolkits-config.ts b/src/components/custom/Toolkits/toolkits-config.ts index 1775075e3..24f33ae3e 100644 --- a/src/components/custom/Toolkits/toolkits-config.ts +++ b/src/components/custom/Toolkits/toolkits-config.ts @@ -392,6 +392,15 @@ const comingSoonTools: Tool[] = [ type: "arcade", isComingSoon: true, }, + { + name: "Bluesky", + image: "bluesky", + summary: "Interact with Bluesky with your agents.", + link: "/toolkits/social-communication/bluesky", + category: "social", + type: "arcade", + isComingSoon: true, + }, { name: "Box", image: "box", From 47961b6180c646a2009c89b8de08a48ec9f62c36 Mon Sep 17 00:00:00 2001 From: Sergio Serrano Date: Tue, 18 Mar 2025 23:20:24 -0300 Subject: [PATCH 4/4] Change to shadcn dialog --- .../custom/Toolkits/ComingSoonModal.tsx | 188 ++++++++---------- src/components/custom/Toolkits/ToolCard.tsx | 1 + src/components/ui/dialog.tsx | 120 +++++++++++ 3 files changed, 206 insertions(+), 103 deletions(-) create mode 100644 src/components/ui/dialog.tsx diff --git a/src/components/custom/Toolkits/ComingSoonModal.tsx b/src/components/custom/Toolkits/ComingSoonModal.tsx index a648f9bdf..c7497042d 100644 --- a/src/components/custom/Toolkits/ComingSoonModal.tsx +++ b/src/components/custom/Toolkits/ComingSoonModal.tsx @@ -1,8 +1,14 @@ -import React, { useState, useEffect } from "react"; -import * as Dialog from "@radix-ui/react-dialog"; +"use client"; +import React, { useState } from "react"; +import { + Dialog, + DialogContent, + DialogDescription, + DialogHeader, + DialogTitle, +} from "@/components/ui/dialog"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; -import { X } from "lucide-react"; import { usePostHog } from "posthog-js/react"; import { useComingSoon } from "./ComingSoonContext"; @@ -18,31 +24,14 @@ export function ComingSoonModal({ toolkitName, }: ComingSoonModalProps) { const { email, setEmail } = useComingSoon(); - const [isSubmitting, setIsSubmitting] = useState(false); const [isSubmitted, setIsSubmitted] = useState(false); + const [isSubmitting, setIsSubmitting] = useState(false); const [error, setError] = useState(""); - - // Reset form state when modal opens/closes - useEffect(() => { - if (!isOpen) { - setIsSubmitted(false); - setError(""); - } - }, [isOpen]); - const posthog = usePostHog(); - const trackNotifyMeClick = (toolkitName: string, email: string) => { - posthog?.capture("Notify me clicked", { - toolkit_name: toolkitName, - notify_email: email, - }); - }; - const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); - - if (!email || !email.includes("@")) { + if (!email?.includes("@")) { setError("Please enter a valid email address"); return; } @@ -51,8 +40,7 @@ export function ComingSoonModal({ setError(""); try { - trackNotifyMeClick(toolkitName, email); - console.log("Notify me clicked", { + posthog?.capture("Notify me clicked", { toolkit_name: toolkitName, notify_email: email, }); @@ -64,94 +52,88 @@ export function ComingSoonModal({ } }; - // Ensure we always call onClose when dialog state changes - const handleOpenChange = (open: boolean) => { - if (!open) { - onClose(); - } + const handleClose = () => { + setIsSubmitted(false); + setError(""); + onClose(); }; return ( - - - - - + !open && handleClose()}> + + + {toolkitName} is coming soon - + {!isSubmitted && ( - + This toolkit is coming to Arcade soon. Sign up to be notified when it's available. - + )} + - {!isSubmitted ? ( -
-
- setEmail(e.target.value)} - className="w-full bg-gray-800/50 text-white" - required - /> - {error &&

{error}

} -
- -
- -
-
- ) : ( -
-
- - - -
-

- Thanks for your interest! -

-

- We'll notify you when the {toolkitName} toolkit becomes - available. -

- + {!isSubmitted ? ( +
+
+ setEmail(e.target.value)} + className="w-full bg-gray-800/50 text-white" + required + disabled={isSubmitting} + /> + {error &&

{error}

}
- )} - - - - - - - + +
+ ) : ( + + )} + + ); } + +const SuccessMessage = ({ + toolkitName, + handleClose, +}: { + toolkitName: string; + handleClose: () => void; +}) => { + return ( +
+
+ + + +
+

+ Thanks for your interest! +

+

+ We'll notify you when the {toolkitName} toolkit becomes available. +

+ +
+ ); +}; diff --git a/src/components/custom/Toolkits/ToolCard.tsx b/src/components/custom/Toolkits/ToolCard.tsx index ee3f3e8a5..414b475a5 100644 --- a/src/components/custom/Toolkits/ToolCard.tsx +++ b/src/components/custom/Toolkits/ToolCard.tsx @@ -151,6 +151,7 @@ export const ToolCard: React.FC = ({ alt={`${name} logo`} width={40} height={40} + priority className="object-cover" onError={handleImageError} /> diff --git a/src/components/ui/dialog.tsx b/src/components/ui/dialog.tsx new file mode 100644 index 000000000..a9292e6ff --- /dev/null +++ b/src/components/ui/dialog.tsx @@ -0,0 +1,120 @@ +import * as React from "react"; +import * as DialogPrimitive from "@radix-ui/react-dialog"; +import { X } from "lucide-react"; + +import { cn } from "@/lib/utils"; + +const Dialog = DialogPrimitive.Root; + +const DialogTrigger = DialogPrimitive.Trigger; + +const DialogPortal = DialogPrimitive.Portal; + +const DialogClose = DialogPrimitive.Close; + +const DialogOverlay = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +DialogOverlay.displayName = DialogPrimitive.Overlay.displayName; + +const DialogContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, ...props }, ref) => ( + + + + {children} + + + Close + + + +)); +DialogContent.displayName = DialogPrimitive.Content.displayName; + +const DialogHeader = ({ + className, + ...props +}: React.HTMLAttributes) => ( +
+); +DialogHeader.displayName = "DialogHeader"; + +const DialogFooter = ({ + className, + ...props +}: React.HTMLAttributes) => ( +
+); +DialogFooter.displayName = "DialogFooter"; + +const DialogTitle = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +DialogTitle.displayName = DialogPrimitive.Title.displayName; + +const DialogDescription = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +DialogDescription.displayName = DialogPrimitive.Description.displayName; + +export { + Dialog, + DialogPortal, + DialogOverlay, + DialogTrigger, + DialogClose, + DialogContent, + DialogHeader, + DialogFooter, + DialogTitle, + DialogDescription, +};