From d408615f3e5865399870272c6d1aaa91ffb4598f Mon Sep 17 00:00:00 2001 From: Tanner Linsley Date: Mon, 12 Oct 2026 23:02:59 -0600 Subject: [PATCH 1/2] Add Cloudflare-hosted Start launch video and poster --- src/blog/tanstack-start-1-0.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/blog/tanstack-start-1-0.md b/src/blog/tanstack-start-1-0.md index f75c4706e..2bd2852ec 100644 --- a/src/blog/tanstack-start-1-0.md +++ b/src/blog/tanstack-start-1-0.md @@ -1,14 +1,16 @@ --- -title: TanStack Start 1.0 +title: TanStack Start 1.0 is Stable published: 2026-10-13 draft: true excerpt: TanStack Start 1.0 is stable and ready for production. authors: - Tanner Linsley library: start +headerImage: https://media.tanstack.com/blog/tanstack-start-1-0/v11-poster.jpg +headerVideo: https://media.tanstack.com/blog/tanstack-start-1-0/v11.mp4 --- -# TanStack Start 1.0 +# TanStack Start 1.0 is Stable _With contributions from [Manuel Schiller](https://github.com/schiller-manuel), [Florian Pellet](https://github.com/sheraff), and [Christopher Horobin](https://github.com/chorobin)._ From 041458bb4a5bc11110543e3d6917d9e67f31d270 Mon Sep 17 00:00:00 2001 From: Tanner Linsley Date: Mon, 12 Oct 2026 23:38:34 -0600 Subject: [PATCH 2/2] Polish blog headers and Start launch video poster --- content-collections.ts | 1 + src/blog/tanstack-start-1-0.md | 10 +- src/routes/blog.$.tsx | 185 +++++++++++++++++++++++++++++---- src/utils/blog.functions.ts | 11 +- 4 files changed, 172 insertions(+), 35 deletions(-) diff --git a/content-collections.ts b/content-collections.ts index 772a71c61..27d4b8eba 100644 --- a/content-collections.ts +++ b/content-collections.ts @@ -34,6 +34,7 @@ const posts = defineCollection({ rss: z.boolean().optional(), excerpt: z.string(), authors: z.string().array(), + contributors: z.string().array().optional(), library: libraryListSchema.optional(), headerImage: z.string().optional(), headerVideo: z.string().optional(), diff --git a/src/blog/tanstack-start-1-0.md b/src/blog/tanstack-start-1-0.md index 2bd2852ec..b3596ea6d 100644 --- a/src/blog/tanstack-start-1-0.md +++ b/src/blog/tanstack-start-1-0.md @@ -5,20 +5,22 @@ draft: true excerpt: TanStack Start 1.0 is stable and ready for production. authors: - Tanner Linsley +contributors: + - Manuel Schiller + - Florian Pellet + - Christopher Horobin library: start -headerImage: https://media.tanstack.com/blog/tanstack-start-1-0/v11-poster.jpg +headerImage: https://media.tanstack.com/blog/tanstack-start-1-0/v11-title-poster.jpg headerVideo: https://media.tanstack.com/blog/tanstack-start-1-0/v11.mp4 --- # TanStack Start 1.0 is Stable -_With contributions from [Manuel Schiller](https://github.com/schiller-manuel), [Florian Pellet](https://github.com/sheraff), and [Christopher Horobin](https://github.com/chorobin)._ - TanStack Start 1.0 is finally stable. And we're really excited to officially call it ready for production. I can't begin to say how proud I am of what we've built here and of the people who have built it. For a long time, I'd hear from people already running Start in production and have to remind them we were still in RC (that conversation happened a lot more than you'd think). I'm really glad we can finally drop that caveat. -We've had tons of people put Start into production through pretty much every stage of its development, from small projects and startups to entire enterprise teams and Fortune 500 companies. To our surprise, so many of these companies insisted on using it even when it was in beta. We'd explain where things were, and they'd basically tell us we're going to use it anyway. +We've had tons of people put Start into production through pretty much every stage of its development, from small projects and startups to entire enterprise teams and Fortune 500 companies. To our surprise, so many of these companies insisted on using it even when it was in beta. We'd explain where things were, and they'd basically tell us, "we're going to use it anyway." When enterprise teams are insisting on putting your beta software into production before it's even a release candidate, it's difficult to not feel the massive level of trust everybody is putting in you. So even though people have been successfully using Start in production for a long time, this is us making our formal commitment to the APIs we've built and the people building on them. You can now choose Start, learn it, ship something with it, and continue to build without wondering whether we're going to change the entire way your application works. diff --git a/src/routes/blog.$.tsx b/src/routes/blog.$.tsx index 2afb0010a..87608c97f 100644 --- a/src/routes/blog.$.tsx +++ b/src/routes/blog.$.tsx @@ -1,6 +1,7 @@ import { createFileRoute } from '@tanstack/react-router' import { PostNotFound } from './blog' import * as React from 'react' +import { PlayIcon } from '@phosphor-icons/react' import { MarkdownContent } from '~/components/markdown' import { Card } from '~/components/Card' import { LibrariesWidget } from '~/components/LibrariesWidget' @@ -12,6 +13,7 @@ import { useMediaQuery } from '~/utils/useMediaQuery' import { Toc } from '~/components/Toc' import { Breadcrumbs } from '~/components/Breadcrumbs' +import { findMaintainerByAuthorName } from '~/utils/authors' import { CoverFallback } from '~/components/CoverFallback' import { fetchBlogPost } from '~/utils/blog.functions' import { parseSiteMarkdown } from '~/utils/markdown' @@ -42,6 +44,9 @@ export const Route = createFileRoute('/blog/$')({ function BlogPost() { const { content, + authors, + contributors, + published, filePath, title, headerImage, @@ -50,7 +55,13 @@ function BlogPost() { library, } = Route.useLoaderData() const { _splat: slug } = Route.useParams() - const markdown = React.useMemo(() => parseSiteMarkdown(content), [content]) + const videoRef = React.useRef(null) + const [startedVideo, setStartedVideo] = React.useState() + const hasStartedVideo = startedVideo === headerVideo + const markdown = React.useMemo( + () => parseSiteMarkdown(content.replace(/^# [^\n]+\n*/m, '')), + [content], + ) const headings = markdown.headings const isTocVisible = headings.length > 1 @@ -146,23 +157,157 @@ function BlogPost() { ].join(' ')} >
- {headerVideo ? ( - + {new Intl.DateTimeFormat('en-US', { + weekday: 'long', + month: 'long', + day: 'numeric', + year: 'numeric', + timeZone: 'UTC', + }).format(new Date(`${published}T00:00:00Z`))} + +

+ {title} +

+
+
+
+ Posted by +
+
+ {authors.map((name) => { + const author = findMaintainerByAuthorName(name) + return author ? ( + + +
+
+ {name} +
+
+ @{author.github} +
+
+
+ ) : ( + + {name} + + ) + })} +
+
+ {contributors.length ? ( +
+
+ With contributions from +
+
+
+ {contributors.map((name) => { + const person = + findMaintainerByAuthorName(name) + return person ? ( + + + + ) : null + })} +
+
+ {contributors.map((name, index) => { + const person = + findMaintainerByAuthorName(name) + return ( + + {index ? ', ' : ''} + {person ? ( + + {name} + + ) : ( + name + )} + + ) + })} +
+
+
+ ) : null} +
+ + {headerVideo ? ( +
+ + {!hasStartedVideo ? ( + + ) : null} +
) : null} {!headerImage && slug ? ( ) : null} heading.level === 1) - ? '' - : title - } + title="" markdown={markdown} preserveTabPanels repo={repo} diff --git a/src/utils/blog.functions.ts b/src/utils/blog.functions.ts index 9ea5f52cf..cb859c323 100644 --- a/src/utils/blog.functions.ts +++ b/src/utils/blog.functions.ts @@ -13,8 +13,6 @@ import { } from '~/utils/blog' import { type BlogCardPost, - formatAuthors, - formatPublishedDate, getBlogAuthorIdentities, getBlogLibraries, isBlogPostUnpublished, @@ -121,18 +119,13 @@ export const fetchBlogPost = createServerFn({ method: 'GET' }) ) const authors = normalizeBlogAuthors(post.authors) - const blogContent = `by ${formatAuthors(authors)} on ${formatPublishedDate( - post.published || '1970-01-01', - )}. - -${post.content}` - const isUnpublished = isBlogPostUnpublished(post) return { authorIdentities: getBlogAuthorIdentities(authors, allMaintainers), authors, - content: blogContent, + content: post.content, + contributors: post.contributors ?? [], description: post.excerpt, filePath: `src/blog/${data}.md`, headerImage: post.headerImage,