+
+
+
+
+
+
+
+
+
+
+
+
+
+
}>
+
{
+ // displaying readme is under suspense, so the router doesn't wait for it to be ready
+ // it will be rendered after the page is already visible,
+ // so we fade it in, but only during client-side navigation
+ if (!el.isConnected) {
+ el.style.opacity = "0";
+ el.style.transition = "opacity 0.3s ease-in-out";
+ onMount(() => {
+ requestAnimationFrame(() => (el.style.opacity = ""));
+ });
+ }
+
+ createPrimitiveNameTooltips(el, () => data().primitives);
+ }}
+ innerHTML={data().readme}
+ />
+
+
+
+
+ >
+ );
+}
diff --git a/site/src/routes/playground/$name.tsx~next b/site/src/routes/playground/$name.tsx~next
new file mode 100644
index 000000000..b5fe242ce
--- /dev/null
+++ b/site/src/routes/playground/$name.tsx~next
@@ -0,0 +1,67 @@
+import { type Component, Suspense, lazy } from "solid-js";
+import { Dynamic } from "solid-js/web";
+import { createFileRoute, notFound } from "@tanstack/solid-router";
+import { HEADER_HEIGHT } from "~/components/Header/Header.jsx";
+import NotFound from "~/components/NotFound.jsx";
+import { ClientOnly } from "~/primitives/client-only.js";
+import { kebabCaseToCapitalized } from "~/utils.js";
+import "./-playground.scss";
+
+const modules = Object.entries(
+ import.meta.glob([
+ "../../../../packages/*/dev/index.tsx",
+ // `filesystem` pulls in `chokidar`/`fsevents` which are Node-only and
+ // cannot be bundled for the browser.
+ "!../../../../packages/filesystem/**",
+ ]),
+).reduce(
+ (acc, [path, fn]) => {
+ const name = path.split("/").at(-3);
+ if (name) acc[name] = lazy(fn as any);
+ return acc;
+ },
+ {} as Record
,
+);
+
+export const Route = createFileRoute("/playground/$name")({
+ component: PlaygroundPage,
+ // Render the 404 page for unknown package names (e.g. /playground/wefwe)
+ // instead of an empty playground. The loader checks the glob-generated
+ // `modules` map and throws `notFound()` when there's no match.
+ notFoundComponent: NotFound,
+ loader: ({ params }) => {
+ if (!(params.name in modules)) throw notFound();
+ return null;
+ },
+ head: ({ params, loaderData }) => ({
+ meta: [
+ {
+ title:
+ loaderData === null
+ ? `${kebabCaseToCapitalized(params.name)} — Playground`
+ : "Not Found — Solid Primitives",
+ },
+ ],
+ }),
+});
+
+function PlaygroundPage() {
+ const params = Route.useParams();
+ const formattedName = () => kebabCaseToCapitalized(params().name);
+
+ return (
+
+
+
{formattedName()} — Playground
+
+
+
+
+
+
+
+
+
+
+ );
+}
diff --git a/site/src/routes/playground/$name.tsx~port to tanstack start v1 b/site/src/routes/playground/$name.tsx~port to tanstack start v1
new file mode 100644
index 000000000..a68300e00
--- /dev/null
+++ b/site/src/routes/playground/$name.tsx~port to tanstack start v1
@@ -0,0 +1,51 @@
+import { type Component, Suspense, lazy } from "solid-js";
+import { Dynamic } from "solid-js/web";
+import { createFileRoute } from "@tanstack/solid-router";
+import { HEADER_HEIGHT } from "~/components/Header/Header.jsx";
+import { ClientOnly } from "~/primitives/client-only.js";
+import { kebabCaseToCapitalized } from "~/utils.js";
+import "./-playground.scss";
+
+const modules = Object.entries(
+ import.meta.glob([
+ "../../../../packages/*/dev/index.tsx",
+ // `filesystem` pulls in `chokidar`/`fsevents` which are Node-only and
+ // cannot be bundled for the browser.
+ "!../../../../packages/filesystem/**",
+ ]),
+).reduce(
+ (acc, [path, fn]) => {
+ const name = path.split("/").at(-3);
+ if (name) acc[name] = lazy(fn as any);
+ return acc;
+ },
+ {} as Record,
+);
+
+export const Route = createFileRoute("/playground/$name")({
+ component: PlaygroundPage,
+ head: ({ params }) => ({
+ meta: [{ title: `${kebabCaseToCapitalized(params.name)} — Playground` }],
+ }),
+});
+
+function PlaygroundPage() {
+ const params = Route.useParams();
+ const formattedName = () => kebabCaseToCapitalized(params().name);
+
+ return (
+
+
+
{formattedName()} — Playground
+
+
+
+
+
+
+
+
+
+
+ );
+}