diff --git a/apps/dotcom/client/src/routeDefs.ts b/apps/dotcom/client/src/routeDefs.ts new file mode 100644 index 000000000000..ef96bb812d0d --- /dev/null +++ b/apps/dotcom/client/src/routeDefs.ts @@ -0,0 +1,91 @@ +import { assert } from 'tldraw' + +export const ROUTES = { + legacyRoot: '/', + legacyNewPage: '/new', + legacyNewPage2: '/r', + legacyRoom: '/r/:roomId', + touchscreenSidePanel: '/ts-side', + legacyRoomHistory: '/r/:boardId/history', + legacyRoomHistorySnapshot: '/r/:boardId/history/:timestamp', + legacySnapshot: '/s/:roomId', + legacyReadonly: '/ro/:roomId', + legacyReadonlyOld: '/v/:roomId', + + tlaRoot: `/q`, + tlaFile: `/q/f/:fileSlug`, + tlaLocalFile: `/q/lf/:fileSlug`, + tlaPlayground: `/q/playground`, + tlaPublish: `/q/p/:fileSlug`, +} as const + +export const routes: { + [key in keyof typeof ROUTES]: PathFn<(typeof ROUTES)[key]> +} = Object.fromEntries( + Object.entries(ROUTES).map(([key, path]) => [ + key, + ((routeParamsOrOptions: any, options: any) => { + if (path.includes('/:')) { + return compilePath(path, routeParamsOrOptions, options) + } else { + return compilePath(path, null, routeParamsOrOptions) + } + }) satisfies PathFn, + ]) +) as any + +type ExtractParamNamesFromPath = route extends `/${infer path}` + ? ExtractParamNamesFromPathSegments> + : never + +type SplitPath = path extends `${infer segment}/${infer rest}` + ? segment | SplitPath + : path + +type ExtractParamNamesFromPathSegments = segments extends `:${infer param}` + ? param + : never + +interface PathOptions { + searchParams?: ConstructorParameters[0] + asUrl?: boolean +} + +type PathFn = path extends `${string}:${string}:${string}` + ? // has at least two params + ( + routeParams: Record, string>, + searchParams?: PathOptions + ) => string + : path extends `${string}:${string}` + ? // only has one param, so we can have a single string + (param: string, searchParams?: PathOptions) => string + : (searchParams?: PathOptions) => string + +function compilePath( + path: string, + routeParams: string | Record | null, + options?: PathOptions +) { + const search = new URLSearchParams(options?.searchParams).toString() + if (!path.includes(':')) { + assert( + routeParams === null || Object.keys(routeParams).length === 0, + `Route params are not allowed for path ${path}` + ) + return path + (search ? `?${search}` : '') + } + assert(routeParams !== null, `Route params are required for path ${path}`) + + path = + path.replace(/:\w+/g, (match) => + // if there's only one param, routeParams will be a string + typeof routeParams === 'string' ? routeParams : routeParams[match.slice(1)] + ) + (search ? `?${search}` : '') + + if (options?.asUrl) { + return `${window.location.origin}${path}` + } + + return path +} diff --git a/apps/dotcom/client/src/routes.tsx b/apps/dotcom/client/src/routes.tsx index 67b0702a7cf1..2e257d7577dd 100644 --- a/apps/dotcom/client/src/routes.tsx +++ b/apps/dotcom/client/src/routes.tsx @@ -1,10 +1,4 @@ import { captureException } from '@sentry/react' -import { - READ_ONLY_LEGACY_PREFIX, - READ_ONLY_PREFIX, - ROOM_PREFIX, - SNAPSHOT_PREFIX, -} from '@tldraw/dotcom-shared' import { TLRemoteSyncError, TLSyncErrorCloseEventReason } from '@tldraw/sync-core' import { Suspense, lazy, useEffect } from 'react' import { Helmet } from 'react-helmet-async' @@ -12,9 +6,9 @@ import { Outlet, Route, createRoutesFromElements, useRouteError } from 'react-ro import { DefaultErrorFallback } from './components/DefaultErrorFallback/DefaultErrorFallback' import { ErrorPage } from './components/ErrorPage/ErrorPage' import { notFound } from './pages/not-found' +import { ROUTES } from './routeDefs' import { IntlProvider } from './tla/utils/i18n' import { TlaNotFoundError } from './tla/utils/notFoundError' -import { PREFIX } from './tla/utils/urls' const LoginRedirectPage = lazy(() => import('./components/LoginRedirectPage/LoginRedirectPage')) @@ -71,55 +65,40 @@ export const router = createRoutesFromElements( }} > }> - import('./pages/root')} /> + import('./pages/root')} /> {/* We don't want to index multiplayer rooms */} }> }> - import('./pages/new')} /> - import('./pages/new')} /> - import('./pages/public-touchscreen-side-panel')} /> + import('./pages/new')} /> + import('./pages/new')} /> import('./pages/public-multiplayer')} + path={ROUTES.touchscreenSidePanel} + lazy={() => import('./pages/public-touchscreen-side-panel')} /> - import('./pages/history')} /> + import('./pages/public-multiplayer')} /> + import('./pages/history')} /> import('./pages/history-snapshot')} /> + import('./pages/public-snapshot')} /> import('./pages/public-snapshot')} - /> - import('./pages/public-readonly-legacy')} /> - import('./pages/public-readonly')} - /> + import('./pages/public-readonly')} /> {/* begin tla */} }> - import('./tla/pages/local-file')} - /> + import('./tla/pages/local-file')} /> import('./tla/providers/TlaRootProviders')}> - import('./tla/pages/local')} /> - {/* import('./tla/pages/playground')} /> */} + import('./tla/pages/local')} /> + {/* import('./tla/pages/playground')} /> */} {/* File view */} - import('./tla/pages/file')} - /> - import('./tla/pages/publish')} - /> + import('./tla/pages/file')} /> + import('./tla/pages/publish')} /> {/* Views that require login */} import('./tla/providers/RequireSignedInUser')}> diff --git a/apps/dotcom/client/src/tla/components/TlaEditor/SlurpFailure.tsx b/apps/dotcom/client/src/tla/components/TlaEditor/SlurpFailure.tsx index 427782ab6e1d..15594cb982cf 100644 --- a/apps/dotcom/client/src/tla/components/TlaEditor/SlurpFailure.tsx +++ b/apps/dotcom/client/src/tla/components/TlaEditor/SlurpFailure.tsx @@ -7,8 +7,8 @@ import { TldrawUiDialogHeader, TldrawUiDialogTitle, } from 'tldraw' +import { routes } from '../../../routeDefs' import { F } from '../../utils/i18n' -import { getLocalFilePath } from '../../utils/urls' import { ExternalLink } from '../ExternalLink/ExternalLink' export function SlurpFailure({ @@ -46,7 +46,7 @@ export function SlurpFailure({

  1. - +
  2. diff --git a/apps/dotcom/client/src/tla/components/TlaErrorContent/TlaErrorContent.tsx b/apps/dotcom/client/src/tla/components/TlaErrorContent/TlaErrorContent.tsx index 080ad850db8f..6b16e0ac2dc1 100644 --- a/apps/dotcom/client/src/tla/components/TlaErrorContent/TlaErrorContent.tsx +++ b/apps/dotcom/client/src/tla/components/TlaErrorContent/TlaErrorContent.tsx @@ -1,7 +1,7 @@ import classNames from 'classnames' import { Link } from 'react-router-dom' +import { routes } from '../../../routeDefs' import { F } from '../../utils/i18n' -import { getRootPath } from '../../utils/urls' import styles from './error.module.css' type TlaPageErrorType = @@ -12,7 +12,7 @@ type TlaPageErrorType = function ErrorLinkHome() { return ( - + ) diff --git a/apps/dotcom/client/src/tla/components/TlaFileMenu/TlaFileMenu.tsx b/apps/dotcom/client/src/tla/components/TlaFileMenu/TlaFileMenu.tsx index 90cccb151a5a..8aa103702e34 100644 --- a/apps/dotcom/client/src/tla/components/TlaFileMenu/TlaFileMenu.tsx +++ b/apps/dotcom/client/src/tla/components/TlaFileMenu/TlaFileMenu.tsx @@ -17,13 +17,13 @@ import { useDialogs, useToasts, } from 'tldraw' +import { routes } from '../../../routeDefs' import { TldrawApp } from '../../app/TldrawApp' import { useApp } from '../../hooks/useAppState' import { useIsFileOwner } from '../../hooks/useIsFileOwner' import { TLAppUiEventSource, useTldrawAppUiEvents } from '../../utils/app-ui-events' import { copyTextToClipboard } from '../../utils/copy' import { defineMessages, useMsg } from '../../utils/i18n' -import { getFilePath, getShareableFileUrl } from '../../utils/urls' import { TlaDeleteFileDialog } from '../dialogs/TlaDeleteFileDialog' const messages = defineMessages({ @@ -92,7 +92,7 @@ function FileItems({ const isOwner = useIsFileOwner(fileId) const handleCopyLinkClick = useCallback(() => { - const url = getShareableFileUrl(fileId) + const url = routes.tlaFile(fileId, { asUrl: true }) copyTextToClipboard(url) addToast({ id: 'copied-link', @@ -106,7 +106,9 @@ function FileItems({ const file = app.getFile(fileId) if (!file) return app.createFile({ id: newFileId, name: getDuplicateName(file, app) }) - navigate(getFilePath(newFileId), { state: { mode: 'duplicate', duplicateId: fileId } }) + navigate(routes.tlaFile(newFileId), { + state: { mode: 'duplicate', duplicateId: fileId }, + }) }, [app, fileId, navigate]) const handleDeleteClick = useCallback(() => { diff --git a/apps/dotcom/client/src/tla/components/TlaFileShareMenu/Tabs/TlaInviteTab.tsx b/apps/dotcom/client/src/tla/components/TlaFileShareMenu/Tabs/TlaInviteTab.tsx index d2ecf18b6b65..a864cfab743e 100644 --- a/apps/dotcom/client/src/tla/components/TlaFileShareMenu/Tabs/TlaInviteTab.tsx +++ b/apps/dotcom/client/src/tla/components/TlaFileShareMenu/Tabs/TlaInviteTab.tsx @@ -1,13 +1,13 @@ import { TlaFile } from '@tldraw/dotcom-shared' import { useCallback } from 'react' import { useEditor, useValue } from 'tldraw' +import { routes } from '../../../../routeDefs' import { useApp } from '../../../hooks/useAppState' import { useIsFileOwner } from '../../../hooks/useIsFileOwner' import { useTldrawUser } from '../../../hooks/useUser' import { useTldrawAppUiEvents } from '../../../utils/app-ui-events' import { copyTextToClipboard } from '../../../utils/copy' import { F, defineMessages, useMsg } from '../../../utils/i18n' -import { getShareableFileUrl } from '../../../utils/urls' import { TlaSelect } from '../../TlaSelect/TlaSelect' import { TlaSwitch } from '../../TlaSwitch/TlaSwitch' import { @@ -48,7 +48,7 @@ export function TlaInviteTab({ fileId }: { fileId: string }) { )} {isShared && } - {isShared && } + {isShared && } ) @@ -140,7 +140,7 @@ function TlaCopyLinkButton({ fileId }: { isShared: boolean; fileId: string }) { const trackEvent = useTldrawAppUiEvents() const handleCopyLinkClick = useCallback(() => { - const url = getShareableFileUrl(fileId) + const url = routes.tlaFile(fileId, { asUrl: true }) copyTextToClipboard(editor.createDeepLink({ url }).toString()) // no toasts please trackEvent('copy-share-link', { source: 'file-share-menu' }) diff --git a/apps/dotcom/client/src/tla/components/TlaFileShareMenu/Tabs/TlaPublishTab.tsx b/apps/dotcom/client/src/tla/components/TlaFileShareMenu/Tabs/TlaPublishTab.tsx index 09e116240fb8..3cc03e478af7 100644 --- a/apps/dotcom/client/src/tla/components/TlaFileShareMenu/Tabs/TlaPublishTab.tsx +++ b/apps/dotcom/client/src/tla/components/TlaFileShareMenu/Tabs/TlaPublishTab.tsx @@ -3,11 +3,11 @@ import { TlaFile } from '@tldraw/dotcom-shared' import { useCallback, useState } from 'react' import { useParams } from 'react-router-dom' import { useEditor } from 'tldraw' +import { routes } from '../../../../routeDefs' import { useApp } from '../../../hooks/useAppState' import { useTldrawAppUiEvents } from '../../../utils/app-ui-events' import { copyTextToClipboard } from '../../../utils/copy' import { F, FormattedRelativeTime } from '../../../utils/i18n' -import { getShareablePublishUrl } from '../../../utils/urls' import { TlaButton } from '../../TlaButton/TlaButton' import { TlaSwitch } from '../../TlaSwitch/TlaSwitch' import { TlaTabsPage } from '../../TlaTabs/TlaTabs' @@ -67,7 +67,7 @@ export function TlaPublishTab({ file }: { file: TlaFile }) { trackEvent('unpublish-file', { source: 'file-share-menu' }) }, [app, auth, file.id, isOwner, trackEvent]) - const publishShareUrl = publishedSlug ? getShareablePublishUrl(publishedSlug) : null + const publishShareUrl = publishedSlug ? routes.tlaPublish(publishedSlug, { asUrl: true }) : null const secondsSince = Math.min(0, Math.floor((Date.now() - file.lastPublished) / 1000)) const learnMoreUrl = 'https://tldraw.notion.site/Publishing-1283e4c324c08059a1a1d9ba9833ddc9' diff --git a/apps/dotcom/client/src/tla/components/TlaSidebar/components/TlaSidebarCreateFileButton.tsx b/apps/dotcom/client/src/tla/components/TlaSidebar/components/TlaSidebarCreateFileButton.tsx index d08250354b2d..468c0e4e07c6 100644 --- a/apps/dotcom/client/src/tla/components/TlaSidebar/components/TlaSidebarCreateFileButton.tsx +++ b/apps/dotcom/client/src/tla/components/TlaSidebar/components/TlaSidebarCreateFileButton.tsx @@ -1,10 +1,10 @@ import { useCallback, useRef } from 'react' import { useNavigate } from 'react-router-dom' import { tltime } from 'tldraw' +import { routes } from '../../../../routeDefs' import { useApp } from '../../../hooks/useAppState' import { useTldrawAppUiEvents } from '../../../utils/app-ui-events' import { useMsg } from '../../../utils/i18n' -import { getFilePath } from '../../../utils/urls' import { TlaIcon } from '../../TlaIcon/TlaIcon' import styles from '../sidebar.module.css' import { messages } from './sidebar-shared' @@ -22,7 +22,7 @@ export function TlaSidebarCreateFileButton() { const res = app.createFile() if (res.ok) { const { file } = res.value - navigate(getFilePath(file.id), { state: { mode: 'create' } }) + navigate(routes.tlaFile(file.id), { state: { mode: 'create' } }) trackEvent('create-file', { source: 'sidebar' }) rCanCreate.current = false tltime.setTimeout('can create again', () => (rCanCreate.current = true), 1000) diff --git a/apps/dotcom/client/src/tla/components/TlaSidebar/components/TlaSidebarFileLink.tsx b/apps/dotcom/client/src/tla/components/TlaSidebar/components/TlaSidebarFileLink.tsx index 901d899b55b4..f4661a903838 100644 --- a/apps/dotcom/client/src/tla/components/TlaSidebar/components/TlaSidebarFileLink.tsx +++ b/apps/dotcom/client/src/tla/components/TlaSidebar/components/TlaSidebarFileLink.tsx @@ -3,11 +3,11 @@ import classNames from 'classnames' import { KeyboardEvent, useEffect, useRef, useState } from 'react' import { Link, useParams } from 'react-router-dom' import { preventDefault, useContainer, useValue } from 'tldraw' +import { routes } from '../../../../routeDefs' import { useApp } from '../../../hooks/useAppState' import { useIsFileOwner } from '../../../hooks/useIsFileOwner' import { useTldrawAppUiEvents } from '../../../utils/app-ui-events' import { F } from '../../../utils/i18n' -import { getFilePath } from '../../../utils/urls' import { TlaIcon } from '../../TlaIcon/TlaIcon' import { TlaTooltipArrow, @@ -48,7 +48,7 @@ export function TlaSidebarFileLink({ item, testId }: { item: RecentFile; testId: isActive={isActive} isOwnFile={isOwnFile} fileName={app.getFileName(fileId)} - href={getFilePath(fileId)} + href={routes.tlaFile(fileId)} /> ) } diff --git a/apps/dotcom/client/src/tla/components/dialogs/TlaDeleteFileDialog.tsx b/apps/dotcom/client/src/tla/components/dialogs/TlaDeleteFileDialog.tsx index ad1c11d31e1a..c3c523141a86 100644 --- a/apps/dotcom/client/src/tla/components/dialogs/TlaDeleteFileDialog.tsx +++ b/apps/dotcom/client/src/tla/components/dialogs/TlaDeleteFileDialog.tsx @@ -10,11 +10,11 @@ import { TldrawUiDialogHeader, TldrawUiDialogTitle, } from 'tldraw' +import { routes } from '../../../routeDefs' import { useApp } from '../../hooks/useAppState' import { useIsFileOwner } from '../../hooks/useIsFileOwner' import { useTldrawAppUiEvents } from '../../utils/app-ui-events' import { F } from '../../utils/i18n' -import { getFilePath } from '../../utils/urls' export function TlaDeleteFileDialog({ fileId, onClose }: { fileId: string; onClose(): void }) { const app = useApp() @@ -32,11 +32,11 @@ export function TlaDeleteFileDialog({ fileId, onClose }: { fileId: string; onClo if (recentFiles.length === 0) { const result = app.createFile() if (result.ok) { - navigate(getFilePath(result.value.file.id), { state: { mode: 'create' } }) + navigate(routes.tlaFile(result.value.file.id), { state: { mode: 'create' } }) trackEvent('delete-file', { source: 'file-menu' }) } } else { - navigate(getFilePath(recentFiles[0].fileId)) + navigate(routes.tlaFile(recentFiles[0].fileId)) } onClose() }, [auth, app, fileId, onClose, navigate, trackEvent]) diff --git a/apps/dotcom/client/src/tla/hooks/useTldrFileDrop.ts b/apps/dotcom/client/src/tla/hooks/useTldrFileDrop.ts index 870fe172864d..74d9ce3f0b3f 100644 --- a/apps/dotcom/client/src/tla/hooks/useTldrFileDrop.ts +++ b/apps/dotcom/client/src/tla/hooks/useTldrFileDrop.ts @@ -2,9 +2,9 @@ import { useAuth } from '@clerk/clerk-react' import { DragEvent, useCallback, useState } from 'react' import { useNavigate } from 'react-router-dom' import { Editor, TLStoreSnapshot, parseTldrawJsonFile, tlmenus, useToasts } from 'tldraw' +import { routes } from '../../routeDefs' import { globalEditor } from '../../utils/globalEditor' import { defineMessages, useIntl } from '../utils/i18n' -import { getFilePath } from '../utils/urls' import { useApp } from './useAppState' const messages = defineMessages({ @@ -66,7 +66,7 @@ export function useTldrFileDrop() { keepOpen: true, }) if (results.slugs.length > 0) { - navigate(getFilePath(results.slugs[0]), { state: { mode: 'create' } }) + navigate(routes.tlaFile(results.slugs[0])) } } }, diff --git a/apps/dotcom/client/src/tla/layouts/TlaErrorLayout/TlaErrorLayout.tsx b/apps/dotcom/client/src/tla/layouts/TlaErrorLayout/TlaErrorLayout.tsx index 56c5642e3d77..ab4b49ab84ea 100644 --- a/apps/dotcom/client/src/tla/layouts/TlaErrorLayout/TlaErrorLayout.tsx +++ b/apps/dotcom/client/src/tla/layouts/TlaErrorLayout/TlaErrorLayout.tsx @@ -1,8 +1,8 @@ import { ReactNode } from 'react' import { useNavigate } from 'react-router-dom' +import { routes } from '../../../routeDefs' import { TlaCloseButton } from '../../components/TlaCloseButton/TlaCloseButton' import { usePreventAccidentalDrops } from '../../hooks/usePreventAccidentalDrops' -import { getRootPath } from '../../utils/urls' import styles from './error-layout.module.css' export function TlaErrorLayout({ children }: { children: ReactNode }) { @@ -11,7 +11,7 @@ export function TlaErrorLayout({ children }: { children: ReactNode }) { return (
    - navigate(getRootPath())} /> + navigate(routes.tlaRoot())} />
    {children}
    diff --git a/apps/dotcom/client/src/tla/pages/local.tsx b/apps/dotcom/client/src/tla/pages/local.tsx index ece91bbb417b..682a66631304 100644 --- a/apps/dotcom/client/src/tla/pages/local.tsx +++ b/apps/dotcom/client/src/tla/pages/local.tsx @@ -2,13 +2,13 @@ import { useEffect } from 'react' import { useNavigate } from 'react-router-dom' import { assert, react } from 'tldraw' import { LocalEditor } from '../../components/LocalEditor' +import { routes } from '../../routeDefs' import { globalEditor } from '../../utils/globalEditor' import { SneakyDarkModeSync } from '../components/TlaEditor/SneakyDarkModeSync' import { components } from '../components/TlaEditor/TlaEditor' import { useMaybeApp } from '../hooks/useAppState' import { TlaAnonLayout } from '../layouts/TlaAnonLayout/TlaAnonLayout' import { clearShouldSlurpFile, getShouldSlurpFile, setShouldSlurpFile } from '../utils/slurping' -import { getFilePath } from '../utils/urls' export function Component() { const app = useMaybeApp() @@ -21,7 +21,10 @@ export function Component() { const res = app.slurpFile() if (res.ok) { clearShouldSlurpFile() - navigate(getFilePath(res.value.file.id), { state: { mode: 'create' }, replace: true }) + navigate(routes.tlaFile(res.value.file.id), { + state: { mode: 'create' }, + replace: true, + }) } else { // if the user has too many files we end up here. // don't slurp the file and when they log out they'll @@ -37,12 +40,15 @@ export function Component() { // result is only false if the user reached their file limit so // we don't need to handle that case here since they have no files if (result.ok) { - navigate(getFilePath(result.value.file.id), { state: { mode: 'create' }, replace: true }) + navigate(routes.tlaFile(result.value.file.id), { + state: { mode: 'create' }, + replace: true, + }) } return } - navigate(getFilePath(recentFiles[0].fileId), { replace: true }) + navigate(routes.tlaFile(recentFiles[0].fileId), { replace: true }) }, [app, navigate]) if (!app) return diff --git a/apps/dotcom/client/src/tla/providers/RequireSignedInUser.tsx b/apps/dotcom/client/src/tla/providers/RequireSignedInUser.tsx index da8704fa8f80..5947141c105d 100644 --- a/apps/dotcom/client/src/tla/providers/RequireSignedInUser.tsx +++ b/apps/dotcom/client/src/tla/providers/RequireSignedInUser.tsx @@ -1,12 +1,12 @@ import { Navigate, Outlet } from 'react-router-dom' +import { routes } from '../../routeDefs' import { useMaybeApp } from '../hooks/useAppState' -import { getRootPath } from '../utils/urls' export function Component() { const app = useMaybeApp() if (!app) { // todo: add a back-to location in the location state, redirect back to here after sign in - return + return } return } diff --git a/apps/dotcom/client/src/tla/providers/TlaRootProviders.tsx b/apps/dotcom/client/src/tla/providers/TlaRootProviders.tsx index 5b34f119f005..798fb9e53b54 100644 --- a/apps/dotcom/client/src/tla/providers/TlaRootProviders.tsx +++ b/apps/dotcom/client/src/tla/providers/TlaRootProviders.tsx @@ -14,6 +14,7 @@ import { useToasts, useValue, } from 'tldraw' +import { routes } from '../../routeDefs' import { globalEditor } from '../../utils/globalEditor' import { MaybeForceUserRefresh } from '../components/MaybeForceUserRefresh/MaybeForceUserRefresh' import { components } from '../components/TlaEditor/TlaEditor' @@ -22,7 +23,6 @@ import { UserProvider } from '../hooks/useUser' import '../styles/tla.css' import { IntlProvider, setupCreateIntl } from '../utils/i18n' import { getLocalSessionState, updateLocalSessionState } from '../utils/local-session-state' -import { getRootPath } from '../utils/urls' const assetUrls = getAssetUrlsByImport() @@ -48,7 +48,7 @@ export function Component() { > - + {container && ( diff --git a/apps/dotcom/client/src/tla/utils/urls.ts b/apps/dotcom/client/src/tla/utils/urls.ts deleted file mode 100644 index 6f0c417ef7d1..000000000000 --- a/apps/dotcom/client/src/tla/utils/urls.ts +++ /dev/null @@ -1,46 +0,0 @@ -export const PREFIX = { - tla: 'q', - file: 'f', - localFile: 'lf', - publish: 'p', -} - -export function buildUrl({ pathname }: { pathname: string }): string { - return `/${PREFIX.tla}${pathname}` -} - -export function getRootPath() { - return buildUrl({ pathname: '/' }) -} - -export function getDebugPath() { - return buildUrl({ pathname: '/debug' }) -} - -export function getProfilePath() { - return buildUrl({ pathname: '/profile' }) -} - -export function getFilePath(fileSlug: string) { - return buildUrl({ pathname: `/${PREFIX.file}/${fileSlug}` }) -} - -export function getLocalFilePath(persistenceKey: string) { - return buildUrl({ pathname: `/${PREFIX.localFile}/${persistenceKey}` }) -} - -export function getPublishPath(publishSlug: string) { - return buildUrl({ pathname: `/${PREFIX.publish}/${publishSlug}` }) -} - -function absoluteUrl(path: string) { - return `${window.location.origin}${path}` -} - -export function getShareableFileUrl(fileId: string): string { - return absoluteUrl(getFilePath(fileId)) -} - -export function getShareablePublishUrl(publishSlug: string): string { - return absoluteUrl(getPublishPath(publishSlug)) -} diff --git a/apps/dotcom/client/src/utils/sharing.ts b/apps/dotcom/client/src/utils/sharing.ts index efe8ad321546..acb581645633 100644 --- a/apps/dotcom/client/src/utils/sharing.ts +++ b/apps/dotcom/client/src/utils/sharing.ts @@ -23,6 +23,7 @@ import { fetch, isShape, } from 'tldraw' +import { routes } from '../routeDefs' import { writeToClipboard } from './clipboard' import { cloneAssetForShare } from './cloneAssetForShare' import { getParentOrigin, isInIframe } from './iFrame' @@ -107,7 +108,7 @@ export function useSharing(): TLUiOverrides { handleUiEvent('leave-shared-project', {}) - navigate('/') + navigate(routes.legacyRoot()) }, } actions[SHARE_PROJECT_ACTION] = { diff --git a/apps/dotcom/client/src/utils/useFileSystem.tsx b/apps/dotcom/client/src/utils/useFileSystem.tsx index acbd6cf1dae7..80f5a1cf896b 100644 --- a/apps/dotcom/client/src/utils/useFileSystem.tsx +++ b/apps/dotcom/client/src/utils/useFileSystem.tsx @@ -12,6 +12,7 @@ import { serializeTldrawJsonBlob, transact, } from 'tldraw' +import { routes } from '../routeDefs' import { shouldClearDocument } from './shouldClearDocument' import { shouldOverrideDocument } from './shouldOverrideDocument' import { useHandleUiEvents } from './useHandleUiEvent' @@ -76,7 +77,7 @@ export function useFileSystem({ isMultiplayer }: { isMultiplayer: boolean }): TL readonlyOk: true, async onSelect(source) { handleUiEvent('create-new-shared-project', { source }) - navigate('/new') + navigate(routes.legacyNewPage()) }, } actions[NEW_PROJECT_ACTION] = {