Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 43 additions & 0 deletions frameworks/react-cra/add-ons/start/assets/src/demo.start.css.ejs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<% if (tailwind) { ignoreFile() } %>.api-page {
display: flex;
align-items: center;
justify-content: center;
min-height: 100vh;
padding: 1rem;
color: #fff;
}

.api-page .content {
width: 100%;
max-width: 2xl;
padding: 8rem;
border-radius: 1rem;
backdrop-filter: blur(1rem);
background-color: rgba(0, 0, 0, 0.5);
box-shadow: 0 0 1rem 0 rgba(0, 0, 0, 0.1);
border: 0.5rem solid rgba(0, 0, 0, 0.1);
}

.api-page .content h1 {
font-size: 2rem;
margin-bottom: 1rem;
}

.api-page .content ul {
margin-bottom: 1rem;
list-style: none;
padding: 0;
}

.api-page .content li {
background-color: rgba(255, 255, 255, 0.1);
padding: 0.5rem;
border-radius: 0.5rem;
border: 1px solid rgba(255, 255, 255, 0.2);
backdrop-filter: blur(0.5rem);
box-shadow: 0 0 0.5rem 0 rgba(255, 255, 255, 0.1);
}

.api-page .content li span {
font-size: 1.2rem;
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ import { useQuery } from '@tanstack/react-query'
<% } else { %>
import { useEffect, useState } from 'react'
<% } %>
import { createFileRoute } from '@tanstack/react-router'
import { createFileRoute } from '@tanstack/react-router'<% if (!tailwind) { %>
import '../demo.start.css'
<% } %>

function getNames() {
return fetch('/api/demo-names').then((res) => res.json())
Expand All @@ -27,6 +29,7 @@ function Home() {
}, [])
<% } %>
return (
<% if (tailwind) { %>
<div
className="flex items-center justify-center min-h-screen p-4 text-white"
style={{
Expand All @@ -49,5 +52,17 @@ function Home() {
</ul>
</div>
</div>
<% } else { %>
<div className="api-page">
<div className="content">
<h1>Start API Request Demo - Names List</h1>
<ul>
{names.map((name) => (
<li key={name}>{name}</li>
))}
</ul>
</div>
</div>
<% } %>
)
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import fs from 'node:fs'
import { useCallback, useState } from 'react'
import { createFileRoute, useRouter } from '@tanstack/react-router'
import { createServerFn } from '@tanstack/react-start'
import { createServerFn } from '@tanstack/react-start'<% if (!tailwind) { %>
import '../demo.start.css'
<% } %>

const filePath = 'todos.json'

Expand Down Expand Up @@ -51,6 +53,7 @@ function Home() {
}, [addTodo, todo])

return (
<% if (tailwind) { %>
<div
className="flex items-center justify-center min-h-screen bg-gradient-to-br from-zinc-800 to-black p-4 text-white"
style={{
Expand Down Expand Up @@ -93,5 +96,34 @@ function Home() {
</div>
</div>
</div>
<% } else { %>
<div>
<h1>Start Server Functions - Todo Example</h1>
<ul>
{todos?.map((t) => (
<li key={t.id}>{t.name}</li>
))}
</ul>
<div className="flex flex-col gap-2">
<input
type="text"
value={todo}
onChange={(e) => setTodo(e.target.value)}
onKeyDown={(e) => {
if (e.key === 'Enter') {
submitTodo()
}
}}
placeholder="Enter a new todo..."
/>
<button
disabled={todo.trim().length === 0}
onClick={submitTodo}
>
Add todo
</button>
</div>
</div>
<% } %>
)
}
7 changes: 2 additions & 5 deletions frameworks/react-cra/add-ons/start/info.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"link": "https://tanstack.com/start/latest",
"modes": ["file-router"],
"type": "add-on",
"tailwind": false,
"warning": "TanStack Start is not yet at 1.0 and may change significantly or not be compatible with other add-ons.\nMigrating to Start might require deleting node_modules and re-installing.",
"routes": [
{
Expand All @@ -20,10 +21,6 @@
"jsName": "StartApiRequestDemo"
}
],
"deletedFiles": [
"./index.html",
"./src/main.tsx",
"./src/App.css"
],
"deletedFiles": ["./index.html", "./src/main.tsx"],
"addOnSpecialSteps": ["rimraf-node-modules"]
}
18 changes: 18 additions & 0 deletions frameworks/react-cra/project/base/src/components/Header.css.ejs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<% if (tailwind) { ignoreFile() } %>.header {
padding: 0.5rem;
display: flex;
gap: 0.5rem;
background-color: #fff;
color: #000;
justify-content: space-between;
}

.nav {
display: flex;
flex-direction: row;
}

.nav-item {
padding: 0 0.5rem;
font-weight: bold;
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,20 @@
<% if (addOns.length === 0 && integrations.length === 0 && routes.length === 0) { ignoreFile() } %>import { Link } from '@tanstack/react-router'
<% for(const integration of integrations.filter(i => i.type === 'header-user')) { %>
import <%= integration.jsName %> from "<%= relativePath(integration.path) %>";
<% } %>
<% } %><% if (!tailwind) { %>
import './Header.css'<% } %>

export default function Header() {
return (
<% if (tailwind) { %>
<header className="p-2 flex gap-2 bg-white text-black justify-between">
<nav className="flex flex-row">
<div className="px-2 font-bold">
<% } else { %>
<header className="header">
<nav className="nav">
<div className="nav-item">
<% } %>
<Link to="/">Home</Link>
</div>
<% for(const addOn of addOns) {
Expand Down
3 changes: 1 addition & 2 deletions frameworks/react-cra/project/base/src/routes/index.tsx.ejs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
<% if (codeRouter) { ignoreFile() } %>
import { createFileRoute } from "@tanstack/react-router";
<% if (codeRouter) { ignoreFile() } %>import { createFileRoute } from "@tanstack/react-router";
import logo from "../logo.svg";<% if (!tailwind) { %>
import "../App.css";
<% } %>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
"/public/manifest.json": "{\n \"short_name\": \"TanStack App\",\n \"name\": \"Create TanStack App Sample\",\n \"icons\": [\n {\n \"src\": \"favicon.ico\",\n \"sizes\": \"64x64 32x32 24x24 16x16\",\n \"type\": \"image/x-icon\"\n },\n {\n \"src\": \"logo192.png\",\n \"type\": \"image/png\",\n \"sizes\": \"192x192\"\n },\n {\n \"src\": \"logo512.png\",\n \"type\": \"image/png\",\n \"sizes\": \"512x512\"\n }\n ],\n \"start_url\": \".\",\n \"display\": \"standalone\",\n \"theme_color\": \"#000000\",\n \"background_color\": \"#ffffff\"\n}\n",
"/public/robots.txt": "# https://www.robotstxt.org/robotstxt.html\nUser-agent: *\nDisallow:\n",
"/src/App.css": ".App {\n text-align: center;\n}\n\n.App-logo {\n height: 40vmin;\n pointer-events: none;\n}\n\n@media (prefers-reduced-motion: no-preference) {\n .App-logo {\n animation: App-logo-spin infinite 20s linear;\n }\n}\n\n.App-header {\n background-color: #282c34;\n min-height: 100vh;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n font-size: calc(10px + 2vmin);\n color: white;\n}\n\n.App-link {\n color: #61dafb;\n}\n\n@keyframes App-logo-spin {\n from {\n transform: rotate(0deg);\n }\n to {\n transform: rotate(360deg);\n }\n}\n",
"/src/components/Header.jsx": "import { Link } from '@tanstack/react-router'\n\nexport default function Header() {\n return (\n <header className=\"p-2 flex gap-2 bg-white text-black justify-between\">\n <nav className=\"flex flex-row\">\n <div className=\"px-2 font-bold\">\n <Link to=\"/\">Home</Link>\n </div>\n\n <div className=\"px-2 font-bold\">\n <Link to=\"/demo/form/simple\">Simple Form</Link>\n </div>\n\n <div className=\"px-2 font-bold\">\n <Link to=\"/demo/form/address\">Address Form</Link>\n </div>\n </nav>\n </header>\n )\n}\n",
"/src/components/Header.css": ".header {\n padding: 0.5rem;\n display: flex;\n gap: 0.5rem;\n background-color: #fff;\n color: #000;\n justify-content: space-between;\n}\n\n.nav {\n display: flex;\n flex-direction: row;\n}\n\n.nav-item {\n padding: 0 0.5rem;\n font-weight: bold;\n}",
"/src/components/Header.jsx": "import { Link } from '@tanstack/react-router'\n\nimport './Header.css'\n\nexport default function Header() {\n return (\n <header className=\"header\">\n <nav className=\"nav\">\n <div className=\"nav-item\">\n <Link to=\"/\">Home</Link>\n </div>\n\n <div className=\"px-2 font-bold\">\n <Link to=\"/demo/form/simple\">Simple Form</Link>\n </div>\n\n <div className=\"px-2 font-bold\">\n <Link to=\"/demo/form/address\">Address Form</Link>\n </div>\n </nav>\n </header>\n )\n}\n",
"/src/components/demo.FormComponents.jsx": "import { useStore } from '@tanstack/react-form'\n\nimport { useFieldContext, useFormContext } from '../hooks/demo.form-context'\n\nexport function SubscribeButton({ label }: { label: string }) {\n const form = useFormContext()\n return (\n <form.Subscribe selector={(state) => state.isSubmitting}>\n {(isSubmitting) => (\n <button\n type=\"submit\"\n disabled={isSubmitting}\n className=\"px-6 py-2 bg-indigo-600 text-white rounded-md hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 transition-colors disabled:opacity-50\"\n >\n {label}\n </button>\n )}\n </form.Subscribe>\n )\n}\n\nfunction ErrorMessages({\n errors,\n}: {\n errors: Array<string | { message: string }>\n}) {\n return (\n <>\n {errors.map((error) => (\n <div\n key={typeof error === 'string' ? error : error.message}\n className=\"text-red-500 mt-1 font-bold\"\n >\n {typeof error === 'string' ? error : error.message}\n </div>\n ))}\n </>\n )\n}\n\nexport function TextField({\n label,\n placeholder,\n}: {\n label: string\n placeholder?: string\n}) {\n const field = useFieldContext<string>()\n const errors = useStore(field.store, (state) => state.meta.errors)\n\n return (\n <div>\n <label htmlFor={label} className=\"block font-bold mb-1 text-xl\">\n {label}\n <input\n value={field.state.value}\n placeholder={placeholder}\n onBlur={field.handleBlur}\n onChange={(e) => field.handleChange(e.target.value)}\n className=\"w-full px-4 py-2 rounded-md border border-gray-300 focus:outline-none focus:ring-2 focus:ring-indigo-500\"\n />\n </label>\n {field.state.meta.isTouched && <ErrorMessages errors={errors} />}\n </div>\n )\n}\n\nexport function TextArea({\n label,\n rows = 3,\n}: {\n label: string\n rows?: number\n}) {\n const field = useFieldContext<string>()\n const errors = useStore(field.store, (state) => state.meta.errors)\n\n return (\n <div>\n <label htmlFor={label} className=\"block font-bold mb-1 text-xl\">\n {label}\n <textarea\n value={field.state.value}\n onBlur={field.handleBlur}\n rows={rows}\n onChange={(e) => field.handleChange(e.target.value)}\n className=\"w-full px-4 py-2 rounded-md border border-gray-300 focus:outline-none focus:ring-2 focus:ring-indigo-500\"\n />\n </label>\n {field.state.meta.isTouched && <ErrorMessages errors={errors} />}\n </div>\n )\n}\n\nexport function Select({\n label,\n values,\n}: {\n label: string\n values: Array<{ label: string; value: string }>\n placeholder?: string\n}) {\n const field = useFieldContext<string>()\n const errors = useStore(field.store, (state) => state.meta.errors)\n\n return (\n <div>\n <label htmlFor={label} className=\"block font-bold mb-1 text-xl\">\n {label}\n </label>\n <select\n name={field.name}\n value={field.state.value}\n onBlur={field.handleBlur}\n onChange={(e) => field.handleChange(e.target.value)}\n className=\"w-full px-4 py-2 rounded-md border border-gray-300 focus:outline-none focus:ring-2 focus:ring-indigo-500\"\n >\n {values.map((value) => (\n <option key={value.value} value={value.value}>\n {value.label}\n </option>\n ))}\n </select>\n {field.state.meta.isTouched && <ErrorMessages errors={errors} />}\n </div>\n )\n}\n",
"/src/hooks/demo.form-context.js": "import { createFormHookContexts } from '@tanstack/react-form'\n\nexport const { fieldContext, useFieldContext, formContext, useFormContext } =\n createFormHookContexts()\n",
"/src/hooks/demo.form.js": "import { createFormHook } from '@tanstack/react-form'\n\nimport {\n Select,\n SubscribeButton,\n TextArea,\n TextField,\n} from '../components/demo.FormComponents'\nimport { fieldContext, formContext } from './demo.form-context'\n\nexport const { useAppForm } = createFormHook({\n fieldComponents: {\n TextField,\n Select,\n TextArea,\n },\n formComponents: {\n SubscribeButton,\n },\n fieldContext,\n formContext,\n})\n",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"/public/manifest.json": "{\n \"short_name\": \"TanStack App\",\n \"name\": \"Create TanStack App Sample\",\n \"icons\": [\n {\n \"src\": \"favicon.ico\",\n \"sizes\": \"64x64 32x32 24x24 16x16\",\n \"type\": \"image/x-icon\"\n },\n {\n \"src\": \"logo192.png\",\n \"type\": \"image/png\",\n \"sizes\": \"192x192\"\n },\n {\n \"src\": \"logo512.png\",\n \"type\": \"image/png\",\n \"sizes\": \"512x512\"\n }\n ],\n \"start_url\": \".\",\n \"display\": \"standalone\",\n \"theme_color\": \"#000000\",\n \"background_color\": \"#ffffff\"\n}\n",
"/public/robots.txt": "# https://www.robotstxt.org/robotstxt.html\nUser-agent: *\nDisallow:\n",
"/src/App.css": ".App {\n text-align: center;\n}\n\n.App-logo {\n height: 40vmin;\n pointer-events: none;\n}\n\n@media (prefers-reduced-motion: no-preference) {\n .App-logo {\n animation: App-logo-spin infinite 20s linear;\n }\n}\n\n.App-header {\n background-color: #282c34;\n min-height: 100vh;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n font-size: calc(10px + 2vmin);\n color: white;\n}\n\n.App-link {\n color: #61dafb;\n}\n\n@keyframes App-logo-spin {\n from {\n transform: rotate(0deg);\n }\n to {\n transform: rotate(360deg);\n }\n}\n",
"/src/components/Header.css": ".header {\n padding: 0.5rem;\n display: flex;\n gap: 0.5rem;\n background-color: #fff;\n color: #000;\n justify-content: space-between;\n}\n\n.nav {\n display: flex;\n flex-direction: row;\n}\n\n.nav-item {\n padding: 0 0.5rem;\n font-weight: bold;\n}",
"/src/main.jsx": "import { StrictMode } from 'react'\nimport ReactDOM from 'react-dom/client'\nimport { RouterProvider, createRouter } from '@tanstack/react-router'\n\n// Import the generated route tree\nimport { routeTree } from './routeTree.gen'\n\nimport './styles.css'\nimport reportWebVitals from './reportWebVitals.js'\n\n// Create a new router instance\nconst router = createRouter({\n routeTree,\n context: {},\n defaultPreload: 'intent',\n scrollRestoration: true,\n defaultStructuralSharing: true,\n defaultPreloadStaleTime: 0,\n})\n\n// Register the router instance for type safety\ndeclare module '@tanstack/react-router' {\n interface Register {\n router: typeof router\n }\n}\n\n// Render the app\nconst rootElement = document.getElementById('app')\nif (rootElement && !rootElement.innerHTML) {\n const root = ReactDOM.createRoot(rootElement)\n root.render(\n <StrictMode>\n <RouterProvider router={router} />\n </StrictMode>,\n )\n}\n\n// If you want to start measuring performance in your app, pass a function\n// to log results (for example: reportWebVitals(console.log))\n// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals\nreportWebVitals()\n",
"/src/reportWebVitals.js": "const reportWebVitals = (onPerfEntry) => {\n if (onPerfEntry && onPerfEntry instanceof Function) {\n import('web-vitals').then(({ onCLS, onINP, onFCP, onLCP, onTTFB }) => {\n onCLS(onPerfEntry)\n onINP(onPerfEntry)\n onFCP(onPerfEntry)\n onLCP(onPerfEntry)\n onTTFB(onPerfEntry)\n })\n }\n}\n\nexport default reportWebVitals\n",
"/src/routes/__root.jsx": "import { Outlet, createRootRoute } from '@tanstack/react-router'\nimport { TanStackRouterDevtoolsPanel } from '@tanstack/react-router-devtools'\nimport { TanstackDevtools } from '@tanstack/react-devtools'\n\nexport const Route = createRootRoute({\n component: () => (\n <>\n <Outlet />\n <TanstackDevtools\n config={{\n position: 'bottom-left',\n }}\n plugins={[\n {\n name: 'Tanstack Router',\n render: <TanStackRouterDevtoolsPanel />,\n },\n ]}\n />\n </>\n ),\n})\n",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"/public/manifest.json": "{\n \"short_name\": \"TanStack App\",\n \"name\": \"Create TanStack App Sample\",\n \"icons\": [\n {\n \"src\": \"favicon.ico\",\n \"sizes\": \"64x64 32x32 24x24 16x16\",\n \"type\": \"image/x-icon\"\n },\n {\n \"src\": \"logo192.png\",\n \"type\": \"image/png\",\n \"sizes\": \"192x192\"\n },\n {\n \"src\": \"logo512.png\",\n \"type\": \"image/png\",\n \"sizes\": \"512x512\"\n }\n ],\n \"start_url\": \".\",\n \"display\": \"standalone\",\n \"theme_color\": \"#000000\",\n \"background_color\": \"#ffffff\"\n}\n",
"/public/robots.txt": "# https://www.robotstxt.org/robotstxt.html\nUser-agent: *\nDisallow:\n",
"/src/App.css": ".App {\n text-align: center;\n}\n\n.App-logo {\n height: 40vmin;\n pointer-events: none;\n}\n\n@media (prefers-reduced-motion: no-preference) {\n .App-logo {\n animation: App-logo-spin infinite 20s linear;\n }\n}\n\n.App-header {\n background-color: #282c34;\n min-height: 100vh;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n font-size: calc(10px + 2vmin);\n color: white;\n}\n\n.App-link {\n color: #61dafb;\n}\n\n@keyframes App-logo-spin {\n from {\n transform: rotate(0deg);\n }\n to {\n transform: rotate(360deg);\n }\n}\n",
"/src/components/Header.css": ".header {\n padding: 0.5rem;\n display: flex;\n gap: 0.5rem;\n background-color: #fff;\n color: #000;\n justify-content: space-between;\n}\n\n.nav {\n display: flex;\n flex-direction: row;\n}\n\n.nav-item {\n padding: 0 0.5rem;\n font-weight: bold;\n}",
"/src/main.tsx": "import { StrictMode } from 'react'\nimport ReactDOM from 'react-dom/client'\nimport { RouterProvider, createRouter } from '@tanstack/react-router'\n\n// Import the generated route tree\nimport { routeTree } from './routeTree.gen'\n\nimport './styles.css'\nimport reportWebVitals from './reportWebVitals.ts'\n\n// Create a new router instance\nconst router = createRouter({\n routeTree,\n context: {},\n defaultPreload: 'intent',\n scrollRestoration: true,\n defaultStructuralSharing: true,\n defaultPreloadStaleTime: 0,\n})\n\n// Register the router instance for type safety\ndeclare module '@tanstack/react-router' {\n interface Register {\n router: typeof router\n }\n}\n\n// Render the app\nconst rootElement = document.getElementById('app')\nif (rootElement && !rootElement.innerHTML) {\n const root = ReactDOM.createRoot(rootElement)\n root.render(\n <StrictMode>\n <RouterProvider router={router} />\n </StrictMode>,\n )\n}\n\n// If you want to start measuring performance in your app, pass a function\n// to log results (for example: reportWebVitals(console.log))\n// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals\nreportWebVitals()\n",
"/src/reportWebVitals.ts": "const reportWebVitals = (onPerfEntry?: () => void) => {\n if (onPerfEntry && onPerfEntry instanceof Function) {\n import('web-vitals').then(({ onCLS, onINP, onFCP, onLCP, onTTFB }) => {\n onCLS(onPerfEntry)\n onINP(onPerfEntry)\n onFCP(onPerfEntry)\n onLCP(onPerfEntry)\n onTTFB(onPerfEntry)\n })\n }\n}\n\nexport default reportWebVitals\n",
"/src/routes/__root.tsx": "import { Outlet, createRootRoute } from '@tanstack/react-router'\nimport { TanStackRouterDevtoolsPanel } from '@tanstack/react-router-devtools'\nimport { TanstackDevtools } from '@tanstack/react-devtools'\n\nexport const Route = createRootRoute({\n component: () => (\n <>\n <Outlet />\n <TanstackDevtools\n config={{\n position: 'bottom-left',\n }}\n plugins={[\n {\n name: 'Tanstack Router',\n render: <TanStackRouterDevtoolsPanel />,\n },\n ]}\n />\n </>\n ),\n})\n",
Expand Down
Loading