feat: improve example-usage initial loading

pull/715/head
Travis Fischer 2025-06-25 00:11:56 -05:00
rodzic 8db253548d
commit 194707b340
7 zmienionych plików z 135 dodań i 58 usunięć

Wyświetl plik

@ -56,6 +56,7 @@
"react-infinite-scroll-hook": "catalog:",
"react-lottie-player": "catalog:",
"react-use": "catalog:",
"server-only": "^0.0.1",
"shiki": "catalog:",
"sonner": "catalog:",
"stripe": "catalog:",

Wyświetl plik

@ -1,12 +1,37 @@
import Link from 'next/link'
import { highlight } from '@/components/code-block/highlight'
import { DemandSideCTA } from '@/components/demand-side-cta'
import { DotsSection } from '@/components/dots-section'
import { ExampleUsage } from '@/components/example-usage'
import { GitHubStarCounter } from '@/components/github-star-counter'
import { githubUrl, twitterUrl } from '@/lib/config'
import {
defaultConfig,
getCodeForDeveloperConfig
} from '@/lib/developer-config'
import { globalAgenticApiClient } from '@/lib/global-api'
export default async function TheBestDamnLandingPageEver() {
const projectIdentifier = '@agentic/search'
const prompt = 'What is the latest news about AI?'
const initialProject =
await globalAgenticApiClient.getPublicProjectByIdentifier({
projectIdentifier,
populate: ['lastPublishedDeployment']
})
// TODO: this should be loaded in `ExampleUsage`
const initialCodeSnippet = getCodeForDeveloperConfig({
config: defaultConfig,
project: initialProject,
deployment: initialProject.lastPublishedDeployment!,
identifier: projectIdentifier,
prompt
})
const initialCodeBlock = await highlight(initialCodeSnippet)
export default function TheBestDamnLandingPageEver() {
return (
<>
{/* Hero section */}
@ -31,7 +56,12 @@ export default function TheBestDamnLandingPageEver() {
How It Works
</h2>
<ExampleUsage />
<ExampleUsage
projectIdentifier={projectIdentifier}
prompt={prompt}
project={initialProject}
initialCodeBlock={initialCodeBlock}
/>
</section>
{/* Marketplace section */}

Wyświetl plik

@ -0,0 +1,41 @@
import { toJsxRuntime } from 'hast-util-to-jsx-runtime'
import { Fragment, type JSX } from 'react'
import { jsx, jsxs } from 'react/jsx-runtime'
import { type BundledLanguage, codeToHast } from 'shiki/bundle/web'
import { cn } from '@/lib/utils'
export async function highlight({
code,
lang = 'ts',
theme = 'github-dark',
className
}: {
code: string
lang?: BundledLanguage
theme?: string
className?: string
}): Promise<JSX.Element> {
className = cn('w-full text-wrap p-4 text-sm rounded-sm', className)
const out = await codeToHast(code, {
lang,
theme,
// TODO: use a custom `pre` element down below instead of this
transformers: [
{
pre(node) {
if (className) {
this.addClassToHast(node, className)
}
}
}
]
})
return toJsxRuntime(out, {
Fragment,
jsx,
jsxs
})
}

Wyświetl plik

@ -1,16 +1,11 @@
import { toJsxRuntime } from 'hast-util-to-jsx-runtime'
import { CheckIcon, CopyIcon } from 'lucide-react'
import {
Fragment,
type JSX,
useCallback,
useEffect,
useRef,
useState
} from 'react'
import { jsx, jsxs } from 'react/jsx-runtime'
import { type BundledLanguage, codeToHast } from 'shiki/bundle/web'
'use client'
import { CheckIcon, CopyIcon } from 'lucide-react'
import { type JSX, useCallback, useEffect, useRef, useState } from 'react'
import { type BundledLanguage } from 'shiki/bundle/web'
import { LoadingIndicator } from '@/components/loading-indicator'
import { Button } from '@/components/ui/button'
import {
Tooltip,
TooltipContent,
@ -19,40 +14,7 @@ import {
import { toastError } from '@/lib/notifications'
import { cn } from '@/lib/utils'
import { LoadingIndicator } from './loading-indicator'
import { Button } from './ui/button'
export async function highlight({
code,
lang = 'ts',
theme = 'github-dark',
className
}: {
code: string
lang?: BundledLanguage
theme?: string
className?: string
}) {
const out = await codeToHast(code, {
lang,
theme,
transformers: [
{
pre(node) {
if (className) {
this.addClassToHast(node, className)
}
}
}
]
})
return toJsxRuntime(out, {
Fragment,
jsx,
jsxs
}) as JSX.Element
}
import { highlight } from './highlight'
export function CodeBlock({
initial,
@ -75,8 +37,7 @@ export function CodeBlock({
void highlight({
code,
lang,
theme,
className: 'w-full text-wrap p-4 text-sm rounded-sm'
theme
}).then(setNodes)
}, [code, lang, theme])

Wyświetl plik

@ -1,5 +1,7 @@
'use client'
import type { Project } from '@agentic/platform-types'
import type { JSX } from 'react'
import { useLocalStorage } from 'react-use'
import { useAgentic } from '@/components/agentic-provider'
@ -29,7 +31,17 @@ import { useQuery } from '@/lib/query-client'
import { LoadingIndicator } from './loading-indicator'
export function ExampleUsage() {
export function ExampleUsage({
projectIdentifier,
prompt,
project: initialProject,
initialCodeBlock
}: {
projectIdentifier: string
prompt: string
project?: Project
initialCodeBlock?: JSX.Element
}) {
const ctx = useAgentic()
const [config, setConfig] = useLocalStorage<DeveloperConfig>(
@ -40,8 +52,6 @@ export function ExampleUsage() {
// TODO: make this configurable
// TODO: allow to take the project and/or consumer in as props
// TODO: need a way of fetching a project and target deployment; same as in `AgenticToolClient.fromIdentifier` (currently only supports latest)
const projectIdentifier = '@agentic/search'
const prompt = 'What is the latest news about AI?'
// Load the public project
const {
@ -55,7 +65,8 @@ export function ExampleUsage() {
projectIdentifier,
populate: ['lastPublishedDeployment']
}),
enabled: !!ctx
enabled: !!ctx,
initialData: initialProject
})
// If the user is authenticated, check if they have an active subscription to
@ -153,7 +164,11 @@ export function ExampleUsage() {
value={mcpClientTarget}
className='w-full'
>
<CodeBlock code={codeSnippet.code} lang={codeSnippet.lang} />
<CodeBlock
code={codeSnippet.code}
lang={codeSnippet.lang}
initial={initialCodeBlock}
/>
</TabsContent>
))}
</Tabs>
@ -185,7 +200,11 @@ export function ExampleUsage() {
{tsFrameworkTargets.map((framework) => (
<TabsContent key={framework} value={framework} className='w-full'>
<CodeBlock code={codeSnippet.code} lang={codeSnippet.lang} />
<CodeBlock
code={codeSnippet.code}
lang={codeSnippet.lang}
initial={initialCodeBlock}
/>
</TabsContent>
))}
</Tabs>
@ -217,7 +236,11 @@ export function ExampleUsage() {
{pyFrameworkTargets.map((framework) => (
<TabsContent key={framework} value={framework} className='w-full'>
<CodeBlock code={codeSnippet.code} lang={codeSnippet.lang} />
<CodeBlock
code={codeSnippet.code}
lang={codeSnippet.lang}
initial={initialCodeBlock}
/>
</TabsContent>
))}
</Tabs>
@ -249,7 +272,11 @@ export function ExampleUsage() {
{httpTargets.map((httpTarget) => (
<TabsContent key={httpTarget} value={httpTarget} className='w-full'>
<CodeBlock code={codeSnippet.code} lang={codeSnippet.lang} />
<CodeBlock
code={codeSnippet.code}
lang={codeSnippet.lang}
initial={initialCodeBlock}
/>
</TabsContent>
))}
</Tabs>

Wyświetl plik

@ -0,0 +1,9 @@
import 'server-only'
import { AgenticApiClient } from '@agentic/platform-api-client'
import { apiBaseUrl } from '@/lib/config'
export const globalAgenticApiClient = new AgenticApiClient({
apiBaseUrl
})

Wyświetl plik

@ -776,6 +776,9 @@ importers:
react-use:
specifier: 'catalog:'
version: 17.6.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
server-only:
specifier: ^0.0.1
version: 0.0.1
shiki:
specifier: 'catalog:'
version: 3.7.0
@ -6980,6 +6983,9 @@ packages:
resolution: {integrity: sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==}
engines: {node: '>= 18'}
server-only@0.0.1:
resolution: {integrity: sha512-qepMx2JxAa5jjfzxG79yPPq+8BuFToHd1hm7kI+Z4zAq1ftQiP7HcxMhDDItrbtwVeLg/cY2JnKnrcFkmiswNA==}
set-function-length@1.2.2:
resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==}
engines: {node: '>= 0.4'}
@ -13872,6 +13878,8 @@ snapshots:
transitivePeerDependencies:
- supports-color
server-only@0.0.1: {}
set-function-length@1.2.2:
dependencies:
define-data-property: 1.1.4