Skip to content
Draft

Rsc #704

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
39 changes: 32 additions & 7 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,23 +45,25 @@
"@sentry/node": "^10.33.0",
"@sentry/tanstackstart-react": "^10.32.1",
"@sentry/vite-plugin": "^4.6.1",
"@shikijs/rehype": "^3.22.0",
"@stackblitz/sdk": "^1.11.0",
"@tailwindcss/typography": "^0.5.13",
"@tailwindcss/vite": "^4.1.11",
"@tanstack/create": "^0.49.1",
"@tanstack/pacer": "^0.16.4",
"@tanstack/react-pacer": "^0.17.4",
"@tanstack/react-query": "^5.90.12",
"@tanstack/react-router": "1.157.16",
"@tanstack/react-router-devtools": "1.157.16",
"@tanstack/react-router-ssr-query": "1.157.16",
"@tanstack/react-start": "1.157.16",
"@tanstack/react-router": "file:../start-rsc/packages/react-router",
"@tanstack/react-router-devtools": "file:../start-rsc/packages/react-router-devtools",
"@tanstack/react-router-ssr-query": "file:../start-rsc/packages/react-router-ssr-query",
"@tanstack/react-start": "file:../start-rsc/packages/react-start",
"@tanstack/react-table": "^8.21.3",
"@types/d3": "^7.4.3",
"@uploadthing/react": "^7.3.3",
"@visx/hierarchy": "^2.10.0",
"@visx/responsive": "^2.10.0",
"@vitejs/plugin-react": "^4.3.3",
"@vitejs/plugin-rsc": "^0.5.15",
"@webcontainer/api": "^1.6.1",
"@xstate/react": "^6.0.0",
"algoliasearch": "^5.23.4",
Expand All @@ -74,6 +76,7 @@
"eslint-plugin-jsx-a11y": "^6.10.2",
"gray-matter": "^4.0.3",
"hast-util-is-element": "^3.0.0",
"hast-util-to-html": "^9.0.5",
"hast-util-to-string": "^3.0.1",
"hono": "^4.11.3",
"html-react-parser": "^5.1.10",
Expand All @@ -93,14 +96,15 @@
"rehype-callouts": "^2.1.2",
"rehype-parse": "^9.0.1",
"rehype-raw": "^7.0.0",
"rehype-react": "^8.0.0",
"rehype-slug": "^6.0.0",
"rehype-stringify": "^10.0.1",
"remark-gfm": "^4.0.1",
"remark-parse": "^11.0.0",
"remark-rehype": "^11.1.2",
"remove-markdown": "^0.5.0",
"resend": "^6.6.0",
"shiki": "^1.4.0",
"shiki": "^3.22.0",
"tailwind-merge": "^1.14.0",
"three": "^0.182.0",
"troika-three-text": "^0.52.4",
Expand All @@ -119,7 +123,7 @@
"@content-collections/vite": "^0.2.4",
"@eslint/js": "^9.39.1",
"@playwright/test": "^1.57.0",
"@shikijs/transformers": "^1.10.3",
"@shikijs/transformers": "^3.22.0",
"@types/express": "^5.0.3",
"@types/hast": "^3.0.4",
"@types/node": "^24.3.0",
Expand Down Expand Up @@ -158,7 +162,28 @@
"jws": ">=3.2.3",
"qs": ">=6.14.1",
"js-yaml": "^3.14.2",
"brace-expansion": ">=1.1.12"
"brace-expansion": ">=1.1.12",
"@tanstack/history": "file:../start-rsc/packages/history",
"@tanstack/router-core": "file:../start-rsc/packages/router-core",
"@tanstack/react-router": "file:../start-rsc/packages/react-router",
"@tanstack/react-router-devtools": "file:../start-rsc/packages/react-router-devtools",
"@tanstack/router-devtools-core": "file:../start-rsc/packages/router-devtools-core",
"@tanstack/router-ssr-query-core": "file:../start-rsc/packages/router-ssr-query-core",
"@tanstack/react-router-ssr-query": "file:../start-rsc/packages/react-router-ssr-query",
"@tanstack/react-start": "file:../start-rsc/packages/react-start",
"@tanstack/react-start-client": "file:../start-rsc/packages/react-start-client",
"@tanstack/react-start-server": "file:../start-rsc/packages/react-start-server",
"@tanstack/react-start-rsc": "file:../start-rsc/packages/react-start-rsc",
"@tanstack/start-plugin-core": "file:../start-rsc/packages/start-plugin-core",
"@tanstack/start-client-core": "file:../start-rsc/packages/start-client-core",
"@tanstack/start-server-core": "file:../start-rsc/packages/start-server-core",
"@tanstack/start-storage-context": "file:../start-rsc/packages/start-storage-context",
"@tanstack/start-fn-stubs": "file:../start-rsc/packages/start-fn-stubs",
"@tanstack/router-utils": "file:../start-rsc/packages/router-utils",
"@tanstack/router-generator": "file:../start-rsc/packages/router-generator",
"@tanstack/router-plugin": "file:../start-rsc/packages/router-plugin",
"@tanstack/virtual-file-routes": "file:../start-rsc/packages/virtual-file-routes",
"@tanstack/valibot-adapter": "file:../start-rsc/packages/valibot-adapter"
}
}
}
718 changes: 566 additions & 152 deletions pnpm-lock.yaml

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions src/components/Breadcrumbs.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Link } from '@tanstack/react-router'
import { ChevronDown } from 'lucide-react'
import { twMerge } from 'tailwind-merge'
import type { MarkdownHeading } from '~/utils/markdown/processor'
import type { MarkdownHeading } from '~/utils/markdown/types'
import {
Dropdown,
DropdownTrigger,
Expand Down Expand Up @@ -43,7 +43,7 @@ export function Breadcrumbs({
)}
{showTocToggle && (
<Dropdown>
<DropdownTrigger asChild={false}>
<DropdownTrigger>
<button
className={twMerge(
hiddenClass,
Expand Down
14 changes: 9 additions & 5 deletions src/components/CodeExampleCard.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import { useState } from 'react'
import { Card } from '~/components/Card'
import { CodeBlock } from '~/components/markdown'
import { HighlightedCodeBlock } from '~/components/markdown'
import { FrameworkIconTabs } from '~/components/FrameworkIconTabs'
import type { Framework } from '~/libraries'

interface CodeExampleCardProps {
title?: string
frameworks: Framework[]
codeByFramework: Partial<Record<Framework, { lang: string; code: string }>>
/** Pre-highlighted HTML by framework (from server-side Shiki) */
codeByFramework: Partial<Record<Framework, { lang: string; html: string }>>
}

export function CodeExampleCard({
Expand All @@ -32,9 +33,12 @@ export function CodeExampleCard({
value={framework}
onChange={setFramework}
/>
<CodeBlock className="mt-0 border-0" showTypeCopyButton={false}>
<code className={`language-${selected.lang}`}>{selected.code}</code>
</CodeBlock>
<HighlightedCodeBlock
html={selected.html}
lang={selected.lang}
showCopyButton={false}
className="mt-0 border-0"
/>
</div>
</Card>
</div>
Expand Down
73 changes: 36 additions & 37 deletions src/components/CodeExplorer.tsx
Original file line number Diff line number Diff line change
@@ -1,44 +1,47 @@
import React from 'react'
import { CodeBlock } from '~/components/markdown'
import { HighlightedCodeBlock } from '~/components/markdown'
import { FileExplorer } from './FileExplorer'
import { InteractiveSandbox } from './InteractiveSandbox'
import { CodeExplorerTopBar } from './CodeExplorerTopBar'
import type { GitHubFileNode } from '~/utils/documents.server'
import type { Library } from '~/libraries'
import { twMerge } from 'tailwind-merge'

function overrideExtension(ext: string | undefined) {
if (!ext) return 'txt'
function getLanguageFromPath(path: string): string {
const ext = path.split('.').pop() || ''

// Override some extensions
if (['cts', 'mts'].includes(ext)) return 'ts'
if (['cjs', 'mjs'].includes(ext)) return 'js'
if (['prettierrc', 'babelrc', 'webmanifest'].includes(ext)) return 'json'
if (['env', 'example'].includes(ext)) return 'sh'
if (
[
'gitignore',
'prettierignore',
'log',
'gitattributes',
'editorconfig',
'lock',
'opts',
'Dockerfile',
'dockerignore',
'npmrc',
'nvmrc',
].includes(ext)
)
return 'txt'
const langMap: Record<string, string> = {
ts: 'typescript',
tsx: 'tsx',
js: 'javascript',
jsx: 'jsx',
mts: 'typescript',
cts: 'typescript',
mjs: 'javascript',
cjs: 'javascript',
json: 'json',
md: 'markdown',
html: 'html',
css: 'css',
scss: 'scss',
yaml: 'yaml',
yml: 'yaml',
toml: 'toml',
sh: 'bash',
bash: 'bash',
sql: 'sql',
vue: 'vue',
svelte: 'svelte',
}

return ext
return langMap[ext] || 'text'
}

interface CodeExplorerProps {
activeTab: 'code' | 'sandbox'
codeSandboxUrl: string
currentCode: string
/** Pre-highlighted HTML from server-side Shiki */
currentCodeHtml: string
currentPath: string
examplePath: string
githubContents: GitHubFileNode[] | undefined
Expand All @@ -52,7 +55,7 @@ interface CodeExplorerProps {
export function CodeExplorer({
activeTab,
codeSandboxUrl,
currentCode,
currentCodeHtml,
currentPath,
examplePath,
githubContents,
Expand Down Expand Up @@ -85,6 +88,8 @@ export function CodeExplorer({
return () => window.removeEventListener('closeSidebar', handleCloseSidebar)
}, [])

const lang = getLanguageFromPath(currentPath)

return (
<div
className={`flex flex-col min-h-[60dvh] sm:min-h-[80dvh] border border-gray-200 dark:border-gray-700 rounded-lg overflow-hidden ${
Expand Down Expand Up @@ -117,21 +122,15 @@ export function CodeExplorer({
setCurrentPath={setCurrentPath}
/>
<div className="flex-1 overflow-auto relative">
<CodeBlock
<HighlightedCodeBlock
html={currentCodeHtml}
lang={lang}
isEmbedded
className={twMerge(
'h-full border-0',
isFullScreen ? 'max-h-[90dvh]' : 'max-h-[80dvh]',
)}
>
<code
className={`language-${overrideExtension(
currentPath.split('.').pop(),
)}`}
>
{currentCode}
</code>
</CodeBlock>
/>
</div>
</div>
<InteractiveSandbox
Expand Down
16 changes: 6 additions & 10 deletions src/components/Doc.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,17 @@ import { useWidthToggle, DocNavigation } from '~/components/DocsLayout'
import { AdGate } from '~/contexts/AdsContext'
import { GamHeader } from './Gam'
import { Toc } from './Toc'
import { renderMarkdown } from '~/utils/markdown'
import { DocBreadcrumb } from './DocBreadcrumb'
import { MarkdownContent } from '~/components/markdown'
import type { ConfigSchema } from '~/utils/config'
import { useLocalCurrentFramework } from './FrameworkSelect'
import { useParams } from '@tanstack/react-router'
import type { MarkdownHeading } from '~/utils/markdown/types'

type DocProps = {
title: string
content: string
contentRsc: React.ReactNode
headings: MarkdownHeading[]
repo: string
branch: string
filePath: string
Expand All @@ -36,7 +37,8 @@ type DocProps = {

export function Doc({
title,
content,
contentRsc,
headings,
repo,
branch,
filePath,
Expand All @@ -51,12 +53,6 @@ export function Doc({
footer,
framework: frameworkProp,
}: DocProps) {
// Extract headings synchronously during render to avoid hydration mismatch
const { headings, markup } = React.useMemo(
() => renderMarkdown(content),
[content],
)

// Get current framework from prop, URL params, or local storage
const { framework: paramsFramework } = useParams({ strict: false })
const localCurrentFramework = useLocalCurrentFramework()
Expand Down Expand Up @@ -159,7 +155,7 @@ export function Doc({
repo={repo}
branch={branch}
filePath={filePath}
htmlMarkup={markup}
contentRsc={contentRsc}
containerRef={markdownContainerRef}
libraryId={libraryId}
libraryVersion={libraryVersion}
Expand Down
2 changes: 1 addition & 1 deletion src/components/DocBreadcrumb.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { useParams } from '@tanstack/react-router'
import { Breadcrumbs } from './Breadcrumbs'
import type { ConfigSchema } from '~/utils/config'
import type { MarkdownHeading } from '~/utils/markdown/processor'
import type { MarkdownHeading } from '~/utils/markdown/types'

function findSectionForDoc(
config: ConfigSchema,
Expand Down
25 changes: 18 additions & 7 deletions src/components/FeedEntry.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type { ReactNode } from 'react'
import type { AnyCompositeComponent } from '@tanstack/react-start/rsc'
import { format, formatDistanceToNow } from '~/utils/dates'
import { Markdown } from '~/components/markdown'
import { libraries } from '~/libraries'
import { partners } from '~/utils/partners'
import { twMerge } from 'tailwind-merge'
Expand All @@ -13,18 +14,22 @@ export interface FeedEntry {
entryType: 'release' | 'blog' | 'announcement'
title: string
content: string
contentRsc?: ReactNode
excerpt?: string | null
publishedAt: number
createdAt: number
updatedAt?: number
metadata?: any
metadata?: Record<string, string | number | boolean | null | undefined>
libraryIds: string[]
partnerIds?: string[]
tags: string[]
showInFeed: boolean
featured?: boolean
autoSynced: boolean
lastSyncedAt?: number
// Composite sources for RSC rendering
timelineCompositeSrc?: AnyCompositeComponent
detailCompositeSrc?: AnyCompositeComponent
}

interface FeedEntryProps {
Expand Down Expand Up @@ -159,12 +164,18 @@ export function FeedEntry({
const releaseLevelBadge = getReleaseLevelBadge()

// Determine external link if available
const getExternalLink = () => {
const getExternalLink = (): string | null => {
if (entry.metadata) {
if (entry.entryType === 'release' && entry.metadata.url) {
if (
entry.entryType === 'release' &&
typeof entry.metadata.url === 'string'
) {
return entry.metadata.url
}
if (entry.entryType === 'blog' && entry.metadata.url) {
if (
entry.entryType === 'blog' &&
typeof entry.metadata.url === 'string'
) {
return entry.metadata.url
}
}
Expand Down Expand Up @@ -414,8 +425,8 @@ export function FeedEntry({
</div>

{/* Content */}
<div className="text-xs text-gray-900 dark:text-gray-100 leading-snug mb-3">
<Markdown rawContent={entry.content} />
<div className="text-xs text-gray-900 dark:text-gray-100 leading-snug mb-3 prose prose-xs dark:prose-invert max-w-none">
{entry.contentRsc ?? entry.content}
</div>

{/* External Link */}
Expand Down
Loading
Loading