@tanstack/cta-framework-react-cra 0.10.0-alpha.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ADD-ON-AUTHORING.md +169 -0
- package/LICENSE +21 -0
- package/add-ons/clerk/README.md +3 -0
- package/add-ons/clerk/assets/_dot_env.local.append +2 -0
- package/add-ons/clerk/assets/src/integrations/clerk/header-user.tsx +19 -0
- package/add-ons/clerk/assets/src/integrations/clerk/provider.tsx +18 -0
- package/add-ons/clerk/assets/src/routes/demo.clerk.tsx +20 -0
- package/add-ons/clerk/info.json +28 -0
- package/add-ons/clerk/logo.svg +6 -0
- package/add-ons/clerk/package.json +5 -0
- package/add-ons/clerk/small-logo.svg +5 -0
- package/add-ons/convex/README.md +4 -0
- package/add-ons/convex/assets/_dot_cursorrules.append +93 -0
- package/add-ons/convex/assets/_dot_env.local.append +3 -0
- package/add-ons/convex/assets/convex/products.ts +8 -0
- package/add-ons/convex/assets/convex/schema.ts +10 -0
- package/add-ons/convex/assets/src/integrations/convex/provider.tsx +20 -0
- package/add-ons/convex/assets/src/routes/demo.convex.tsx +33 -0
- package/add-ons/convex/info.json +23 -0
- package/add-ons/convex/package.json +6 -0
- package/add-ons/convex/small-logo.svg +5 -0
- package/add-ons/form/assets/src/components/demo.FormComponents.tsx.ejs +300 -0
- package/add-ons/form/assets/src/hooks/demo.form-context.ts +4 -0
- package/add-ons/form/assets/src/hooks/demo.form.ts +22 -0
- package/add-ons/form/assets/src/routes/demo.form.address.tsx.ejs +213 -0
- package/add-ons/form/assets/src/routes/demo.form.simple.tsx.ejs +77 -0
- package/add-ons/form/info.json +31 -0
- package/add-ons/form/package.json +6 -0
- package/add-ons/form/small-logo.svg +1 -0
- package/add-ons/module-federation/assets/module-federation.config.js.ejs +31 -0
- package/add-ons/module-federation/assets/src/demo-mf-component.tsx +3 -0
- package/add-ons/module-federation/assets/src/demo-mf-self-contained.tsx +11 -0
- package/add-ons/module-federation/info.json +8 -0
- package/add-ons/module-federation/package.json +5 -0
- package/add-ons/netlify/README.md +11 -0
- package/add-ons/netlify/info.json +8 -0
- package/add-ons/netlify/small-logo.svg +1 -0
- package/add-ons/sentry/assets/_dot_cursorrules.append +22 -0
- package/add-ons/sentry/assets/_dot_env.local.append +11 -0
- package/add-ons/sentry/assets/src/app/global-middleware.ts +11 -0
- package/add-ons/sentry/assets/src/routes/demo.sentry.testing.tsx +489 -0
- package/add-ons/sentry/info.json +17 -0
- package/add-ons/sentry/package.json +5 -0
- package/add-ons/sentry/small-logo.svg +1 -0
- package/add-ons/shadcn/README.md +7 -0
- package/add-ons/shadcn/assets/_dot_cursorrules.append +7 -0
- package/add-ons/shadcn/assets/components.json +21 -0
- package/add-ons/shadcn/assets/src/lib/utils.ts +6 -0
- package/add-ons/shadcn/assets/src/styles.css +138 -0
- package/add-ons/shadcn/info.json +8 -0
- package/add-ons/shadcn/package.json +9 -0
- package/add-ons/shadcn/small-logo.svg +1 -0
- package/add-ons/start/assets/_dot_gitignore.append +2 -0
- package/add-ons/start/assets/app.config.ts.ejs +32 -0
- package/add-ons/start/assets/src/api.ts +6 -0
- package/add-ons/start/assets/src/client.tsx.ejs +33 -0
- package/add-ons/start/assets/src/router.tsx.ejs +48 -0
- package/add-ons/start/assets/src/routes/api.demo-names.ts +11 -0
- package/add-ons/start/assets/src/routes/demo.start.api-request.tsx.ejs +33 -0
- package/add-ons/start/assets/src/routes/demo.start.server-funcs.tsx +50 -0
- package/add-ons/start/assets/src/ssr.tsx.ejs +30 -0
- package/add-ons/start/info.json +31 -0
- package/add-ons/start/package.json +13 -0
- package/add-ons/start/small-logo.svg +1 -0
- package/add-ons/store/assets/src/lib/demo-store.ts +13 -0
- package/add-ons/store/assets/src/routes/demo.store.tsx.ejs +75 -0
- package/add-ons/store/info.json +16 -0
- package/add-ons/store/package.json +6 -0
- package/add-ons/store/small-logo.svg +1 -0
- package/add-ons/t3env/README.md +16 -0
- package/add-ons/t3env/assets/src/env.ts +39 -0
- package/add-ons/t3env/info.json +8 -0
- package/add-ons/t3env/package.json +6 -0
- package/add-ons/t3env/small-logo.svg +6 -0
- package/add-ons/tRPC/assets/src/integrations/trpc/init.ts +9 -0
- package/add-ons/tRPC/assets/src/integrations/trpc/react.ts +4 -0
- package/add-ons/tRPC/assets/src/integrations/trpc/router.ts +21 -0
- package/add-ons/tRPC/assets/src/routes/api.trpc.$.tsx +16 -0
- package/add-ons/tRPC/info.json +9 -0
- package/add-ons/tRPC/package.json +9 -0
- package/add-ons/tRPC/small-logo.svg +1 -0
- package/add-ons/table/assets/src/data/demo-table-data.ts +50 -0
- package/add-ons/table/assets/src/routes/demo.table.tsx.ejs +373 -0
- package/add-ons/table/info.json +16 -0
- package/add-ons/table/package.json +7 -0
- package/add-ons/table/small-logo.svg +1 -0
- package/add-ons/tanstack-query/assets/src/integrations/tanstack-query/layout.tsx +5 -0
- package/add-ons/tanstack-query/assets/src/integrations/tanstack-query/root-provider.tsx.ejs +70 -0
- package/add-ons/tanstack-query/assets/src/routes/demo.tanstack-query.tsx.ejs +53 -0
- package/add-ons/tanstack-query/info.json +28 -0
- package/add-ons/tanstack-query/package.json +6 -0
- package/add-ons/tanstack-query/small-logo.svg +1 -0
- package/dist/index.js +18 -0
- package/dist/types/index.d.ts +1 -0
- package/examples/tanchat/README.md +37 -0
- package/examples/tanchat/assets/_dot_env.local.append +2 -0
- package/examples/tanchat/assets/public/example-guitar-flowers.jpg +0 -0
- package/examples/tanchat/assets/public/example-guitar-motherboard.jpg +0 -0
- package/examples/tanchat/assets/public/example-guitar-racing.jpg +0 -0
- package/examples/tanchat/assets/public/example-guitar-steamer-trunk.jpg +0 -0
- package/examples/tanchat/assets/public/example-guitar-superhero.jpg +0 -0
- package/examples/tanchat/assets/public/example-guitar-traveling.jpg +0 -0
- package/examples/tanchat/assets/public/example-guitar-video-games.jpg +0 -0
- package/examples/tanchat/assets/src/components/example-AIAssistant.tsx +173 -0
- package/examples/tanchat/assets/src/components/example-GuitarRecommendation.tsx +47 -0
- package/examples/tanchat/assets/src/data/example-guitars.ts +83 -0
- package/examples/tanchat/assets/src/demo.index.css +220 -0
- package/examples/tanchat/assets/src/integrations/tanchat/header-user.tsx +5 -0
- package/examples/tanchat/assets/src/routes/api.messages.ts +24 -0
- package/examples/tanchat/assets/src/routes/api.sse.ts +23 -0
- package/examples/tanchat/assets/src/routes/example.chat.tsx +159 -0
- package/examples/tanchat/assets/src/routes/example.guitars/$guitarId.tsx +50 -0
- package/examples/tanchat/assets/src/routes/example.guitars/index.tsx +54 -0
- package/examples/tanchat/assets/src/store/example-assistant.ts +3 -0
- package/examples/tanchat/assets/src/utils/demo.ai.ts +62 -0
- package/examples/tanchat/assets/src/utils/demo.sse.ts +31 -0
- package/examples/tanchat/assets/src/utils/demo.tools.ts +47 -0
- package/examples/tanchat/info.json +35 -0
- package/examples/tanchat/package.json +16 -0
- package/examples/tanchat/small-logo.svg +1 -0
- package/package.json +34 -0
- package/project/base/README.md.ejs +558 -0
- package/project/base/_dot_gitignore +5 -0
- package/project/base/_dot_vscode/settings.json.ejs +35 -0
- package/project/base/index.html.ejs +20 -0
- package/project/base/package.json +30 -0
- package/project/base/public/favicon.ico +0 -0
- package/project/base/public/logo192.png +0 -0
- package/project/base/public/logo512.png +0 -0
- package/project/base/public/manifest.json +25 -0
- package/project/base/public/robots.txt +3 -0
- package/project/base/src/App.css.ejs +38 -0
- package/project/base/src/App.test.tsx.ejs +10 -0
- package/project/base/src/App.tsx.ejs +63 -0
- package/project/base/src/components/Header.tsx.ejs +27 -0
- package/project/base/src/logo.svg +44 -0
- package/project/base/src/main.tsx.ejs +155 -0
- package/project/base/src/reportWebVitals.ts.ejs +28 -0
- package/project/base/src/routes/__root.tsx.ejs +82 -0
- package/project/base/src/routes/index.tsx.ejs +67 -0
- package/project/base/src/styles.css.ejs +15 -0
- package/project/base/tsconfig.json.ejs +29 -0
- package/project/base/vite.config.js.ejs +23 -0
- package/project/packages.json +20 -0
- package/src/index.ts +26 -0
- package/tests/react-cra.test.ts +150 -0
- package/tests/snapshots/react-cra/cr-js-form-npm.json +29 -0
- package/tests/snapshots/react-cra/cr-js-npm.json +23 -0
- package/tests/snapshots/react-cra/cr-ts-npm.json +24 -0
- package/tests/snapshots/react-cra/cr-ts-start-npm.json +28 -0
- package/tests/snapshots/react-cra/cr-ts-start-tanstack-query-npm.json +31 -0
- package/tests/snapshots/react-cra/fr-ts-biome-npm.json +26 -0
- package/tests/snapshots/react-cra/fr-ts-npm.json +24 -0
- package/tests/snapshots/react-cra/fr-ts-tw-npm.json +23 -0
- package/tests/test-utilities.ts +44 -0
- package/toolchains/biome/assets/biome.json +31 -0
- package/toolchains/biome/info.json +8 -0
- package/toolchains/biome/package.json +10 -0
- package/toolchains/biome/small-logo.svg +5 -0
- package/toolchains/eslint/assets/_dot_prettierignore +3 -0
- package/toolchains/eslint/assets/eslint.config.js +5 -0
- package/toolchains/eslint/assets/prettier.config.js +10 -0
- package/toolchains/eslint/info.json +8 -0
- package/toolchains/eslint/package.json +11 -0
- package/toolchains/eslint/small-logo.svg +7 -0
- package/tsconfig.json +17 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 633 633"><defs><linearGradient id="b" x1="50%" x2="50%" y1="0%" y2="71.65%"><stop offset="0%" stop-color="#6BDAFF"/><stop offset="31.922%" stop-color="#F9FFB5"/><stop offset="70.627%" stop-color="#FFA770"/><stop offset="100%" stop-color="#FF7373"/></linearGradient><linearGradient id="d" x1="43.996%" x2="53.441%" y1="8.54%" y2="93.872%"><stop offset="0%" stop-color="#673800"/><stop offset="100%" stop-color="#B65E00"/></linearGradient><linearGradient id="e" x1="50%" x2="50%" y1="0%" y2="100%"><stop offset="0%" stop-color="#2F8A00"/><stop offset="100%" stop-color="#90FF57"/></linearGradient><linearGradient id="f" x1="50%" x2="50%" y1="0%" y2="100%"><stop offset="0%" stop-color="#2F8A00"/><stop offset="100%" stop-color="#90FF57"/></linearGradient><linearGradient id="g" x1="50%" x2="50%" y1="0%" y2="100%"><stop offset="0%" stop-color="#2F8A00"/><stop offset="100%" stop-color="#90FF57"/></linearGradient><linearGradient id="h" x1="50%" x2="50%" y1="0%" y2="100%"><stop offset="0%" stop-color="#2F8A00"/><stop offset="100%" stop-color="#90FF57"/></linearGradient><linearGradient id="i" x1="50%" x2="50%" y1="0%" y2="100%"><stop offset="0%" stop-color="#2F8A00"/><stop offset="100%" stop-color="#90FF57"/></linearGradient><linearGradient id="j" x1="50%" x2="50%" y1="0%" y2="100%"><stop offset="0%" stop-color="#2F8A00"/><stop offset="100%" stop-color="#90FF57"/></linearGradient><linearGradient id="k" x1="92.9%" x2="8.641%" y1="45.768%" y2="54.892%"><stop offset="0%" stop-color="#EE2700"/><stop offset="100%" stop-color="#FF008E"/></linearGradient><linearGradient id="l" x1="61.109%" x2="43.717%" y1="3.633%" y2="43.072%"><stop offset="0%" stop-color="#FFF400"/><stop offset="100%" stop-color="#3C8700"/></linearGradient><linearGradient id="m" x1="50%" x2="50%" y1="0%" y2="100%"><stop offset="0%" stop-color="#FFDF00"/><stop offset="100%" stop-color="#FF9D00"/></linearGradient><linearGradient id="n" x1="127.279%" x2="0%" y1="49.778%" y2="50.222%"><stop offset="0%" stop-color="#FFA400"/><stop offset="100%" stop-color="#FF5E00"/></linearGradient><linearGradient id="o" x1="127.279%" x2="0%" y1="47.531%" y2="52.469%"><stop offset="0%" stop-color="#FFA400"/><stop offset="100%" stop-color="#FF5E00"/></linearGradient><linearGradient id="p" x1="127.279%" x2="0%" y1="46.195%" y2="53.805%"><stop offset="0%" stop-color="#FFA400"/><stop offset="100%" stop-color="#FF5E00"/></linearGradient><linearGradient id="q" x1="127.279%" x2="0%" y1="35.33%" y2="64.67%"><stop offset="0%" stop-color="#FFA400"/><stop offset="100%" stop-color="#FF5E00"/></linearGradient><linearGradient id="r" x1="127.279%" x2="0%" y1="4.875%" y2="95.125%"><stop offset="0%" stop-color="#FFA400"/><stop offset="100%" stop-color="#FF5E00"/></linearGradient><linearGradient id="s" x1="78.334%" x2="31.668%" y1="0%" y2="100%"><stop offset="0%" stop-color="#FFA400"/><stop offset="100%" stop-color="#FF5E00"/></linearGradient><linearGradient id="t" x1="57.913%" x2="44.88%" y1="0%" y2="100%"><stop offset="0%" stop-color="#FFA400"/><stop offset="100%" stop-color="#FF5E00"/></linearGradient><linearGradient id="u" x1="50.495%" x2="49.68%" y1="0%" y2="100%"><stop offset="0%" stop-color="#FFA400"/><stop offset="100%" stop-color="#FF5E00"/></linearGradient><circle id="a" cx="308.5" cy="308.5" r="308.5"/><circle id="v" cx="307.5" cy="308.5" r="316.5"/></defs><g fill="none" fill-rule="evenodd" transform="translate(9 8)"><mask id="c" fill="#fff"><use xlink:href="#a"/></mask><use xlink:href="#a" fill="url(#b)"/><ellipse cx="81.5" cy="602.5" fill="#015064" stroke="#00CFE2" stroke-width="25" mask="url(#c)" rx="214.5" ry="185.968"/><ellipse cx="535.5" cy="602.5" fill="#015064" stroke="#00CFE2" stroke-width="25" mask="url(#c)" rx="214.5" ry="185.968"/><ellipse cx="81.5" cy="640.5" fill="#015064" stroke="#00A8B8" stroke-width="25" mask="url(#c)" rx="214.5" ry="185.968"/><ellipse cx="535.5" cy="640.5" fill="#015064" stroke="#00A8B8" stroke-width="25" mask="url(#c)" rx="214.5" ry="185.968"/><ellipse cx="81.5" cy="676.5" fill="#015064" stroke="#007782" stroke-width="25" mask="url(#c)" rx="214.5" ry="185.968"/><ellipse cx="535.5" cy="676.5" fill="#015064" stroke="#007782" stroke-width="25" mask="url(#c)" rx="214.5" ry="185.968"/><g mask="url(#c)"><path fill="url(#d)" stroke="#6E3A00" stroke-width="6.088" d="M98.318 88.007c7.691 37.104 16.643 72.442 26.856 106.013 10.212 33.571 25.57 68.934 46.07 106.088l-51.903 11.67c-10.057-60.01-17.232-99.172-21.525-117.487-4.293-18.315-10.989-51.434-20.089-99.357l20.591-6.927" transform="scale(-1 1) rotate(25 -300.37 -553.013)"/><g stroke="#2F8A00"><path fill="url(#e)" stroke-width="9.343" d="M108.544 66.538s-13.54-21.305-37.417-27.785c-15.917-4.321-33.933.31-54.048 13.892C33.464 65.975 47.24 73.52 58.405 75.28c16.749 2.64 50.14-8.74 50.14-8.74Z" transform="rotate(1 -6061.691 5926.397)"/><path fill="url(#f)" stroke-width="9.343" d="M108.544 67.138s-47.187-5.997-81.077 19.936C4.873 104.362-3.782 137.794 1.502 187.369c28.42-29.22 48.758-50.836 61.016-64.846 18.387-21.016 46.026-55.385 46.026-55.385Z" transform="rotate(1 -6061.691 5926.397)"/><path fill="url(#g)" stroke-width="9.343" d="M108.544 66.538c-1.96-21.705 3.98-38.018 17.82-48.94C140.203 6.674 154.85.808 170.303 0c-4.865 21.527-12.373 36.314-22.524 44.361-10.151 8.048-23.23 15.44-39.236 22.177Z" transform="rotate(1 -6061.691 5926.397)"/><path fill="url(#h)" stroke-width="9.343" d="M108.544 67.138c29.838-31.486 61.061-42.776 93.669-33.869C234.82 42.176 253.749 60.785 259 89.096c-34.898-3.657-59.974-6.343-75.228-8.058-15.254-1.716-40.33-6.349-75.228-13.9Z" transform="rotate(1 -6061.691 5926.397)"/><path fill="url(#i)" stroke-width="9.343" d="M108.544 67.138c34.868-9.381 64.503-3.658 88.905 17.17 24.402 20.829 39.656 46.686 45.762 77.571-39.626-7.574-68.4-20.115-86.322-37.624a395.051 395.051 0 0 1-48.345-57.117Z" transform="rotate(1 -6061.691 5926.397)"/><path fill="url(#j)" stroke-width="9.343" d="M108.544 67.138C76.206 82.6 57.608 105.366 52.75 135.436c-4.858 30.07-.292 62.89 13.698 98.462 24.873-41.418 38.905-71.368 42.096-89.849 3.191-18.48 3.191-44.118 0-76.91Z" transform="rotate(1 -6061.691 5926.397)"/><path stroke-linecap="round" stroke-width="5.91" d="M211.284 173.477c-13.851 21.992-23.291 42.022-28.32 60.093-5.03 18.071-8.175 33.143-9.436 45.216"/><path stroke-linecap="round" stroke-width="5.91" d="M209.814 176.884c-23.982 2.565-42.792 10.469-56.428 23.714-13.639 13.245-23.483 26.136-29.536 38.674M219.045 167.299c29.028-7.723 50.972-10.173 65.831-7.352 14.859 2.822 26.807 7.659 35.842 14.51M211.31 172.618c20.29 9.106 38.353 19.052 54.186 29.837 15.833 10.786 27.714 20.99 35.643 30.617"/></g><path stroke="#830305" stroke-linecap="round" stroke-linejoin="bevel" stroke-width="6.937" d="m409.379 398.157-23.176 18.556M328.04 375.516l-22.313 28.398M312.904 353.698l53.18 59.816"/><path fill="url(#k)" d="M67.585 27.463H5.68C1.893 28.148 0 30.38 0 34.16c0 3.78 1.893 6.211 5.68 7.293h67.17l41.751-30.356c2.488-2.646 2.794-5.315.92-8.006s-4.6-3.626-8.177-2.803l-39.76 27.174Z" transform="scale(-1 1) rotate(-9 2092.128 2856.854)"/><path fill="#D8D8D8" stroke="#FFF" stroke-linecap="round" stroke-linejoin="bevel" stroke-width="4.414" d="m402.861 391.51.471-4.088M382.21 388.752l.472-4.087M361.546 385.404l.485-3.845M337.59 371.883l2.56-2.498M324.276 359.567l2.56-2.497"/></g><ellipse cx="308.5" cy="720.5" fill="url(#l)" mask="url(#c)" rx="266" ry="316.5"/><ellipse cx="308.5" cy="720.5" stroke="#6DA300" stroke-opacity=".502" stroke-width="26" mask="url(#c)" rx="253" ry="303.5"/><g mask="url(#c)"><g transform="translate(389 -32)"><circle cx="168.5" cy="113.5" r="113.5" fill="url(#m)"/><circle cx="168.5" cy="113.5" r="106" stroke="#FFC900" stroke-opacity=".529" stroke-width="15"/><path stroke="url(#n)" stroke-linecap="round" stroke-linejoin="bevel" stroke-width="12" d="M30 113H0"/><path stroke="url(#o)" stroke-linecap="round" stroke-linejoin="bevel" stroke-width="12" d="M33.5 79.5 7 74"/><path stroke="url(#p)" stroke-linecap="round" stroke-linejoin="bevel" stroke-width="12" d="m34 146-29 8"/><path stroke="url(#q)" stroke-linecap="round" stroke-linejoin="bevel" stroke-width="12" d="m45 177-24 13"/><path stroke="url(#r)" stroke-linecap="round" stroke-linejoin="bevel" stroke-width="12" d="m67 204-20 19"/><path stroke="url(#s)" stroke-linecap="round" stroke-linejoin="bevel" stroke-width="12" d="m94.373 227-13.834 22.847"/><path stroke="url(#t)" stroke-linecap="round" stroke-linejoin="bevel" stroke-width="12" d="M127.5 243.5 120 268"/><path stroke="url(#u)" stroke-linecap="round" stroke-linejoin="bevel" stroke-width="12" d="m167.5 252.5.5 24.5"/></g></g><circle cx="307.5" cy="308.5" r="304" stroke="#000" stroke-width="25"/></g></svg>
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
<% if (addOnEnabled.tRPC) { %>
|
|
2
|
+
import { QueryClient } from "@tanstack/react-query";
|
|
3
|
+
import superjson from "superjson";
|
|
4
|
+
import { createTRPCClient, httpBatchStreamLink } from "@trpc/client";
|
|
5
|
+
import { createTRPCOptionsProxy } from "@trpc/tanstack-react-query";
|
|
6
|
+
|
|
7
|
+
import { TRPCProvider } from "@/integrations/trpc/react";
|
|
8
|
+
|
|
9
|
+
import type { TRPCRouter } from "@/integrations/trpc/router";
|
|
10
|
+
|
|
11
|
+
function getUrl() {
|
|
12
|
+
const base = (() => {
|
|
13
|
+
if (typeof window !== "undefined") return "";
|
|
14
|
+
return `http://localhost:${process.env.PORT ?? 3000}`;
|
|
15
|
+
})();
|
|
16
|
+
return `${base}/api/trpc`;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export const trpcClient = createTRPCClient<TRPCRouter>({
|
|
20
|
+
links: [
|
|
21
|
+
httpBatchStreamLink({
|
|
22
|
+
transformer: superjson,
|
|
23
|
+
url: getUrl(),
|
|
24
|
+
}),
|
|
25
|
+
],
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
const queryClient = new QueryClient({
|
|
29
|
+
defaultOptions: {
|
|
30
|
+
dehydrate: { serializeData: superjson.serialize },
|
|
31
|
+
hydrate: { deserializeData: superjson.deserialize },
|
|
32
|
+
},
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
const serverHelpers = createTRPCOptionsProxy({
|
|
36
|
+
client: trpcClient,
|
|
37
|
+
queryClient: queryClient,
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
export function getContext() {
|
|
41
|
+
return {
|
|
42
|
+
queryClient,
|
|
43
|
+
trpc: serverHelpers,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export function Provider({ children }: { children: React.ReactNode }) {
|
|
48
|
+
return (
|
|
49
|
+
<TRPCProvider trpcClient={trpcClient} queryClient={queryClient}>
|
|
50
|
+
{children}
|
|
51
|
+
</TRPCProvider>
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
<% } else { %>
|
|
55
|
+
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
|
|
56
|
+
|
|
57
|
+
const queryClient = new QueryClient()
|
|
58
|
+
|
|
59
|
+
export function getContext() {
|
|
60
|
+
return {
|
|
61
|
+
queryClient,
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export function Provider({ children }: { children: React.ReactNode }) {
|
|
66
|
+
return (
|
|
67
|
+
<QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
|
|
68
|
+
)
|
|
69
|
+
}
|
|
70
|
+
<% } %>
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { <% if (fileRouter) { %>createFileRoute<% } else { %>createRoute<% } %> } from '@tanstack/react-router'
|
|
2
|
+
import { useQuery } from '@tanstack/react-query'
|
|
3
|
+
<% if (addOnEnabled.tRPC) { %>
|
|
4
|
+
import { useTRPC } from "@/integrations/trpc/react";
|
|
5
|
+
<% } %>
|
|
6
|
+
<% if (codeRouter) { %>
|
|
7
|
+
import type { RootRoute } from '@tanstack/react-router'
|
|
8
|
+
<% } else { %>
|
|
9
|
+
export const Route = createFileRoute('/demo/tanstack-query')({
|
|
10
|
+
<% if (addOnEnabled.tRPC) { %>
|
|
11
|
+
loader: async ({ context }) => {
|
|
12
|
+
await context.queryClient.prefetchQuery(
|
|
13
|
+
context.trpc.people.list.queryOptions()
|
|
14
|
+
);
|
|
15
|
+
},
|
|
16
|
+
<% } %>
|
|
17
|
+
component: TanStackQueryDemo,
|
|
18
|
+
})
|
|
19
|
+
<% } %>
|
|
20
|
+
function TanStackQueryDemo() {
|
|
21
|
+
<% if (addOnEnabled.tRPC) { %>
|
|
22
|
+
const trpc = useTRPC();
|
|
23
|
+
const { data } = useQuery(trpc.people.list.queryOptions());
|
|
24
|
+
<% } else { %>
|
|
25
|
+
const { data } = useQuery({
|
|
26
|
+
queryKey: ['people'],
|
|
27
|
+
queryFn: () => Promise.resolve([
|
|
28
|
+
{ name: 'John Doe' },
|
|
29
|
+
{ name: 'Jane Doe' },
|
|
30
|
+
]),
|
|
31
|
+
initialData: [],
|
|
32
|
+
})
|
|
33
|
+
<% } %>
|
|
34
|
+
|
|
35
|
+
return (
|
|
36
|
+
<div className="p-4">
|
|
37
|
+
<h1 className="text-2xl mb-4">People list</h1>
|
|
38
|
+
<ul>
|
|
39
|
+
{data.map((person) => (
|
|
40
|
+
<li key={person.name}>{person.name}</li>
|
|
41
|
+
))}
|
|
42
|
+
</ul>
|
|
43
|
+
</div>
|
|
44
|
+
)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
<% if (codeRouter) { %>
|
|
48
|
+
export default (parentRoute: RootRoute) => createRoute({
|
|
49
|
+
path: '/demo/tanstack-query',
|
|
50
|
+
component: TanStackQueryDemo,
|
|
51
|
+
getParentRoute: () => parentRoute,
|
|
52
|
+
})
|
|
53
|
+
<% } %>
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "Query",
|
|
3
|
+
"description": "Integrate TanStack Query into your application.",
|
|
4
|
+
"phase": "add-on",
|
|
5
|
+
"modes": ["file-router", "code-router"],
|
|
6
|
+
"type": "add-on",
|
|
7
|
+
"link": "https://tanstack.com/query/latest",
|
|
8
|
+
"routes": [
|
|
9
|
+
{
|
|
10
|
+
"url": "/demo/tanstack-query",
|
|
11
|
+
"name": "TanStack Query",
|
|
12
|
+
"path": "src/routes/demo.tanstack-query.tsx",
|
|
13
|
+
"jsName": "TanStackQueryDemo"
|
|
14
|
+
}
|
|
15
|
+
],
|
|
16
|
+
"integrations": [
|
|
17
|
+
{
|
|
18
|
+
"type": "root-provider",
|
|
19
|
+
"path": "src/integrations/tanstack-query/root-provider.tsx",
|
|
20
|
+
"jsName": "TanStackQueryProvider"
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
"type": "layout",
|
|
24
|
+
"path": "src/integrations/tanstack-query/layout.tsx",
|
|
25
|
+
"jsName": "TanStackQueryLayout"
|
|
26
|
+
}
|
|
27
|
+
]
|
|
28
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 633 633"><defs><linearGradient id="b" x1="50%" x2="50%" y1="0%" y2="71.65%"><stop offset="0%" stop-color="#6BDAFF"/><stop offset="31.922%" stop-color="#F9FFB5"/><stop offset="70.627%" stop-color="#FFA770"/><stop offset="100%" stop-color="#FF7373"/></linearGradient><linearGradient id="d" x1="43.996%" x2="53.441%" y1="8.54%" y2="93.872%"><stop offset="0%" stop-color="#673800"/><stop offset="100%" stop-color="#B65E00"/></linearGradient><linearGradient id="e" x1="50%" x2="50%" y1="0%" y2="100%"><stop offset="0%" stop-color="#2F8A00"/><stop offset="100%" stop-color="#90FF57"/></linearGradient><linearGradient id="f" x1="50%" x2="50%" y1="0%" y2="100%"><stop offset="0%" stop-color="#2F8A00"/><stop offset="100%" stop-color="#90FF57"/></linearGradient><linearGradient id="g" x1="50%" x2="50%" y1="0%" y2="100%"><stop offset="0%" stop-color="#2F8A00"/><stop offset="100%" stop-color="#90FF57"/></linearGradient><linearGradient id="h" x1="50%" x2="50%" y1="0%" y2="100%"><stop offset="0%" stop-color="#2F8A00"/><stop offset="100%" stop-color="#90FF57"/></linearGradient><linearGradient id="i" x1="50%" x2="50%" y1="0%" y2="100%"><stop offset="0%" stop-color="#2F8A00"/><stop offset="100%" stop-color="#90FF57"/></linearGradient><linearGradient id="j" x1="50%" x2="50%" y1="0%" y2="100%"><stop offset="0%" stop-color="#2F8A00"/><stop offset="100%" stop-color="#90FF57"/></linearGradient><linearGradient id="k" x1="92.9%" x2="8.641%" y1="45.768%" y2="54.892%"><stop offset="0%" stop-color="#EE2700"/><stop offset="100%" stop-color="#FF008E"/></linearGradient><linearGradient id="l" x1="61.109%" x2="43.717%" y1="3.633%" y2="43.072%"><stop offset="0%" stop-color="#FFF400"/><stop offset="100%" stop-color="#3C8700"/></linearGradient><linearGradient id="m" x1="50%" x2="50%" y1="0%" y2="100%"><stop offset="0%" stop-color="#FFDF00"/><stop offset="100%" stop-color="#FF9D00"/></linearGradient><linearGradient id="n" x1="127.279%" x2="0%" y1="49.778%" y2="50.222%"><stop offset="0%" stop-color="#FFA400"/><stop offset="100%" stop-color="#FF5E00"/></linearGradient><linearGradient id="o" x1="127.279%" x2="0%" y1="47.531%" y2="52.469%"><stop offset="0%" stop-color="#FFA400"/><stop offset="100%" stop-color="#FF5E00"/></linearGradient><linearGradient id="p" x1="127.279%" x2="0%" y1="46.195%" y2="53.805%"><stop offset="0%" stop-color="#FFA400"/><stop offset="100%" stop-color="#FF5E00"/></linearGradient><linearGradient id="q" x1="127.279%" x2="0%" y1="35.33%" y2="64.67%"><stop offset="0%" stop-color="#FFA400"/><stop offset="100%" stop-color="#FF5E00"/></linearGradient><linearGradient id="r" x1="127.279%" x2="0%" y1="4.875%" y2="95.125%"><stop offset="0%" stop-color="#FFA400"/><stop offset="100%" stop-color="#FF5E00"/></linearGradient><linearGradient id="s" x1="78.334%" x2="31.668%" y1="0%" y2="100%"><stop offset="0%" stop-color="#FFA400"/><stop offset="100%" stop-color="#FF5E00"/></linearGradient><linearGradient id="t" x1="57.913%" x2="44.88%" y1="0%" y2="100%"><stop offset="0%" stop-color="#FFA400"/><stop offset="100%" stop-color="#FF5E00"/></linearGradient><linearGradient id="u" x1="50.495%" x2="49.68%" y1="0%" y2="100%"><stop offset="0%" stop-color="#FFA400"/><stop offset="100%" stop-color="#FF5E00"/></linearGradient><circle id="a" cx="308.5" cy="308.5" r="308.5"/><circle id="v" cx="307.5" cy="308.5" r="316.5"/></defs><g fill="none" fill-rule="evenodd" transform="translate(9 8)"><mask id="c" fill="#fff"><use xlink:href="#a"/></mask><use xlink:href="#a" fill="url(#b)"/><ellipse cx="81.5" cy="602.5" fill="#015064" stroke="#00CFE2" stroke-width="25" mask="url(#c)" rx="214.5" ry="185.968"/><ellipse cx="535.5" cy="602.5" fill="#015064" stroke="#00CFE2" stroke-width="25" mask="url(#c)" rx="214.5" ry="185.968"/><ellipse cx="81.5" cy="640.5" fill="#015064" stroke="#00A8B8" stroke-width="25" mask="url(#c)" rx="214.5" ry="185.968"/><ellipse cx="535.5" cy="640.5" fill="#015064" stroke="#00A8B8" stroke-width="25" mask="url(#c)" rx="214.5" ry="185.968"/><ellipse cx="81.5" cy="676.5" fill="#015064" stroke="#007782" stroke-width="25" mask="url(#c)" rx="214.5" ry="185.968"/><ellipse cx="535.5" cy="676.5" fill="#015064" stroke="#007782" stroke-width="25" mask="url(#c)" rx="214.5" ry="185.968"/><g mask="url(#c)"><path fill="url(#d)" stroke="#6E3A00" stroke-width="6.088" d="M98.318 88.007c7.691 37.104 16.643 72.442 26.856 106.013 10.212 33.571 25.57 68.934 46.07 106.088l-51.903 11.67c-10.057-60.01-17.232-99.172-21.525-117.487-4.293-18.315-10.989-51.434-20.089-99.357l20.591-6.927" transform="scale(-1 1) rotate(25 -300.37 -553.013)"/><g stroke="#2F8A00"><path fill="url(#e)" stroke-width="9.343" d="M108.544 66.538s-13.54-21.305-37.417-27.785c-15.917-4.321-33.933.31-54.048 13.892C33.464 65.975 47.24 73.52 58.405 75.28c16.749 2.64 50.14-8.74 50.14-8.74Z" transform="rotate(1 -6061.691 5926.397)"/><path fill="url(#f)" stroke-width="9.343" d="M108.544 67.138s-47.187-5.997-81.077 19.936C4.873 104.362-3.782 137.794 1.502 187.369c28.42-29.22 48.758-50.836 61.016-64.846 18.387-21.016 46.026-55.385 46.026-55.385Z" transform="rotate(1 -6061.691 5926.397)"/><path fill="url(#g)" stroke-width="9.343" d="M108.544 66.538c-1.96-21.705 3.98-38.018 17.82-48.94C140.203 6.674 154.85.808 170.303 0c-4.865 21.527-12.373 36.314-22.524 44.361-10.151 8.048-23.23 15.44-39.236 22.177Z" transform="rotate(1 -6061.691 5926.397)"/><path fill="url(#h)" stroke-width="9.343" d="M108.544 67.138c29.838-31.486 61.061-42.776 93.669-33.869C234.82 42.176 253.749 60.785 259 89.096c-34.898-3.657-59.974-6.343-75.228-8.058-15.254-1.716-40.33-6.349-75.228-13.9Z" transform="rotate(1 -6061.691 5926.397)"/><path fill="url(#i)" stroke-width="9.343" d="M108.544 67.138c34.868-9.381 64.503-3.658 88.905 17.17 24.402 20.829 39.656 46.686 45.762 77.571-39.626-7.574-68.4-20.115-86.322-37.624a395.051 395.051 0 0 1-48.345-57.117Z" transform="rotate(1 -6061.691 5926.397)"/><path fill="url(#j)" stroke-width="9.343" d="M108.544 67.138C76.206 82.6 57.608 105.366 52.75 135.436c-4.858 30.07-.292 62.89 13.698 98.462 24.873-41.418 38.905-71.368 42.096-89.849 3.191-18.48 3.191-44.118 0-76.91Z" transform="rotate(1 -6061.691 5926.397)"/><path stroke-linecap="round" stroke-width="5.91" d="M211.284 173.477c-13.851 21.992-23.291 42.022-28.32 60.093-5.03 18.071-8.175 33.143-9.436 45.216"/><path stroke-linecap="round" stroke-width="5.91" d="M209.814 176.884c-23.982 2.565-42.792 10.469-56.428 23.714-13.639 13.245-23.483 26.136-29.536 38.674M219.045 167.299c29.028-7.723 50.972-10.173 65.831-7.352 14.859 2.822 26.807 7.659 35.842 14.51M211.31 172.618c20.29 9.106 38.353 19.052 54.186 29.837 15.833 10.786 27.714 20.99 35.643 30.617"/></g><path stroke="#830305" stroke-linecap="round" stroke-linejoin="bevel" stroke-width="6.937" d="m409.379 398.157-23.176 18.556M328.04 375.516l-22.313 28.398M312.904 353.698l53.18 59.816"/><path fill="url(#k)" d="M67.585 27.463H5.68C1.893 28.148 0 30.38 0 34.16c0 3.78 1.893 6.211 5.68 7.293h67.17l41.751-30.356c2.488-2.646 2.794-5.315.92-8.006s-4.6-3.626-8.177-2.803l-39.76 27.174Z" transform="scale(-1 1) rotate(-9 2092.128 2856.854)"/><path fill="#D8D8D8" stroke="#FFF" stroke-linecap="round" stroke-linejoin="bevel" stroke-width="4.414" d="m402.861 391.51.471-4.088M382.21 388.752l.472-4.087M361.546 385.404l.485-3.845M337.59 371.883l2.56-2.498M324.276 359.567l2.56-2.497"/></g><ellipse cx="308.5" cy="720.5" fill="url(#l)" mask="url(#c)" rx="266" ry="316.5"/><ellipse cx="308.5" cy="720.5" stroke="#6DA300" stroke-opacity=".502" stroke-width="26" mask="url(#c)" rx="253" ry="303.5"/><g mask="url(#c)"><g transform="translate(389 -32)"><circle cx="168.5" cy="113.5" r="113.5" fill="url(#m)"/><circle cx="168.5" cy="113.5" r="106" stroke="#FFC900" stroke-opacity=".529" stroke-width="15"/><path stroke="url(#n)" stroke-linecap="round" stroke-linejoin="bevel" stroke-width="12" d="M30 113H0"/><path stroke="url(#o)" stroke-linecap="round" stroke-linejoin="bevel" stroke-width="12" d="M33.5 79.5 7 74"/><path stroke="url(#p)" stroke-linecap="round" stroke-linejoin="bevel" stroke-width="12" d="m34 146-29 8"/><path stroke="url(#q)" stroke-linecap="round" stroke-linejoin="bevel" stroke-width="12" d="m45 177-24 13"/><path stroke="url(#r)" stroke-linecap="round" stroke-linejoin="bevel" stroke-width="12" d="m67 204-20 19"/><path stroke="url(#s)" stroke-linecap="round" stroke-linejoin="bevel" stroke-width="12" d="m94.373 227-13.834 22.847"/><path stroke="url(#t)" stroke-linecap="round" stroke-linejoin="bevel" stroke-width="12" d="M127.5 243.5 120 268"/><path stroke="url(#u)" stroke-linecap="round" stroke-linejoin="bevel" stroke-width="12" d="m167.5 252.5.5 24.5"/></g></g><circle cx="307.5" cy="308.5" r="304" stroke="#000" stroke-width="25"/></g></svg>
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { dirname, join } from 'node:path';
|
|
2
|
+
import { fileURLToPath } from 'node:url';
|
|
3
|
+
import { registerFramework } from '@tanstack/cta-engine';
|
|
4
|
+
export function register() {
|
|
5
|
+
registerFramework({
|
|
6
|
+
id: 'react-cra',
|
|
7
|
+
name: 'react',
|
|
8
|
+
description: 'Templates for React CRA',
|
|
9
|
+
version: '0.1.0',
|
|
10
|
+
baseDirectory: join(dirname(dirname(fileURLToPath(import.meta.url))), 'project'),
|
|
11
|
+
addOnsDirectories: [
|
|
12
|
+
join(dirname(dirname(fileURLToPath(import.meta.url))), 'add-ons'),
|
|
13
|
+
join(dirname(dirname(fileURLToPath(import.meta.url))), 'toolchains'),
|
|
14
|
+
join(dirname(dirname(fileURLToPath(import.meta.url))), 'examples'),
|
|
15
|
+
],
|
|
16
|
+
examplesDirectory: join(dirname(dirname(fileURLToPath(import.meta.url))), 'examples'),
|
|
17
|
+
});
|
|
18
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function register(): void;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# TanStack Chat Application
|
|
2
|
+
|
|
3
|
+
Am example chat application built with TanStack Start, TanStack Store, and Claude AI.
|
|
4
|
+
|
|
5
|
+
## .env Updates
|
|
6
|
+
|
|
7
|
+
```env
|
|
8
|
+
ANTHROPIC_API_KEY=your_anthropic_api_key
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## ✨ Features
|
|
12
|
+
|
|
13
|
+
### AI Capabilities
|
|
14
|
+
- 🤖 Powered by Claude 3.5 Sonnet
|
|
15
|
+
- 📝 Rich markdown formatting with syntax highlighting
|
|
16
|
+
- 🎯 Customizable system prompts for tailored AI behavior
|
|
17
|
+
- 🔄 Real-time message updates and streaming responses (coming soon)
|
|
18
|
+
|
|
19
|
+
### User Experience
|
|
20
|
+
- 🎨 Modern UI with Tailwind CSS and Lucide icons
|
|
21
|
+
- 🔍 Conversation management and history
|
|
22
|
+
- 🔐 Secure API key management
|
|
23
|
+
- 📋 Markdown rendering with code highlighting
|
|
24
|
+
|
|
25
|
+
### Technical Features
|
|
26
|
+
- 📦 Centralized state management with TanStack Store
|
|
27
|
+
- 🔌 Extensible architecture for multiple AI providers
|
|
28
|
+
- 🛠️ TypeScript for type safety
|
|
29
|
+
|
|
30
|
+
## Architecture
|
|
31
|
+
|
|
32
|
+
### Tech Stack
|
|
33
|
+
- **Frontend Framework**: TanStack Start
|
|
34
|
+
- **Routing**: TanStack Router
|
|
35
|
+
- **State Management**: TanStack Store
|
|
36
|
+
- **Styling**: Tailwind CSS
|
|
37
|
+
- **AI Integration**: Anthropic's Claude API
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import { useEffect, useRef } from 'react'
|
|
2
|
+
import { useStore } from '@tanstack/react-store'
|
|
3
|
+
import { Send, X } from 'lucide-react'
|
|
4
|
+
import ReactMarkdown from 'react-markdown'
|
|
5
|
+
import rehypeRaw from 'rehype-raw'
|
|
6
|
+
import rehypeSanitize from 'rehype-sanitize'
|
|
7
|
+
import rehypeHighlight from 'rehype-highlight'
|
|
8
|
+
import remarkGfm from 'remark-gfm'
|
|
9
|
+
import { useChat } from '@ai-sdk/react'
|
|
10
|
+
import { genAIResponse } from '../utils/demo.ai'
|
|
11
|
+
|
|
12
|
+
import { showAIAssistant } from '../store/example-assistant'
|
|
13
|
+
import GuitarRecommendation from './example-GuitarRecommendation'
|
|
14
|
+
|
|
15
|
+
import type { UIMessage } from 'ai'
|
|
16
|
+
|
|
17
|
+
function Messages({ messages }: { messages: Array<UIMessage> }) {
|
|
18
|
+
const messagesContainerRef = useRef<HTMLDivElement>(null)
|
|
19
|
+
|
|
20
|
+
useEffect(() => {
|
|
21
|
+
if (messagesContainerRef.current) {
|
|
22
|
+
messagesContainerRef.current.scrollTop =
|
|
23
|
+
messagesContainerRef.current.scrollHeight
|
|
24
|
+
}
|
|
25
|
+
}, [messages])
|
|
26
|
+
|
|
27
|
+
if (!messages.length) {
|
|
28
|
+
return (
|
|
29
|
+
<div className="flex-1 flex items-center justify-center text-gray-400 text-sm">
|
|
30
|
+
Ask me anything! I'm here to help.
|
|
31
|
+
</div>
|
|
32
|
+
)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return (
|
|
36
|
+
<div ref={messagesContainerRef} className="flex-1 overflow-y-auto">
|
|
37
|
+
{messages.map(({ id, role, content, parts }) => (
|
|
38
|
+
<div
|
|
39
|
+
key={id}
|
|
40
|
+
className={`py-3 ${
|
|
41
|
+
role === 'assistant'
|
|
42
|
+
? 'bg-gradient-to-r from-orange-500/5 to-red-600/5'
|
|
43
|
+
: 'bg-transparent'
|
|
44
|
+
}`}
|
|
45
|
+
>
|
|
46
|
+
{content.length > 0 && (
|
|
47
|
+
<div className="flex items-start gap-2 px-4">
|
|
48
|
+
{role === 'assistant' ? (
|
|
49
|
+
<div className="w-6 h-6 rounded-lg bg-gradient-to-r from-orange-500 to-red-600 flex items-center justify-center text-xs font-medium text-white flex-shrink-0">
|
|
50
|
+
AI
|
|
51
|
+
</div>
|
|
52
|
+
) : (
|
|
53
|
+
<div className="w-6 h-6 rounded-lg bg-gray-700 flex items-center justify-center text-xs font-medium text-white flex-shrink-0">
|
|
54
|
+
Y
|
|
55
|
+
</div>
|
|
56
|
+
)}
|
|
57
|
+
<div className="flex-1 min-w-0">
|
|
58
|
+
<ReactMarkdown
|
|
59
|
+
className="prose dark:prose-invert max-w-none prose-sm"
|
|
60
|
+
rehypePlugins={[
|
|
61
|
+
rehypeRaw,
|
|
62
|
+
rehypeSanitize,
|
|
63
|
+
rehypeHighlight,
|
|
64
|
+
remarkGfm,
|
|
65
|
+
]}
|
|
66
|
+
>
|
|
67
|
+
{content}
|
|
68
|
+
</ReactMarkdown>
|
|
69
|
+
</div>
|
|
70
|
+
</div>
|
|
71
|
+
)}
|
|
72
|
+
{parts
|
|
73
|
+
.filter((part) => part.type === 'tool-invocation')
|
|
74
|
+
.filter(
|
|
75
|
+
(part) => part.toolInvocation.toolName === 'recommendGuitar',
|
|
76
|
+
)
|
|
77
|
+
.map((toolCall) => (
|
|
78
|
+
<div
|
|
79
|
+
key={toolCall.toolInvocation.toolName}
|
|
80
|
+
className="max-w-[80%] mx-auto"
|
|
81
|
+
>
|
|
82
|
+
<GuitarRecommendation id={toolCall.toolInvocation.args.id} />
|
|
83
|
+
</div>
|
|
84
|
+
))}
|
|
85
|
+
</div>
|
|
86
|
+
))}
|
|
87
|
+
</div>
|
|
88
|
+
)
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export default function AIAssistant() {
|
|
92
|
+
const isOpen = useStore(showAIAssistant)
|
|
93
|
+
const { messages, input, handleInputChange, handleSubmit } = useChat({
|
|
94
|
+
initialMessages: [],
|
|
95
|
+
fetch: (_url, options) => {
|
|
96
|
+
const { messages } = JSON.parse(options!.body! as string)
|
|
97
|
+
return genAIResponse({
|
|
98
|
+
data: {
|
|
99
|
+
messages,
|
|
100
|
+
},
|
|
101
|
+
})
|
|
102
|
+
},
|
|
103
|
+
onToolCall: (call) => {
|
|
104
|
+
if (call.toolCall.toolName === 'recommendGuitar') {
|
|
105
|
+
return 'Handled by the UI'
|
|
106
|
+
}
|
|
107
|
+
},
|
|
108
|
+
})
|
|
109
|
+
|
|
110
|
+
return (
|
|
111
|
+
<div className="relative z-50">
|
|
112
|
+
<button
|
|
113
|
+
onClick={() => showAIAssistant.setState((state) => !state)}
|
|
114
|
+
className="flex items-center gap-2 px-3 py-1 rounded-lg bg-gradient-to-r from-orange-500 to-red-600 text-white hover:opacity-90 transition-opacity"
|
|
115
|
+
>
|
|
116
|
+
<div className="w-5 h-5 rounded-lg bg-white/20 flex items-center justify-center text-xs font-medium">
|
|
117
|
+
AI
|
|
118
|
+
</div>
|
|
119
|
+
AI Assistant
|
|
120
|
+
</button>
|
|
121
|
+
|
|
122
|
+
{isOpen && (
|
|
123
|
+
<div className="absolute top-full right-0 mt-2 w-[700px] h-[600px] bg-gray-900 rounded-lg shadow-xl border border-orange-500/20 flex flex-col">
|
|
124
|
+
<div className="flex items-center justify-between p-3 border-b border-orange-500/20">
|
|
125
|
+
<h3 className="font-semibold text-white">AI Assistant</h3>
|
|
126
|
+
<button
|
|
127
|
+
onClick={() => showAIAssistant.setState((state) => !state)}
|
|
128
|
+
className="text-gray-400 hover:text-white transition-colors"
|
|
129
|
+
>
|
|
130
|
+
<X className="w-4 h-4" />
|
|
131
|
+
</button>
|
|
132
|
+
</div>
|
|
133
|
+
|
|
134
|
+
<Messages messages={messages} />
|
|
135
|
+
|
|
136
|
+
<div className="p-3 border-t border-orange-500/20">
|
|
137
|
+
<form onSubmit={handleSubmit}>
|
|
138
|
+
<div className="relative">
|
|
139
|
+
<textarea
|
|
140
|
+
value={input}
|
|
141
|
+
onChange={handleInputChange}
|
|
142
|
+
placeholder="Type your message..."
|
|
143
|
+
className="w-full rounded-lg border border-orange-500/20 bg-gray-800/50 pl-3 pr-10 py-2 text-sm text-white placeholder-gray-400 focus:outline-none focus:ring-2 focus:ring-orange-500/50 focus:border-transparent resize-none overflow-hidden"
|
|
144
|
+
rows={1}
|
|
145
|
+
style={{ minHeight: '36px', maxHeight: '120px' }}
|
|
146
|
+
onInput={(e) => {
|
|
147
|
+
const target = e.target as HTMLTextAreaElement
|
|
148
|
+
target.style.height = 'auto'
|
|
149
|
+
target.style.height =
|
|
150
|
+
Math.min(target.scrollHeight, 120) + 'px'
|
|
151
|
+
}}
|
|
152
|
+
onKeyDown={(e) => {
|
|
153
|
+
if (e.key === 'Enter' && !e.shiftKey) {
|
|
154
|
+
e.preventDefault()
|
|
155
|
+
handleSubmit(e)
|
|
156
|
+
}
|
|
157
|
+
}}
|
|
158
|
+
/>
|
|
159
|
+
<button
|
|
160
|
+
type="submit"
|
|
161
|
+
disabled={!input.trim()}
|
|
162
|
+
className="absolute right-2 top-1/2 -translate-y-1/2 p-1.5 text-orange-500 hover:text-orange-400 disabled:text-gray-500 transition-colors focus:outline-none"
|
|
163
|
+
>
|
|
164
|
+
<Send className="w-4 h-4" />
|
|
165
|
+
</button>
|
|
166
|
+
</div>
|
|
167
|
+
</form>
|
|
168
|
+
</div>
|
|
169
|
+
</div>
|
|
170
|
+
)}
|
|
171
|
+
</div>
|
|
172
|
+
)
|
|
173
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { useNavigate } from '@tanstack/react-router'
|
|
2
|
+
|
|
3
|
+
import { showAIAssistant } from '../store/example-assistant'
|
|
4
|
+
|
|
5
|
+
import guitars from '../data/example-guitars'
|
|
6
|
+
|
|
7
|
+
export default function GuitarRecommendation({ id }: { id: string }) {
|
|
8
|
+
const navigate = useNavigate()
|
|
9
|
+
const guitar = guitars.find((guitar) => guitar.id === +id)
|
|
10
|
+
if (!guitar) {
|
|
11
|
+
return null
|
|
12
|
+
}
|
|
13
|
+
return (
|
|
14
|
+
<div className="my-4 rounded-lg overflow-hidden border border-orange-500/20 bg-gray-800/50">
|
|
15
|
+
<div className="aspect-[4/3] relative overflow-hidden">
|
|
16
|
+
<img
|
|
17
|
+
src={guitar.image}
|
|
18
|
+
alt={guitar.name}
|
|
19
|
+
className="w-full h-full object-cover"
|
|
20
|
+
/>
|
|
21
|
+
</div>
|
|
22
|
+
<div className="p-4">
|
|
23
|
+
<h3 className="text-lg font-semibold text-white mb-2">{guitar.name}</h3>
|
|
24
|
+
<p className="text-sm text-gray-300 mb-3 line-clamp-2">
|
|
25
|
+
{guitar.shortDescription}
|
|
26
|
+
</p>
|
|
27
|
+
<div className="flex items-center justify-between">
|
|
28
|
+
<div className="text-lg font-bold text-emerald-400">
|
|
29
|
+
${guitar.price}
|
|
30
|
+
</div>
|
|
31
|
+
<button
|
|
32
|
+
onClick={() => {
|
|
33
|
+
navigate({
|
|
34
|
+
to: '/example/guitars/$guitarId',
|
|
35
|
+
params: { guitarId: guitar.id.toString() },
|
|
36
|
+
})
|
|
37
|
+
showAIAssistant.setState(() => false)
|
|
38
|
+
}}
|
|
39
|
+
className="bg-gradient-to-r from-orange-500 to-red-600 text-white px-4 py-1.5 rounded-lg text-sm hover:opacity-90 transition-opacity"
|
|
40
|
+
>
|
|
41
|
+
View Details
|
|
42
|
+
</button>
|
|
43
|
+
</div>
|
|
44
|
+
</div>
|
|
45
|
+
</div>
|
|
46
|
+
)
|
|
47
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
export interface Guitar {
|
|
2
|
+
id: number
|
|
3
|
+
name: string
|
|
4
|
+
image: string
|
|
5
|
+
description: string
|
|
6
|
+
shortDescription: string
|
|
7
|
+
price: number
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const guitars: Array<Guitar> = [
|
|
11
|
+
{
|
|
12
|
+
id: 1,
|
|
13
|
+
name: 'Video Game Guitar',
|
|
14
|
+
image: '/example-guitar-video-games.jpg',
|
|
15
|
+
description:
|
|
16
|
+
"The Video Game Guitar is a unique acoustic guitar that features a design inspired by video games. It has a sleek, high-gloss finish and a comfortable playability. The guitar's ergonomic body and fast neck profile ensure comfortable playability for hours on end.",
|
|
17
|
+
shortDescription:
|
|
18
|
+
'A unique electric guitar with a video game design, high-gloss finish, and comfortable playability.',
|
|
19
|
+
price: 699,
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
id: 2,
|
|
23
|
+
name: 'Superhero Guitar',
|
|
24
|
+
image: '/example-guitar-superhero.jpg',
|
|
25
|
+
description:
|
|
26
|
+
"The Superhero Guitar is a bold black electric guitar that stands out with its unique superhero logo design. Its sleek, high-gloss finish and powerful pickups make it perfect for high-energy performances. The guitar's ergonomic body and fast neck profile ensure comfortable playability for hours on end.",
|
|
27
|
+
shortDescription:
|
|
28
|
+
'A bold black electric guitar with a unique superhero logo, high-gloss finish, and powerful pickups.',
|
|
29
|
+
price: 699,
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
id: 3,
|
|
33
|
+
name: 'Motherboard Guitar',
|
|
34
|
+
image: '/example-guitar-motherboard.jpg',
|
|
35
|
+
description:
|
|
36
|
+
"This guitar is a tribute to the motherboard of a computer. It's a unique and stylish instrument that will make you feel like a hacker. The intricate circuit-inspired design features actual LED lights that pulse with your playing intensity, while the neck is inlaid with binary code patterns that glow under stage lights. Each pickup has been custom-wound to produce tones ranging from clean digital precision to glitched-out distortion, perfect for electronic music fusion. The Motherboard Guitar seamlessly bridges the gap between traditional craftsmanship and cutting-edge technology, making it the ultimate instrument for the digital age musician.",
|
|
37
|
+
shortDescription:
|
|
38
|
+
'A tech-inspired electric guitar featuring LED lights and binary code inlays that glow under stage lights.',
|
|
39
|
+
price: 649,
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
id: 4,
|
|
43
|
+
name: 'Racing Guitar',
|
|
44
|
+
image: '/example-guitar-racing.jpg',
|
|
45
|
+
description:
|
|
46
|
+
"Engineered for speed and precision, the Racing Guitar embodies the spirit of motorsport in every curve and contour. Its aerodynamic body, painted in classic racing stripes and high-gloss finish, is crafted from lightweight materials that allow for effortless play during extended performances. The custom low-action setup and streamlined neck profile enable lightning-fast fretwork, while specially designed pickups deliver a high-octane tone that cuts through any mix. Built with performance-grade hardware including racing-inspired control knobs and checkered flag inlays, this guitar isn't just played—it's driven to the limits of musical possibility.",
|
|
47
|
+
shortDescription:
|
|
48
|
+
'A lightweight, aerodynamic guitar with racing stripes and a low-action setup designed for speed and precision.',
|
|
49
|
+
price: 679,
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
id: 5,
|
|
53
|
+
name: 'Steamer Trunk Guitar',
|
|
54
|
+
image: '/example-guitar-steamer-trunk.jpg',
|
|
55
|
+
description:
|
|
56
|
+
'The Steamer Trunk Guitar is a semi-hollow body instrument that exudes vintage charm and character. Crafted from reclaimed antique luggage wood, it features brass hardware that adds a touch of elegance and durability. The fretboard is adorned with a world map inlay, making it a unique piece that tells a story of travel and adventure.',
|
|
57
|
+
shortDescription:
|
|
58
|
+
'A semi-hollow body guitar with brass hardware and a world map inlay, crafted from reclaimed antique luggage wood.',
|
|
59
|
+
price: 629,
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
id: 6,
|
|
63
|
+
name: "Travelin' Man Guitar",
|
|
64
|
+
image: '/example-guitar-traveling.jpg',
|
|
65
|
+
description:
|
|
66
|
+
"The Travelin' Man Guitar is an acoustic masterpiece adorned with vintage postcards from around the world. Each postcard tells a story of adventure and wanderlust, making this guitar a unique piece of art. Its rich, resonant tones and comfortable playability make it perfect for musicians who love to travel and perform.",
|
|
67
|
+
shortDescription:
|
|
68
|
+
'An acoustic guitar with vintage postcards, rich tones, and comfortable playability.',
|
|
69
|
+
price: 499,
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
id: 7,
|
|
73
|
+
name: 'Flowerly Love Guitar',
|
|
74
|
+
image: '/example-guitar-flowers.jpg',
|
|
75
|
+
description:
|
|
76
|
+
"The Flowerly Love Guitar is an acoustic masterpiece adorned with intricate floral designs on its body. Each flower is hand-painted, adding a touch of nature's beauty to the instrument. Its warm, resonant tones make it perfect for both intimate performances and larger gatherings.",
|
|
77
|
+
shortDescription:
|
|
78
|
+
'An acoustic guitar with hand-painted floral designs and warm, resonant tones.',
|
|
79
|
+
price: 599,
|
|
80
|
+
},
|
|
81
|
+
]
|
|
82
|
+
|
|
83
|
+
export default guitars
|