Skip to content

Commit

Permalink
feat: add goto, shows dynamic queries
Browse files Browse the repository at this point in the history
  • Loading branch information
stipsan committed Dec 10, 2024
1 parent 2335a98 commit bb5f667
Show file tree
Hide file tree
Showing 6 changed files with 152 additions and 12 deletions.
2 changes: 1 addition & 1 deletion tanstack-start/app/components/ThemeButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export function ThemeButton() {
await randomColorTheme()
})
}
className={`bg-theme-button text-theme-button focus:ring-theme focus:ring-offset-theme rounded-md px-4 py-2 text-sm font-semibold transition ease-in-out focus:outline-none focus:ring-2 focus:ring-opacity-50 focus:ring-offset-2 focus:duration-0 disabled:cursor-not-allowed disabled:opacity-50 ${pending ? 'animate-pulse cursor-wait duration-150' : 'duration-1000'} `}
className={`bg-theme-button text-theme-button focus:ring-theme focus:ring-offset-theme rounded-md px-4 py-2 text-sm font-semibold transition ease-in-out [view-transition-name:theme-button] focus:outline-none focus:ring-2 focus:ring-opacity-50 focus:ring-offset-2 focus:duration-0 disabled:cursor-not-allowed disabled:opacity-50 ${pending ? 'animate-pulse cursor-wait duration-150' : 'duration-1000'} `}
>
{pending ? 'Generating...' : 'Random Color Theme'}
</button>
Expand Down
37 changes: 30 additions & 7 deletions tanstack-start/app/routeTree.gen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,18 @@

// Import Routes

import {Route as rootRoute} from './routes/__root'
import {Route as IndexImport} from './routes/index'
import { Route as rootRoute } from './routes/__root'
import { Route as GotoImport } from './routes/goto'
import { Route as IndexImport } from './routes/index'

// Create/Update Routes

const GotoRoute = GotoImport.update({
id: '/goto',
path: '/goto',
getParentRoute: () => rootRoute,
} as any)

const IndexRoute = IndexImport.update({
id: '/',
path: '/',
Expand All @@ -32,39 +39,51 @@ declare module '@tanstack/react-router' {
preLoaderRoute: typeof IndexImport
parentRoute: typeof rootRoute
}
'/goto': {
id: '/goto'
path: '/goto'
fullPath: '/goto'
preLoaderRoute: typeof GotoImport
parentRoute: typeof rootRoute
}
}
}

// Create and export the route tree

export interface FileRoutesByFullPath {
'/': typeof IndexRoute
'/goto': typeof GotoRoute
}

export interface FileRoutesByTo {
'/': typeof IndexRoute
'/goto': typeof GotoRoute
}

export interface FileRoutesById {
'__root__': typeof rootRoute
__root__: typeof rootRoute
'/': typeof IndexRoute
'/goto': typeof GotoRoute
}

export interface FileRouteTypes {
fileRoutesByFullPath: FileRoutesByFullPath
fullPaths: '/'
fullPaths: '/' | '/goto'
fileRoutesByTo: FileRoutesByTo
to: '/'
id: '__root__' | '/'
to: '/' | '/goto'
id: '__root__' | '/' | '/goto'
fileRoutesById: FileRoutesById
}

export interface RootRouteChildren {
IndexRoute: typeof IndexRoute
GotoRoute: typeof GotoRoute
}

const rootRouteChildren: RootRouteChildren = {
IndexRoute: IndexRoute,
GotoRoute: GotoRoute,
}

export const routeTree = rootRoute
Expand All @@ -77,11 +96,15 @@ export const routeTree = rootRoute
"__root__": {
"filePath": "__root.tsx",
"children": [
"/"
"/",
"/goto"
]
},
"/": {
"filePath": "index.tsx"
},
"/goto": {
"filePath": "goto.tsx"
}
}
}
Expand Down
1 change: 1 addition & 0 deletions tanstack-start/app/router.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {routeTree} from './routeTree.gen'
export function createRouter() {
const router = createTanStackRouter({
routeTree,
defaultViewTransition: true,
})

return router
Expand Down
96 changes: 96 additions & 0 deletions tanstack-start/app/routes/goto.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import {createFileRoute, Link} from '@tanstack/react-router'
import {createServerFn} from '@tanstack/start'
import {zodValidator} from '@tanstack/zod-adapter'
import {defineQuery} from 'groq'
import {useEffect, useId} from 'react'
import {z} from 'zod'
import {sanityFetch} from '../utils/sanity'

const SEARCH_QUERY = defineQuery(`{
"title": *[_type == "demo" && slug.current == $slug][0].title,
"urls": *[_type == "demo" && slug.current != $slug && [title,slug.current,url] match "*"+$q+"*"]{title,url}
}`)

const getDemo = createServerFn({
method: 'GET',
})
.validator(
z.object({
lastLiveEventId: z.string().optional(),
slug: z.string(),
q: z.string(),
}),
)
.handler(({data: {slug, q, lastLiveEventId}}) => {
return sanityFetch({
query: SEARCH_QUERY,
params: {slug, q},
lastLiveEventId,
})
})

export const Route = createFileRoute('/goto')({
component: Home,
validateSearch: zodValidator(
z.object({
q: z.string().default(''),
}),
),
loaderDeps: ({search: {lastLiveEventId, q}}) => ({lastLiveEventId, q}),
loader: async ({deps: {lastLiveEventId, q}}) =>
await getDemo({data: {slug: 'tanstack-start', q, lastLiveEventId}}),
head: (ctx) => ({
meta: [{title: ctx.loaderData?.data?.title || 'TanStack Start Starter'}],
}),
})

function Home() {
const state = Route.useLoaderData()
const {q} = Route.useSearch()
const navigate = Route.useNavigate()
const id = useId()

// @TODO handle this server side
useEffect(() => {
if (!q) return
const validUrl = state.data.urls.find((item) => item.url && new URL(item.url).hostname === q)
if (validUrl?.url) {
location.href = validUrl.url
}
}, [state.data.urls, q])

return (
<>
<h1 className="text-balance text-4xl font-bold leading-tight tracking-tighter [view-transition-name:title] md:text-6xl lg:pr-8 lg:text-8xl">
<Link to="/">{state.data?.title || 'TanStack Start Starter'}</Link>
</h1>
<input
name="q"
type="search"
list={id}
placeholder="Go to..."
autoFocus
className="bg-theme text-theme ring-theme placeholder:text-theme w-56 rounded-md px-4 py-2 text-sm font-semibold ring-2 ring-opacity-75 [view-transition-name:search] focus:outline-none"
defaultValue={q}
onInput={(event) => {
const q = event.currentTarget.value
navigate({
search: (prev) => ({...prev, q}),
replace: true,
resetScroll: false,
})
}}
/>
<datalist id={id}>
{state.data.urls.map((item) => {
if (!item || !item.title || !item.url) return null
return (
<option key={item.url} value={new URL(item.url).hostname}>
{item.title}
</option>
)
})}
</datalist>
</>
)
}
16 changes: 12 additions & 4 deletions tanstack-start/app/routes/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {createFileRoute} from '@tanstack/react-router'
import {createFileRoute, Link} from '@tanstack/react-router'
import {createServerFn} from '@tanstack/start'
import {defineQuery} from 'groq'
import {z} from 'zod'
Expand Down Expand Up @@ -33,8 +33,16 @@ function Home() {
const state = Route.useLoaderData()

return (
<h1 className="text-balance text-4xl font-bold leading-tight tracking-tighter md:text-6xl lg:pr-8 lg:text-8xl">
{state.data || 'TanStack Start Starter'}
</h1>
<>
<h1 className="text-balance text-4xl font-bold leading-tight tracking-tighter [view-transition-name:title] md:text-6xl lg:pr-8 lg:text-8xl">
{state.data || 'TanStack Start Starter'}
</h1>
<Link
className="bg-theme text-theme ring-theme focus:bg-theme-button hover:bg-theme-button hover:text-theme-button focus:text-theme-button w-56 rounded-md px-4 py-2 text-sm font-semibold ring-2 ring-opacity-75 [view-transition-name:search] focus:outline-none"
to="/goto"
>
Go to...
</Link>
</>
)
}
12 changes: 12 additions & 0 deletions tanstack-start/sanity.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,17 @@ export type THEME_QUERYResult =
}
| null

// Source: ./app/routes/goto.tsx
// Variable: SEARCH_QUERY
// Query: { "title": *[_type == "demo" && slug.current == $slug][0].title, "urls": *[_type == "demo" && slug.current != $slug && [title,slug.current,url] match "*"+$q+"*"]{title,url}}
export type SEARCH_QUERYResult = {
title: string | null
urls: Array<{
title: string | null
url: string | null
}>
}

// Source: ./app/routes/index.tsx
// Variable: DEMO_QUERY
// Query: *[_type == "demo" && slug.current == $slug][0].title
Expand All @@ -192,6 +203,7 @@ export type DEMO_QUERYResult = string | null
declare module '@sanity/client' {
interface SanityQueries {
'*[_id == "theme"][0]{background,text}': THEME_QUERYResult
'{\n "title": *[_type == "demo" && slug.current == $slug][0].title,\n "urls": *[_type == "demo" && slug.current != $slug && [title,slug.current,url] match "*"+$q+"*"]{title,url}\n}': SEARCH_QUERYResult
'*[_type == "demo" && slug.current == $slug][0].title': DEMO_QUERYResult
}
}

0 comments on commit bb5f667

Please sign in to comment.