mirror of
https://github.com/FranP-code/Reflecto.git
synced 2025-10-13 00:43:31 +00:00
feat: add Space route with Tldraw integration and session validation
This commit is contained in:
2
.vscode/settings.json
vendored
2
.vscode/settings.json
vendored
@@ -32,5 +32,5 @@
|
||||
"source.fixAll.biome": "explicit",
|
||||
"source.organizeImports.biome": "explicit"
|
||||
},
|
||||
"cSpell.words": ["Reflecto"]
|
||||
"cSpell.words": ["Reflecto", "Tldraw"]
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
"react-dom": "^19.0.0",
|
||||
"sonner": "^2.0.5",
|
||||
"tailwind-merge": "^3.3.1",
|
||||
"tldraw": "^3.15.4",
|
||||
"tw-animate-css": "^1.2.5",
|
||||
"vite-plugin-pwa": "^1.0.1",
|
||||
"zod": "^4.0.2"
|
||||
|
||||
@@ -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.
|
||||
|
||||
import { Route as rootRouteImport } from './routes/__root'
|
||||
import { Route as SpaceRouteImport } from './routes/space'
|
||||
import { Route as LoginRouteImport } from './routes/login'
|
||||
import { Route as DashboardRouteImport } from './routes/dashboard'
|
||||
import { Route as IndexRouteImport } from './routes/index'
|
||||
|
||||
const SpaceRoute = SpaceRouteImport.update({
|
||||
id: '/space',
|
||||
path: '/space',
|
||||
getParentRoute: () => rootRouteImport,
|
||||
} as any)
|
||||
const LoginRoute = LoginRouteImport.update({
|
||||
id: '/login',
|
||||
path: '/login',
|
||||
@@ -33,34 +39,45 @@ export interface FileRoutesByFullPath {
|
||||
'/': typeof IndexRoute
|
||||
'/dashboard': typeof DashboardRoute
|
||||
'/login': typeof LoginRoute
|
||||
'/space': typeof SpaceRoute
|
||||
}
|
||||
export interface FileRoutesByTo {
|
||||
'/': typeof IndexRoute
|
||||
'/dashboard': typeof DashboardRoute
|
||||
'/login': typeof LoginRoute
|
||||
'/space': typeof SpaceRoute
|
||||
}
|
||||
export interface FileRoutesById {
|
||||
__root__: typeof rootRouteImport
|
||||
'/': typeof IndexRoute
|
||||
'/dashboard': typeof DashboardRoute
|
||||
'/login': typeof LoginRoute
|
||||
'/space': typeof SpaceRoute
|
||||
}
|
||||
export interface FileRouteTypes {
|
||||
fileRoutesByFullPath: FileRoutesByFullPath
|
||||
fullPaths: '/' | '/dashboard' | '/login'
|
||||
fullPaths: '/' | '/dashboard' | '/login' | '/space'
|
||||
fileRoutesByTo: FileRoutesByTo
|
||||
to: '/' | '/dashboard' | '/login'
|
||||
id: '__root__' | '/' | '/dashboard' | '/login'
|
||||
to: '/' | '/dashboard' | '/login' | '/space'
|
||||
id: '__root__' | '/' | '/dashboard' | '/login' | '/space'
|
||||
fileRoutesById: FileRoutesById
|
||||
}
|
||||
export interface RootRouteChildren {
|
||||
IndexRoute: typeof IndexRoute
|
||||
DashboardRoute: typeof DashboardRoute
|
||||
LoginRoute: typeof LoginRoute
|
||||
SpaceRoute: typeof SpaceRoute
|
||||
}
|
||||
|
||||
declare module '@tanstack/react-router' {
|
||||
interface FileRoutesByPath {
|
||||
'/space': {
|
||||
id: '/space'
|
||||
path: '/space'
|
||||
fullPath: '/space'
|
||||
preLoaderRoute: typeof SpaceRouteImport
|
||||
parentRoute: typeof rootRouteImport
|
||||
}
|
||||
'/login': {
|
||||
id: '/login'
|
||||
path: '/login'
|
||||
@@ -89,6 +106,7 @@ const rootRouteChildren: RootRouteChildren = {
|
||||
IndexRoute: IndexRoute,
|
||||
DashboardRoute: DashboardRoute,
|
||||
LoginRoute: LoginRoute,
|
||||
SpaceRoute: SpaceRoute,
|
||||
}
|
||||
export const routeTree = rootRouteImport
|
||||
._addFileChildren(rootRouteChildren)
|
||||
|
||||
36
apps/web/src/routes/space.tsx
Normal file
36
apps/web/src/routes/space.tsx
Normal 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
785
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user