Skip to content
Merged
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
4 changes: 2 additions & 2 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ src/
│ └── data-grid-render/ # Data Grid cell renderer showcase (internal)
│
├── components/
│ ├── data-table/ # Data Table UI components (toolbar, filters, pagination…)
│ ├── data-grid/ # Data Grid UI components (cells, menus, presence…)
│ ├── data-table/ # Data Table ui components (toolbar, filters, pagination…)
│ ├── data-grid/ # Data Grid ui components (cells, menus, presence…)
│ ├── layouts/ # Site header and mobile navigation
│ └── ui/ # shadcn/ui primitives
│
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,10 @@ import { useWindowSize } from "@/hooks/use-window-size";
import { getCellKey } from "@/lib/data-grid";
import { getFilterFn } from "@/lib/data-grid-filters";
import { generateId } from "@/lib/id";
import { multiplayerCollection } from "../lib/multiplayer-collection";
import {
multiplayerCollection,
serializeSkater,
} from "../lib/multiplayer-collection";
import { DataGridPresenceAvatars } from "./data-grid-presence-avatars";

const stanceOptions = skaters.stance.enumValues.map((stance) => ({
Expand All @@ -62,15 +65,6 @@ const trickOptions = TRICKS.map((trick) => ({
value: trick,
}));

function toWire(row: SkaterSchema): Record<string, unknown> {
return {
...row,
startedSkating: row.startedSkating?.toISOString() ?? null,
createdAt: row.createdAt.toISOString(),
updatedAt: row.updatedAt?.toISOString() ?? null,
};
}

interface DataGridMultiplayerDemoProps {
roomId: string;
}
Expand All @@ -86,11 +80,13 @@ export function DataGridMultiplayerDemo({
let query = q.from({ skater: multiplayerCollection });
for (const sort of sorting) {
const field = sort.id as keyof SkaterSchema;

query = query.orderBy(
(t) => t.skater[field],
sort.desc ? "desc" : "asc",
);
}

query = query.orderBy((t) => t.skater.order, "asc");
return query;
},
Expand Down Expand Up @@ -158,7 +154,8 @@ export function DataGridMultiplayerDemo({
}
}
}
if (insertedRows.length > 0) sendRowsAdd(insertedRows.map(toWire));
if (insertedRows.length > 0)
sendRowsAdd(insertedRows.map(serializeSkater));
},
[data, sendRowsDelete, sendRowsAdd, sendCellUpdate],
);
Expand Down Expand Up @@ -322,7 +319,7 @@ export function DataGridMultiplayerDemo({
};

multiplayerCollection.insert(newSkater);
sendRowAdd(toWire(newSkater));
sendRowAdd(serializeSkater(newSkater));
trackRowsAdd([newSkater]);

return { rowIndex: data.length, columnId: "name" };
Expand Down Expand Up @@ -355,7 +352,7 @@ export function DataGridMultiplayerDemo({
multiplayerCollection.insert(newSkater);
}

sendRowsAdd(newRows.map(toWire));
sendRowsAdd(newRows.map(serializeSkater));
trackRowsAdd(newRows);
},
[data, trackRowsAdd, sendRowsAdd],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,30 +3,21 @@
import dynamic from "next/dynamic";
import { useRouter, useSearchParams } from "next/navigation";
import * as React from "react";
import {
DataGridSkeleton,
DataGridSkeletonGrid,
DataGridSkeletonToolbar,
} from "@/components/data-grid/data-grid-skeleton";
import { generateId } from "@/lib/id";
import { DataGridMultiplayerSkeleton } from "./data-grid-multiplayer-skeleton";

const DataGridMultiplayerDemo = dynamic(
() =>
import("./components/data-grid-multiplayer-demo").then(
import("./data-grid-multiplayer-demo").then(
(mod) => mod.DataGridMultiplayerDemo,
),
{
ssr: false,
loading: () => (
<DataGridSkeleton className="container flex flex-col gap-4 py-4">
<DataGridSkeletonToolbar actionCount={5} />
<DataGridSkeletonGrid />
</DataGridSkeleton>
),
loading: () => <DataGridMultiplayerSkeleton />,
},
);

export function DataGridMultiplayerPageClient() {
export function DataGridMultiplayerRoom() {
const router = useRouter();
const searchParams = useSearchParams();
const roomId = searchParams.get("room");
Expand All @@ -42,12 +33,7 @@ export function DataGridMultiplayerPageClient() {
}, [roomId, router]);

if (!roomId) {
return (
<DataGridSkeleton className="container flex flex-col gap-4 py-4">
<DataGridSkeletonToolbar actionCount={5} />
<DataGridSkeletonGrid />
</DataGridSkeleton>
);
return <DataGridMultiplayerSkeleton />;
}

return <DataGridMultiplayerDemo roomId={roomId} />;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import {
DataGridSkeleton,
DataGridSkeletonGrid,
DataGridSkeletonToolbar,
} from "@/components/data-grid/data-grid-skeleton";

export function DataGridMultiplayerSkeleton() {
return (
<DataGridSkeleton className="container flex flex-col gap-4 py-4">
<DataGridSkeletonToolbar actionCount={5} />
<DataGridSkeletonGrid />
</DataGridSkeleton>
);
}
9 changes: 9 additions & 0 deletions src/app/data-grid-multiplayer/lib/multiplayer-collection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,12 @@ export const multiplayerCollection = createCollection(
getKey: (item: SkaterSchema) => item.id,
}),
);

export function serializeSkater(row: SkaterSchema): Record<string, unknown> {
return {
...row,
startedSkating: row.startedSkating?.toISOString() ?? null,
createdAt: row.createdAt.toISOString(),
updatedAt: row.updatedAt?.toISOString() ?? null,
};
}
21 changes: 4 additions & 17 deletions src/app/data-grid-multiplayer/page.tsx
Original file line number Diff line number Diff line change
@@ -1,24 +1,11 @@
import { Suspense } from "react";
import {
DataGridSkeleton,
DataGridSkeletonGrid,
DataGridSkeletonToolbar,
} from "@/components/data-grid/data-grid-skeleton";
import { DataGridMultiplayerPageClient } from "./multiplayer-page-client";

function MultiplayerFallback() {
return (
<DataGridSkeleton className="container flex flex-col gap-4 py-4">
<DataGridSkeletonToolbar actionCount={5} />
<DataGridSkeletonGrid />
</DataGridSkeleton>
);
}
import { DataGridMultiplayerRoom } from "./components/data-grid-multiplayer-room";
import { DataGridMultiplayerSkeleton } from "./components/data-grid-multiplayer-skeleton";

export default function DataGridMultiplayerPage() {
return (
<Suspense fallback={<MultiplayerFallback />}>
<DataGridMultiplayerPageClient />
<Suspense fallback={<DataGridMultiplayerSkeleton />}>
<DataGridMultiplayerRoom />
</Suspense>
);
}
7 changes: 6 additions & 1 deletion src/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,14 @@ export const metadata: Metadata = {
"nextjs",
"react",
"table",
"react-table",
"data-table",
"data-grid",
"tanstack-table",
"tanstack-db",
"shadcn-ui",
"shadcn-table",
"partykit",
"multiplayer",
"tablecn",
],
authors: [
Expand Down
10 changes: 6 additions & 4 deletions src/app/sitemap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@ import type { MetadataRoute } from "next";
import { siteConfig } from "@/config/site";

export default function sitemap(): MetadataRoute.Sitemap {
const routes = [""].map((route) => ({
url: `${siteConfig.url}${route}`,
lastModified: new Date().toISOString(),
}));
const routes = ["", ...siteConfig.navLinks.map(({ href }) => href)].map(
(route) => ({
url: `${siteConfig.url}${route}`,
lastModified: new Date().toISOString(),
}),
);

return [...routes];
}
Loading