docs-i18n 0.6.3 → 0.7.0

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.
Files changed (169) hide show
  1. package/{src/admin/ui → admin/app}/components/JobDialog.tsx +21 -2
  2. package/{src/admin/ui → admin/app}/components/JobPanel.tsx +1 -1
  3. package/{src/admin/ui → admin/app}/components/Preview.tsx +2 -5
  4. package/{src/admin/ui → admin/app}/lib/api.ts +18 -39
  5. package/admin/app/routeTree.gen.ts +68 -0
  6. package/admin/app/router.tsx +23 -0
  7. package/admin/app/routes/__root.tsx +55 -0
  8. package/admin/app/routes/index.tsx +416 -0
  9. package/{src/admin/ui → admin/app}/styles.css +36 -3
  10. package/admin/package.json +27 -0
  11. package/admin/server/functions/jobs.ts +53 -0
  12. package/admin/server/functions/misc.ts +84 -0
  13. package/{src/admin/server/routes → admin/server/functions}/models.ts +16 -29
  14. package/admin/server/functions/status.ts +61 -0
  15. package/admin/server/index.ts +35 -0
  16. package/admin/server/init.ts +46 -0
  17. package/{src/admin → admin}/server/services/job-manager.ts +39 -10
  18. package/{src/admin → admin}/server/services/status.ts +6 -6
  19. package/admin/tsconfig.json +19 -0
  20. package/{src/admin → admin}/vite.config.ts +8 -2
  21. package/dist/{assemble-7H4QCW35.js → assemble-CP2BRYQJ.js} +6 -4
  22. package/dist/{chunk-A3YQNPKZ.js → chunk-CLYUAWZE.js} +1 -1
  23. package/dist/{chunk-YN4VJHCQ.js → chunk-JHBSHTXC.js} +1 -1
  24. package/dist/chunk-L64GJ4OB.js +32 -0
  25. package/dist/{chunk-SKKZIV3L.js → chunk-PNKVD2UK.js} +1 -29
  26. package/dist/{chunk-XEOYZUHS.js → chunk-QKIR7RKQ.js} +4 -31
  27. package/dist/chunk-TRURQFP4.js +31 -0
  28. package/dist/cli.js +108 -7
  29. package/dist/index.d.ts +41 -1
  30. package/dist/index.js +92 -3
  31. package/dist/{rescan-O5D3CYC2.js → rescan-HXMWFAOC.js} +5 -3
  32. package/dist/{status-F4MYIAAY.js → status-AGZDXOTZ.js} +4 -2
  33. package/dist/{translate-ZIVKNAC4.js → translate-A5X6MX4Y.js} +14 -7
  34. package/dist/upload-XL6KG6S2.js +132 -0
  35. package/package.json +17 -15
  36. package/template/app/components/BlogArticle.tsx +159 -0
  37. package/template/app/components/BlogList.tsx +88 -0
  38. package/template/app/components/Breadcrumbs.tsx +81 -0
  39. package/template/app/components/Card.tsx +31 -0
  40. package/template/app/components/Doc.tsx +191 -0
  41. package/template/app/components/DocBreadcrumb.tsx +60 -0
  42. package/template/app/components/DocContainer.tsx +13 -0
  43. package/template/app/components/DocTitle.tsx +11 -0
  44. package/template/app/components/DocsLayout.tsx +715 -0
  45. package/template/app/components/Dropdown.tsx +116 -0
  46. package/template/app/components/FallbackBanner.tsx +36 -0
  47. package/template/app/components/Footer.tsx +29 -0
  48. package/template/app/components/FrameworkSelect.tsx +150 -0
  49. package/template/app/components/LibraryCard.tsx +178 -0
  50. package/template/app/components/LocaleSwitcher.tsx +43 -0
  51. package/template/app/components/Navbar.tsx +430 -0
  52. package/template/app/components/PostNotFound.tsx +20 -0
  53. package/template/app/components/SearchButton.tsx +32 -0
  54. package/template/app/components/Select.tsx +103 -0
  55. package/template/app/components/Spinner.tsx +18 -0
  56. package/template/app/components/ThemeProvider.tsx +141 -0
  57. package/template/app/components/ThemeToggle.tsx +31 -0
  58. package/template/app/components/Toc.tsx +86 -0
  59. package/template/app/components/VersionSelect.tsx +118 -0
  60. package/template/app/components/icons/BSkyIcon.tsx +27 -0
  61. package/template/app/components/icons/BaseballCapIcon.tsx +25 -0
  62. package/template/app/components/icons/BrandXIcon.tsx +28 -0
  63. package/template/app/components/icons/CheckCircleIcon.tsx +28 -0
  64. package/template/app/components/icons/CogsIcon.tsx +25 -0
  65. package/template/app/components/icons/DiscordIcon.tsx +24 -0
  66. package/template/app/components/icons/GithubIcon.tsx +24 -0
  67. package/template/app/components/icons/GoogleIcon.tsx +24 -0
  68. package/template/app/components/icons/InstagramIcon.tsx +24 -0
  69. package/template/app/components/icons/NpmIcon.tsx +26 -0
  70. package/template/app/components/icons/YinYangIcon.tsx +26 -0
  71. package/template/app/components/icons/YouTubeIcon.tsx +24 -0
  72. package/template/app/components/markdown/CodeBlock.tsx +254 -0
  73. package/template/app/components/markdown/FileTabs.tsx +58 -0
  74. package/template/app/components/markdown/FrameworkContent.tsx +76 -0
  75. package/template/app/components/markdown/Markdown.tsx +216 -0
  76. package/template/app/components/markdown/MarkdownContent.tsx +89 -0
  77. package/template/app/components/markdown/MarkdownFrameworkHandler.tsx +66 -0
  78. package/template/app/components/markdown/MarkdownHeadingContext.tsx +35 -0
  79. package/template/app/components/markdown/MarkdownLink.tsx +46 -0
  80. package/template/app/components/markdown/MarkdownTabsHandler.tsx +109 -0
  81. package/template/app/components/markdown/PackageManagerTabs.tsx +95 -0
  82. package/template/app/components/markdown/Tabs.tsx +139 -0
  83. package/template/app/components/markdown/index.ts +15 -0
  84. package/template/app/components/ui/Button.tsx +141 -0
  85. package/template/app/components/ui/InlineCode.tsx +16 -0
  86. package/template/app/components/ui/MarkdownImg.tsx +21 -0
  87. package/template/app/config/frameworks.ts +93 -0
  88. package/template/app/contexts/SearchContext.tsx +36 -0
  89. package/template/app/db/index.ts +17 -0
  90. package/template/app/db/schema.ts +74 -0
  91. package/template/app/hooks/useClickOutside.ts +106 -0
  92. package/template/app/routeTree.gen.ts +584 -0
  93. package/template/app/router.tsx +29 -0
  94. package/template/app/routes/$lang.$project.$version.docs.$.tsx +128 -0
  95. package/template/app/routes/$lang.$project.$version.docs.framework.$framework.$.tsx +106 -0
  96. package/template/app/routes/$lang.$project.$version.docs.framework.$framework.index.tsx +27 -0
  97. package/template/app/routes/$lang.$project.$version.docs.framework.index.tsx +44 -0
  98. package/template/app/routes/$lang.$project.$version.docs.index.tsx +27 -0
  99. package/template/app/routes/$lang.$project.$version.docs.tsx +70 -0
  100. package/template/app/routes/$lang.$project.$version.tsx +69 -0
  101. package/template/app/routes/$lang.$project.docs.$.tsx +104 -0
  102. package/template/app/routes/$lang.$project.docs.index.tsx +20 -0
  103. package/template/app/routes/$lang.$project.docs.tsx +79 -0
  104. package/template/app/routes/$lang.$project.tsx +89 -0
  105. package/template/app/routes/$lang.blog.$.tsx +82 -0
  106. package/template/app/routes/$lang.blog.index.tsx +56 -0
  107. package/template/app/routes/$lang.blog.tsx +26 -0
  108. package/template/app/routes/$lang.docs.$.tsx +100 -0
  109. package/template/app/routes/$lang.docs.framework.$framework.$.tsx +104 -0
  110. package/template/app/routes/$lang.docs.framework.$framework.index.tsx +32 -0
  111. package/template/app/routes/$lang.docs.framework.index.tsx +47 -0
  112. package/template/app/routes/$lang.docs.index.tsx +20 -0
  113. package/template/app/routes/$lang.docs.tsx +90 -0
  114. package/template/app/routes/$lang.tsx +16 -0
  115. package/template/app/routes/__root.tsx +180 -0
  116. package/template/app/routes/index.tsx +89 -0
  117. package/template/app/site.config.ts +182 -0
  118. package/template/app/styles/app.css +1029 -0
  119. package/template/app/types/index.ts +77 -0
  120. package/template/app/utils/blog.server.ts +193 -0
  121. package/template/app/utils/blog.ts +42 -0
  122. package/template/app/utils/config.ts +120 -0
  123. package/template/app/utils/content-loader.ts +400 -0
  124. package/template/app/utils/dates.ts +29 -0
  125. package/template/app/utils/docs.server.ts +150 -0
  126. package/template/app/utils/markdown/filterFrameworkContent.ts +233 -0
  127. package/template/app/utils/markdown/index.ts +2 -0
  128. package/template/app/utils/markdown/installCommand.ts +143 -0
  129. package/template/app/utils/markdown/plugins/collectHeadings.ts +104 -0
  130. package/template/app/utils/markdown/plugins/extractCodeMeta.ts +57 -0
  131. package/template/app/utils/markdown/plugins/helpers.ts +33 -0
  132. package/template/app/utils/markdown/plugins/index.ts +8 -0
  133. package/template/app/utils/markdown/plugins/parseCommentComponents.ts +103 -0
  134. package/template/app/utils/markdown/plugins/transformCommentComponents.ts +23 -0
  135. package/template/app/utils/markdown/plugins/transformFrameworkComponent.ts +217 -0
  136. package/template/app/utils/markdown/plugins/transformTabsComponent.ts +359 -0
  137. package/template/app/utils/markdown/processor.ts +75 -0
  138. package/template/app/utils/site-config.tsx +11 -0
  139. package/template/app/utils/upload.ts +232 -0
  140. package/template/app/utils/useLocalStorage.ts +65 -0
  141. package/template/app/utils/utils.ts +23 -0
  142. package/template/package.json +54 -0
  143. package/template/public/favicon.svg +1 -0
  144. package/template/public/fonts/Inter-latin-ext.woff2 +0 -0
  145. package/template/public/fonts/Inter-latin.woff2 +0 -0
  146. package/template/public/images/frameworks/angular-logo.svg +1 -0
  147. package/template/public/images/frameworks/js-logo.svg +1 -0
  148. package/template/public/images/frameworks/lit-logo.svg +1 -0
  149. package/template/public/images/frameworks/preact-logo.svg +6 -0
  150. package/template/public/images/frameworks/qwik-logo.svg +1 -0
  151. package/template/public/images/frameworks/react-logo.svg +1 -0
  152. package/template/public/images/frameworks/solid-logo.svg +1 -0
  153. package/template/public/images/frameworks/svelte-logo.svg +1 -0
  154. package/template/public/images/frameworks/vue-logo.svg +4 -0
  155. package/template/tsconfig.json +24 -0
  156. package/template/vite.config.ts +43 -0
  157. package/template/wrangler.jsonc +16 -0
  158. package/README.md +0 -161
  159. package/dist/server-73AVSOL5.js +0 -598
  160. package/src/admin/index.html +0 -13
  161. package/src/admin/server/index.ts +0 -138
  162. package/src/admin/server/routes/jobs.ts +0 -113
  163. package/src/admin/server/routes/status.ts +0 -57
  164. package/src/admin/ui/App.tsx +0 -332
  165. package/src/admin/ui/main.tsx +0 -19
  166. /package/{src/admin/ui → admin/app}/components/FileList.tsx +0 -0
  167. /package/{src/admin/ui → admin/app}/components/LangGrid.tsx +0 -0
  168. /package/{src/admin/ui → admin/app}/components/ProgressBar.tsx +0 -0
  169. /package/{src/admin/ui → admin/app}/lib/flags.ts +0 -0
@@ -0,0 +1,180 @@
1
+ import * as React from 'react'
2
+ import {
3
+ createRootRouteWithContext,
4
+ useMatches,
5
+ useRouterState,
6
+ HeadContent,
7
+ Scripts,
8
+ Link,
9
+ } from '@tanstack/react-router'
10
+ import { QueryClient } from '@tanstack/react-query'
11
+ import appCss from '~/styles/app.css?url'
12
+ import { siteConfig } from '~/site.config'
13
+ import { SearchProvider, useSearchContext } from '~/contexts/SearchContext'
14
+ import { ThemeProvider, useHtmlClass } from '~/components/ThemeProvider'
15
+ import { Spinner } from '~/components/Spinner'
16
+ import { Navbar } from '~/components/Navbar'
17
+
18
+ export const Route = createRootRouteWithContext<{
19
+ queryClient: QueryClient
20
+ }>()({
21
+ head: () => ({
22
+ meta: [
23
+ {
24
+ charSet: 'utf-8',
25
+ },
26
+ {
27
+ name: 'viewport',
28
+ content: 'width=device-width, initial-scale=1',
29
+ },
30
+ {
31
+ title: `${siteConfig.name} - Documentation`,
32
+ },
33
+ ],
34
+ links: [
35
+ { rel: 'stylesheet', href: appCss },
36
+ { rel: 'icon', href: '/favicon.svg', type: 'image/svg+xml' },
37
+ ],
38
+ scripts: [
39
+ // Theme detection script - must run before body renders to prevent flash
40
+ {
41
+ children: `(function(){try{var t=localStorage.getItem('theme')||'auto';var v=['light','dark','auto'].includes(t)?t:'auto';if(v==='auto'){var a=matchMedia('(prefers-color-scheme: dark)').matches?'dark':'light';document.documentElement.classList.add(a,'auto')}else{document.documentElement.classList.add(v)}}catch(e){var a=matchMedia('(prefers-color-scheme: dark)').matches?'dark':'light';document.documentElement.classList.add(a,'auto')}})()`,
42
+ },
43
+ ],
44
+ }),
45
+ staleTime: Infinity,
46
+ shellComponent: ({ children }) => {
47
+ return (
48
+ <ThemeProvider>
49
+ <SearchProvider>
50
+ <ShellComponent>{children}</ShellComponent>
51
+ </SearchProvider>
52
+ </ThemeProvider>
53
+ )
54
+ },
55
+ errorComponent: DefaultCatchBoundary,
56
+ notFoundComponent: () => <NotFound />,
57
+ })
58
+
59
+ function ShellComponent({ children }: { children: React.ReactNode }) {
60
+ const hasBaseParent = useMatches({
61
+ select: (matches) => matches.find((d) => d.staticData?.baseParent),
62
+ })
63
+
64
+ const isLoading = useRouterState({
65
+ select: (s) => s.status === 'pending',
66
+ })
67
+
68
+ const [canShowLoading, setShowLoading] = React.useState(false)
69
+
70
+ React.useEffect(() => {
71
+ const timeout = setTimeout(() => {
72
+ setShowLoading(true)
73
+ }, 2000)
74
+
75
+ return () => {
76
+ clearTimeout(timeout)
77
+ }
78
+ }, [])
79
+
80
+ const hideNavbar = useMatches({
81
+ select: (s) => s.some((d) => d.staticData?.showNavbar === false),
82
+ })
83
+
84
+ const htmlClass = useHtmlClass()
85
+
86
+ return (
87
+ <html lang="en" className={htmlClass} suppressHydrationWarning>
88
+ <head>
89
+ <HeadContent />
90
+ {hasBaseParent ? <base target="_parent" /> : null}
91
+ </head>
92
+ <body className="overflow-x-hidden">
93
+ {hideNavbar ? children : <Navbar>{children}</Navbar>}
94
+ {canShowLoading ? (
95
+ <div
96
+ className={`fixed top-0 left-0 h-[300px] w-full
97
+ transition-all duration-300 pointer-events-none
98
+ z-30 dark:h-[200px] dark:bg-white/10! dark:rounded-[100%] ${
99
+ isLoading
100
+ ? 'delay-500 opacity-1 -translate-y-1/2'
101
+ : 'delay-0 opacity-0 -translate-y-full'
102
+ }`}
103
+ style={{
104
+ background: `radial-gradient(closest-side, rgba(0,10,40,0.2) 0%, rgba(0,0,0,0) 100%)`,
105
+ }}
106
+ >
107
+ <div
108
+ className={`absolute top-1/2 left-1/2 -translate-x-1/2 translate-y-[30px] p-2 bg-white/80 dark:bg-gray-800
109
+ rounded-lg shadow-lg`}
110
+ >
111
+ <Spinner className="text-5xl" />
112
+ </div>
113
+ </div>
114
+ ) : null}
115
+ <SearchHotkeyController />
116
+ <Scripts />
117
+ </body>
118
+ </html>
119
+ )
120
+ }
121
+
122
+ function SearchHotkeyController() {
123
+ const { openSearch } = useSearchContext()
124
+
125
+ React.useEffect(() => {
126
+ const handleGlobalKeyDown = (event: KeyboardEvent) => {
127
+ if (event.defaultPrevented) return
128
+ if (!(event.metaKey || event.ctrlKey)) return
129
+ if (event.key.toLowerCase() !== 'k') return
130
+
131
+ event.preventDefault()
132
+ openSearch()
133
+ }
134
+
135
+ window.addEventListener('keydown', handleGlobalKeyDown)
136
+ return () => {
137
+ window.removeEventListener('keydown', handleGlobalKeyDown)
138
+ }
139
+ }, [openSearch])
140
+
141
+ return null
142
+ }
143
+
144
+ function NotFound() {
145
+ return (
146
+ <div className="flex-1 flex items-center justify-center py-20">
147
+ <div className="text-center">
148
+ <h1 className="text-4xl font-bold mb-4">404</h1>
149
+ <p className="text-lg text-gray-500 dark:text-gray-400 mb-6">
150
+ The page you are looking for does not exist.
151
+ </p>
152
+ <Link
153
+ to="/"
154
+ className="px-6 py-3 rounded-lg bg-gray-900 dark:bg-gray-100 text-white dark:text-gray-900 font-medium hover:opacity-90 transition-opacity"
155
+ >
156
+ Go Home
157
+ </Link>
158
+ </div>
159
+ </div>
160
+ )
161
+ }
162
+
163
+ function DefaultCatchBoundary({ error }: { error: Error }) {
164
+ return (
165
+ <div className="flex-1 flex items-center justify-center py-20">
166
+ <div className="text-center max-w-lg">
167
+ <h1 className="text-2xl font-bold mb-4">Something went wrong</h1>
168
+ <p className="text-gray-500 dark:text-gray-400 mb-4">
169
+ {error.message || 'An unexpected error occurred.'}
170
+ </p>
171
+ <Link
172
+ to="/"
173
+ className="px-6 py-3 rounded-lg bg-gray-900 dark:bg-gray-100 text-white dark:text-gray-900 font-medium hover:opacity-90 transition-opacity"
174
+ >
175
+ Go Home
176
+ </Link>
177
+ </div>
178
+ </div>
179
+ )
180
+ }
@@ -0,0 +1,89 @@
1
+ import { createFileRoute, redirect } from '@tanstack/react-router'
2
+ import { siteConfig, getProject, isSingleProject, getSingleProject } from '~/site.config'
3
+ import LibraryCard from '~/components/LibraryCard'
4
+ import { Footer } from '~/components/Footer'
5
+
6
+ export const Route = createFileRoute('/')({
7
+ beforeLoad: () => {
8
+ // If only one project, redirect directly to its docs (simplified URL)
9
+ if (isSingleProject()) {
10
+ const project = getSingleProject()
11
+
12
+ throw redirect({
13
+ to: '/$lang/docs/$',
14
+ params: {
15
+ lang: siteConfig.defaultLocale,
16
+ _splat: project.defaultDocs || 'overview',
17
+ },
18
+ })
19
+ }
20
+ },
21
+ component: Index,
22
+ })
23
+
24
+ function Index() {
25
+ const projects = siteConfig.projects
26
+
27
+ return (
28
+ <div className="max-w-full z-10 space-y-24">
29
+ <div className="space-y-8">
30
+ <div className="flex flex-col items-center gap-6 text-center px-4 pt-12 xl:pt-24">
31
+ <div className="flex gap-2 lg:gap-4 items-center">
32
+ <h1
33
+ className={`inline-block
34
+ font-black text-5xl
35
+ md:text-6xl
36
+ lg:text-8xl`}
37
+ >
38
+ <span
39
+ className={`
40
+ inline-block text-black dark:text-white
41
+ mb-2 uppercase [letter-spacing:-.02em] pr-1.5
42
+ `}
43
+ >
44
+ {siteConfig.name}
45
+ </span>
46
+ </h1>
47
+ </div>
48
+ {siteConfig.description && (
49
+ <h2
50
+ className="font-bold text-2xl max-w-md
51
+ md:text-4xl md:max-w-2xl
52
+ 2xl:text-5xl lg:max-w-2xl text-balance"
53
+ >
54
+ {siteConfig.description}
55
+ </h2>
56
+ )}
57
+ </div>
58
+ </div>
59
+
60
+ <div className="px-4 lg:max-w-(--breakpoint-lg) md:mx-auto">
61
+ <h3
62
+ id="libraries"
63
+ className={`text-4xl font-light mb-6 scroll-mt-24`}
64
+ >
65
+ <a
66
+ href="#libraries"
67
+ className="hover:underline decoration-gray-400 dark:decoration-gray-600"
68
+ >
69
+ Projects
70
+ </a>
71
+ </h3>
72
+
73
+ <div
74
+ className={`grid grid-cols-1 gap-6 gap-y-8 justify-center
75
+ sm:grid-cols-2 md:grid-cols-3 xl:grid-cols-3`}
76
+ >
77
+ {projects.map((project, i) => {
78
+ return (
79
+ <LibraryCard key={project.id} index={i} project={project} />
80
+ )
81
+ })}
82
+ </div>
83
+ </div>
84
+
85
+ <div className={`h-20`} />
86
+ <Footer />
87
+ </div>
88
+ )
89
+ }
@@ -0,0 +1,182 @@
1
+ /**
2
+ * Site-wide configuration. Customize this for your project.
3
+ */
4
+ import type { SiteConfig, ProjectConfig } from '~/types'
5
+
6
+ export const siteConfig: SiteConfig = {
7
+ /** Displayed in the navbar and page title */
8
+ name: 'TanStack',
9
+ /** Project description shown on landing page */
10
+ description: 'High-quality open-source software for web developers',
11
+ /** Repository URL — used for "Edit on GitHub" links */
12
+ repo: 'https://github.com/nicepkg/docs-i18n',
13
+ /** Default locale (must exist in `supportedLocales`) */
14
+ defaultLocale: 'en',
15
+ /** All locales the site supports */
16
+ supportedLocales: {
17
+ en: 'English',
18
+ 'zh-hans': '简体中文',
19
+ ja: '日本語',
20
+ es: 'Español',
21
+ },
22
+ /** Default project ID to redirect to from / */
23
+ defaultProject: 'query',
24
+ /** Projects configured for this site */
25
+ projects: [
26
+ {
27
+ id: 'query',
28
+ name: 'TanStack Query',
29
+ type: 'doc',
30
+ repo: 'tanstack/query',
31
+ latestVersion: 'v5',
32
+ latestBranch: 'main',
33
+ availableVersions: ['v5', 'v4', 'v3'],
34
+ docsRoot: 'content/query',
35
+ defaultDocs: 'overview',
36
+ frameworks: ['react', 'vue', 'solid', 'svelte', 'angular'],
37
+ colorFrom: 'from-red-500',
38
+ colorTo: 'to-amber-500',
39
+ textColor: 'text-amber-500',
40
+ bgStyle: 'bg-red-500',
41
+ borderStyle: 'border-red-500/50',
42
+ textStyle: 'text-red-500',
43
+ tagline:
44
+ 'Powerful asynchronous state management, server-state utilities and data fetching',
45
+ description:
46
+ 'Fetch, cache, update, and wrangle all forms of async data in your TS/JS, React, Vue, Solid, Svelte & Angular applications all without touching any "global state".',
47
+ },
48
+ {
49
+ id: 'router',
50
+ name: 'TanStack Router',
51
+ type: 'doc',
52
+ repo: 'tanstack/router',
53
+ latestVersion: 'v1',
54
+ latestBranch: 'main',
55
+ availableVersions: ['v1'],
56
+ docsRoot: 'content/router',
57
+ defaultDocs: 'overview',
58
+ frameworks: ['react'],
59
+ colorFrom: 'from-emerald-500',
60
+ colorTo: 'to-lime-600',
61
+ textColor: 'text-emerald-500',
62
+ bgStyle: 'bg-emerald-500',
63
+ borderStyle: 'border-emerald-500/50',
64
+ textStyle: 'text-emerald-500',
65
+ tagline: 'Type-safe routing for React applications',
66
+ description:
67
+ 'A powerful React router for client-side and full-stack applications. Fully type-safe APIs, first-class search-params for managing state in the URL.',
68
+ },
69
+ {
70
+ id: 'table',
71
+ name: 'TanStack Table',
72
+ type: 'doc',
73
+ repo: 'tanstack/table',
74
+ latestVersion: 'v8',
75
+ latestBranch: 'main',
76
+ availableVersions: ['v8'],
77
+ docsRoot: 'content/table',
78
+ defaultDocs: 'overview',
79
+ frameworks: ['react', 'vue', 'solid', 'svelte'],
80
+ colorFrom: 'from-cyan-500',
81
+ colorTo: 'to-blue-600',
82
+ textColor: 'text-blue-600',
83
+ bgStyle: 'bg-blue-500',
84
+ borderStyle: 'border-blue-500/50',
85
+ textStyle: 'text-blue-500',
86
+ tagline: 'Headless UI for building powerful tables & datagrids',
87
+ description:
88
+ 'Supercharge your tables or build a datagrid from scratch for TS/JS, React, Vue, Solid & Svelte while retaining 100% control over markup and styles.',
89
+ },
90
+ {
91
+ id: 'form',
92
+ name: 'TanStack Form',
93
+ type: 'doc',
94
+ repo: 'tanstack/form',
95
+ latestVersion: 'v1',
96
+ latestBranch: 'main',
97
+ availableVersions: ['v1'],
98
+ docsRoot: 'content/form',
99
+ defaultDocs: 'overview',
100
+ frameworks: ['react', 'vue', 'angular'],
101
+ colorFrom: 'from-yellow-500',
102
+ colorTo: 'to-yellow-600',
103
+ textColor: 'text-yellow-600',
104
+ bgStyle: 'bg-yellow-500',
105
+ borderStyle: 'border-yellow-500/50',
106
+ textStyle: 'text-yellow-500',
107
+ badge: 'NEW',
108
+ tagline: 'Headless UI for building performant and type-safe forms',
109
+ description:
110
+ 'Headless, performant, and type-safe form state management for TS/JS, React, Vue & Angular.',
111
+ },
112
+ {
113
+ id: 'virtual',
114
+ name: 'TanStack Virtual',
115
+ type: 'doc',
116
+ repo: 'tanstack/virtual',
117
+ latestVersion: 'v3',
118
+ latestBranch: 'main',
119
+ availableVersions: ['v3'],
120
+ docsRoot: 'content/virtual',
121
+ defaultDocs: 'overview',
122
+ frameworks: ['react', 'vue', 'solid', 'svelte'],
123
+ colorFrom: 'from-purple-500',
124
+ colorTo: 'to-violet-600',
125
+ textColor: 'text-purple-600',
126
+ bgStyle: 'bg-purple-500',
127
+ borderStyle: 'border-purple-500/50',
128
+ textStyle: 'text-purple-500',
129
+ tagline: 'Headless UI for virtualizing large element lists',
130
+ description:
131
+ 'Virtualize only the visible content for massive scrollable DOM nodes at 60FPS in TS/JS, React, Vue, Solid & Svelte while retaining 100% control over markup and styles.',
132
+ },
133
+ ],
134
+ features: {
135
+ frameworkSelector: true,
136
+ versionSelector: true,
137
+ editOnGithub: true,
138
+ },
139
+ }
140
+
141
+ /**
142
+ * Find a project by ID. Returns undefined if not found.
143
+ */
144
+ export function findProject(id: string): ProjectConfig | undefined {
145
+ return siteConfig.projects.find((p) => p.id === id)
146
+ }
147
+
148
+ /**
149
+ * Get a project by ID. Throws if not found.
150
+ */
151
+ export function getProject(id: string): ProjectConfig {
152
+ const project = findProject(id)
153
+ if (!project) {
154
+ throw new Error(`Project not found: ${id}`)
155
+ }
156
+ return project
157
+ }
158
+
159
+ /**
160
+ * Get all doc-type projects.
161
+ */
162
+ export function getDocProjects(): ProjectConfig[] {
163
+ return siteConfig.projects.filter((p) => p.type === 'doc')
164
+ }
165
+
166
+ /**
167
+ * Whether this site has only one project (enables simplified URLs).
168
+ */
169
+ export function isSingleProject(): boolean {
170
+ return siteConfig.projects.length <= 1
171
+ }
172
+
173
+ /**
174
+ * Get the single/default project. Throws if no projects configured.
175
+ */
176
+ export function getSingleProject(): ProjectConfig {
177
+ const projectId = siteConfig.defaultProject || siteConfig.projects[0]?.id
178
+ if (!projectId) {
179
+ throw new Error('No projects configured in site.config.ts')
180
+ }
181
+ return getProject(projectId)
182
+ }