feat: add Space route with Tldraw integration and session validation

This commit is contained in:
2025-09-04 00:23:00 -03:00
parent b3c491561b
commit 6360efbab1
5 changed files with 844 additions and 4 deletions

View File

@@ -32,5 +32,5 @@
"source.fixAll.biome": "explicit", "source.fixAll.biome": "explicit",
"source.organizeImports.biome": "explicit" "source.organizeImports.biome": "explicit"
}, },
"cSpell.words": ["Reflecto"] "cSpell.words": ["Reflecto", "Tldraw"]
} }

View File

@@ -34,6 +34,7 @@
"react-dom": "^19.0.0", "react-dom": "^19.0.0",
"sonner": "^2.0.5", "sonner": "^2.0.5",
"tailwind-merge": "^3.3.1", "tailwind-merge": "^3.3.1",
"tldraw": "^3.15.4",
"tw-animate-css": "^1.2.5", "tw-animate-css": "^1.2.5",
"vite-plugin-pwa": "^1.0.1", "vite-plugin-pwa": "^1.0.1",
"zod": "^4.0.2" "zod": "^4.0.2"

View File

@@ -9,10 +9,16 @@
// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. // Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified.
import { Route as rootRouteImport } from './routes/__root' import { Route as rootRouteImport } from './routes/__root'
import { Route as SpaceRouteImport } from './routes/space'
import { Route as LoginRouteImport } from './routes/login' import { Route as LoginRouteImport } from './routes/login'
import { Route as DashboardRouteImport } from './routes/dashboard' import { Route as DashboardRouteImport } from './routes/dashboard'
import { Route as IndexRouteImport } from './routes/index' import { Route as IndexRouteImport } from './routes/index'
const SpaceRoute = SpaceRouteImport.update({
id: '/space',
path: '/space',
getParentRoute: () => rootRouteImport,
} as any)
const LoginRoute = LoginRouteImport.update({ const LoginRoute = LoginRouteImport.update({
id: '/login', id: '/login',
path: '/login', path: '/login',
@@ -33,34 +39,45 @@ export interface FileRoutesByFullPath {
'/': typeof IndexRoute '/': typeof IndexRoute
'/dashboard': typeof DashboardRoute '/dashboard': typeof DashboardRoute
'/login': typeof LoginRoute '/login': typeof LoginRoute
'/space': typeof SpaceRoute
} }
export interface FileRoutesByTo { export interface FileRoutesByTo {
'/': typeof IndexRoute '/': typeof IndexRoute
'/dashboard': typeof DashboardRoute '/dashboard': typeof DashboardRoute
'/login': typeof LoginRoute '/login': typeof LoginRoute
'/space': typeof SpaceRoute
} }
export interface FileRoutesById { export interface FileRoutesById {
__root__: typeof rootRouteImport __root__: typeof rootRouteImport
'/': typeof IndexRoute '/': typeof IndexRoute
'/dashboard': typeof DashboardRoute '/dashboard': typeof DashboardRoute
'/login': typeof LoginRoute '/login': typeof LoginRoute
'/space': typeof SpaceRoute
} }
export interface FileRouteTypes { export interface FileRouteTypes {
fileRoutesByFullPath: FileRoutesByFullPath fileRoutesByFullPath: FileRoutesByFullPath
fullPaths: '/' | '/dashboard' | '/login' fullPaths: '/' | '/dashboard' | '/login' | '/space'
fileRoutesByTo: FileRoutesByTo fileRoutesByTo: FileRoutesByTo
to: '/' | '/dashboard' | '/login' to: '/' | '/dashboard' | '/login' | '/space'
id: '__root__' | '/' | '/dashboard' | '/login' id: '__root__' | '/' | '/dashboard' | '/login' | '/space'
fileRoutesById: FileRoutesById fileRoutesById: FileRoutesById
} }
export interface RootRouteChildren { export interface RootRouteChildren {
IndexRoute: typeof IndexRoute IndexRoute: typeof IndexRoute
DashboardRoute: typeof DashboardRoute DashboardRoute: typeof DashboardRoute
LoginRoute: typeof LoginRoute LoginRoute: typeof LoginRoute
SpaceRoute: typeof SpaceRoute
} }
declare module '@tanstack/react-router' { declare module '@tanstack/react-router' {
interface FileRoutesByPath { interface FileRoutesByPath {
'/space': {
id: '/space'
path: '/space'
fullPath: '/space'
preLoaderRoute: typeof SpaceRouteImport
parentRoute: typeof rootRouteImport
}
'/login': { '/login': {
id: '/login' id: '/login'
path: '/login' path: '/login'
@@ -89,6 +106,7 @@ const rootRouteChildren: RootRouteChildren = {
IndexRoute: IndexRoute, IndexRoute: IndexRoute,
DashboardRoute: DashboardRoute, DashboardRoute: DashboardRoute,
LoginRoute: LoginRoute, LoginRoute: LoginRoute,
SpaceRoute: SpaceRoute,
} }
export const routeTree = rootRouteImport export const routeTree = rootRouteImport
._addFileChildren(rootRouteChildren) ._addFileChildren(rootRouteChildren)

View File

@@ -0,0 +1,36 @@
import { createFileRoute } from "@tanstack/react-router";
import { useEffect, useMemo } from "react";
import { Tldraw } from "tldraw";
import { z } from "zod";
import "tldraw/tldraw.css";
import { authClient } from "@/lib/auth-client";
export const Route = createFileRoute("/space")({
validateSearch: z.object({
id: z.string().optional(),
}).parse,
component: SpaceRoute,
});
function SpaceRoute() {
const { id } = Route.useSearch();
const { data: session, isPending } = authClient.useSession();
const navigate = Route.useNavigate();
useEffect(() => {
if (!((session || isPending) && id)) {
navigate({
to: "/login",
});
}
}, [session, isPending, navigate, id]);
// Use a stable persistence key so tabs with same id share state locally
const persistenceKey = useMemo(() => `space-${id ?? "default"}`, [id]);
return (
<div className="mx-4 mt-4" style={{ position: "relative", inset: 0 }}>
<Tldraw inferDarkMode persistenceKey={persistenceKey} />
</div>
);
}

785
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff