diff --git a/pages/_app.tsx b/pages/_app.tsx
index 78e36f7fa..e7bcfd312 100644
--- a/pages/_app.tsx
+++ b/pages/_app.tsx
@@ -24,8 +24,14 @@ import { hasGoogleAnalytics, OptionalGoogleAnalytics } from '~/common/components
import { isVercelFromFrontend } from '~/common/util/pwaUtils';
-const MyApp = ({ Component, emotionCache, pageProps }: MyAppProps) =>
- <>
+const MyApp = ({ Component, emotionCache, pageProps }: MyAppProps) => {
+
+ // We are using a nextjs per-page layout pattern to bring the (Optima) layout creation to a shared place
+ // This reduces the flicker and the time switching between apps, and seems to not have impact on
+ // the build. This is a good trade-off for now.
+ const getLayout = Component.getLayout ?? ((page: any) => page);
+
+ return <>
{Brand.Title.Common}
@@ -39,7 +45,7 @@ const MyApp = ({ Component, emotionCache, pageProps }: MyAppProps) =>
{/* ^ SSR boundary */}
-
+ {getLayout()}
@@ -52,6 +58,7 @@ const MyApp = ({ Component, emotionCache, pageProps }: MyAppProps) =>
{hasGoogleAnalytics && }
>;
+};
// enables the React Query API invocation
export default apiQuery.withTRPC(MyApp);
\ No newline at end of file
diff --git a/pages/call.tsx b/pages/call.tsx
index 2e56d3ac1..47880c561 100644
--- a/pages/call.tsx
+++ b/pages/call.tsx
@@ -2,9 +2,7 @@ import * as React from 'react';
import { AppCall } from '../src/apps/call/AppCall';
-import { withLayout } from '~/common/layout/withLayout';
+import { withNextJSPerPageLayout } from '~/common/layout/withLayout';
-export default function CallPage() {
- return withLayout({ type: 'optima' }, );
-}
\ No newline at end of file
+export default withNextJSPerPageLayout({ type: 'optima' }, () => );
diff --git a/pages/dev/beam.tsx b/pages/dev/beam.tsx
index dab3ee05c..f9798464f 100644
--- a/pages/dev/beam.tsx
+++ b/pages/dev/beam.tsx
@@ -2,9 +2,7 @@ import * as React from 'react';
import { AppBeam } from '../../src/apps/beam/AppBeam';
-import { withLayout } from '~/common/layout/withLayout';
+import { withNextJSPerPageLayout } from '~/common/layout/withLayout';
-export default function BeamPage() {
- return withLayout({ type: 'optima' }, );
-}
\ No newline at end of file
+export default withNextJSPerPageLayout({ type: 'optima' }, () => );
diff --git a/pages/diff.tsx b/pages/diff.tsx
index a406e2b76..bd86c316f 100644
--- a/pages/diff.tsx
+++ b/pages/diff.tsx
@@ -2,9 +2,7 @@ import * as React from 'react';
import { AppDiff } from '../src/apps/diff/AppDiff';
-import { withLayout } from '~/common/layout/withLayout';
+import { withNextJSPerPageLayout } from '~/common/layout/withLayout';
-export default function DiffPage() {
- return withLayout({ type: 'optima' }, );
-}
\ No newline at end of file
+export default withNextJSPerPageLayout({ type: 'optima' }, () => );
diff --git a/pages/draw.tsx b/pages/draw.tsx
index 8f6642f9e..601dbd3cb 100644
--- a/pages/draw.tsx
+++ b/pages/draw.tsx
@@ -2,9 +2,7 @@ import * as React from 'react';
import { AppDraw } from '../src/apps/draw/AppDraw';
-import { withLayout } from '~/common/layout/withLayout';
+import { withNextJSPerPageLayout } from '~/common/layout/withLayout';
-export default function DrawPage() {
- return withLayout({ type: 'optima' }, );
-}
\ No newline at end of file
+export default withNextJSPerPageLayout({ type: 'optima' }, () => );
diff --git a/pages/index.tsx b/pages/index.tsx
index 68a906ca1..fc8ccb9cb 100644
--- a/pages/index.tsx
+++ b/pages/index.tsx
@@ -2,13 +2,16 @@ import * as React from 'react';
import { AppChat } from '../src/apps/chat/AppChat';
-import { withLayout } from '~/common/layout/withLayout';
+import { withNextJSPerPageLayout } from '~/common/layout/withLayout';
+import { useDebugHook } from '~/common/components/useDebugHook';
-export default function IndexPage() {
+export default withNextJSPerPageLayout({ type: 'optima' }, () => {
+
+ useDebugHook('IndexPage');
// TODO: This Index page will point to the Dashboard (or a landing page)
// For now it offers the chat experience, but this will change. #299
- return withLayout({ type: 'optima' }, );
-}
\ No newline at end of file
+ return ;
+});
diff --git a/pages/info/debug.tsx b/pages/info/debug.tsx
index a822e7b1f..a9959ece6 100644
--- a/pages/info/debug.tsx
+++ b/pages/info/debug.tsx
@@ -9,7 +9,7 @@ import { AppPlaceholder } from '../../src/apps/AppPlaceholder';
import { getBackendCapabilities } from '~/modules/backend/store-backend-capabilities';
import { getPlantUmlServerUrl } from '~/modules/blocks/code/RenderCode';
-import { withLayout } from '~/common/layout/withLayout';
+import { withNextJSPerPageLayout } from '~/common/layout/withLayout';
// app config
@@ -164,6 +164,4 @@ function AppDebug() {
}
-export default function DebugPage() {
- return withLayout({ type: 'plain' }, );
-};
\ No newline at end of file
+export default withNextJSPerPageLayout({ type: 'plain' }, () => );
diff --git a/pages/link/callback_openrouter.tsx b/pages/link/callback_openrouter.tsx
index 08706a90e..a73e351ca 100644
--- a/pages/link/callback_openrouter.tsx
+++ b/pages/link/callback_openrouter.tsx
@@ -7,7 +7,7 @@ import { useModelsStore } from '~/modules/llms/store-llms';
import { InlineError } from '~/common/components/InlineError';
import { apiQuery } from '~/common/util/trpc.client';
import { navigateToIndex, useRouterQuery } from '~/common/app.routes';
-import { withLayout } from '~/common/layout/withLayout';
+import { withNextJSPerPageLayout } from '~/common/layout/withLayout';
function CallbackOpenRouterPage(props: { openRouterCode: string | undefined }) {
@@ -81,10 +81,11 @@ function CallbackOpenRouterPage(props: { openRouterCode: string | undefined }) {
* Docs: https://openrouter.ai/docs#oauth
* Example URL: https://localhost:3000/link/callback_openrouter?code=SomeCode
*/
-export default function CallbackPage() {
+export default withNextJSPerPageLayout({ type: 'plain' }, () => {
// external state - get the 'code=...' from the URL
const { code } = useRouterQuery<{ code: string | undefined }>();
- return withLayout({ type: 'plain' }, );
-}
\ No newline at end of file
+ return ;
+
+});
diff --git a/pages/link/chat/[chatLinkId].tsx b/pages/link/chat/[chatLinkId].tsx
index dfaa50e60..f086bfc22 100644
--- a/pages/link/chat/[chatLinkId].tsx
+++ b/pages/link/chat/[chatLinkId].tsx
@@ -3,13 +3,14 @@ import * as React from 'react';
import { AppLinkChat } from '../../../src/apps/link-chat/AppLinkChat';
import { useRouterQuery } from '~/common/app.routes';
-import { withLayout } from '~/common/layout/withLayout';
+import { withNextJSPerPageLayout } from '~/common/layout/withLayout';
-export default function ChatLinkPage() {
+export default withNextJSPerPageLayout({ type: 'optima', suspendAutoModelsSetup: true }, () => {
// external state
const { chatLinkId } = useRouterQuery<{ chatLinkId: string | undefined }>();
- return withLayout({ type: 'optima', suspendAutoModelsSetup: true }, );
-}
\ No newline at end of file
+ return ;
+
+});
\ No newline at end of file
diff --git a/pages/link/share_target.tsx b/pages/link/share_target.tsx
index be29c7e65..6543024f5 100644
--- a/pages/link/share_target.tsx
+++ b/pages/link/share_target.tsx
@@ -10,7 +10,7 @@ import { callBrowseFetchPage } from '~/modules/browse/browse.client';
import { LogoProgress } from '~/common/components/LogoProgress';
import { asValidURL } from '~/common/util/urlUtils';
import { navigateToIndex, useRouterQuery } from '~/common/app.routes';
-import { withLayout } from '~/common/layout/withLayout';
+import { withNextJSPerPageLayout } from '~/common/layout/withLayout';
/**
@@ -135,6 +135,4 @@ function AppShareTarget() {
* This page will be invoked on mobile when sharing Text/URLs/Files from other APPs
* Example URL: https://localhost:3000/link/share_target?title=This+Title&text=https%3A%2F%2Fexample.com%2Fapp%2Fpath
*/
-export default function ShareTargetPage() {
- return withLayout({ type: 'plain' }, );
-}
\ No newline at end of file
+export default withNextJSPerPageLayout({ type: 'plain' }, () => );
diff --git a/pages/news.tsx b/pages/news.tsx
index e64df9359..96b08dfee 100644
--- a/pages/news.tsx
+++ b/pages/news.tsx
@@ -3,12 +3,13 @@ import * as React from 'react';
import { AppNews } from '../src/apps/news/AppNews';
import { markNewsAsSeen } from '../src/apps/news/news.version';
-import { withLayout } from '~/common/layout/withLayout';
+import { withNextJSPerPageLayout } from '~/common/layout/withLayout';
-export default function NewsPage() {
+export default withNextJSPerPageLayout({ type: 'optima', suspendAutoModelsSetup: true }, () => {
+
// 'touch' the last seen news version
React.useEffect(() => markNewsAsSeen(), []);
- return withLayout({ type: 'optima', suspendAutoModelsSetup: true }, );
-}
\ No newline at end of file
+ return ;
+});
\ No newline at end of file
diff --git a/pages/personas.tsx b/pages/personas.tsx
index 551e73ed7..eb1d76f23 100644
--- a/pages/personas.tsx
+++ b/pages/personas.tsx
@@ -2,9 +2,7 @@ import * as React from 'react';
import { AppPersonas } from '../src/apps/personas/AppPersonas';
-import { withLayout } from '~/common/layout/withLayout';
+import { withNextJSPerPageLayout } from '~/common/layout/withLayout';
-export default function PersonasPage() {
- return withLayout({ type: 'optima' }, );
-}
\ No newline at end of file
+export default withNextJSPerPageLayout({ type: 'optima' }, () => );
diff --git a/pages/tokens.tsx b/pages/tokens.tsx
index 8d7d20a13..3ecf25efc 100644
--- a/pages/tokens.tsx
+++ b/pages/tokens.tsx
@@ -2,9 +2,7 @@ import * as React from 'react';
import { AppTokens } from '../src/apps/tokens/AppTokens';
-import { withLayout } from '~/common/layout/withLayout';
+import { withNextJSPerPageLayout } from '~/common/layout/withLayout';
-export default function TokenizerPage() {
- return withLayout({ type: 'optima' }, );
-}
\ No newline at end of file
+export default withNextJSPerPageLayout({ type: 'optima' }, () => );
diff --git a/pages/workspace.tsx b/pages/workspace.tsx
index dc0cde643..7ecef59eb 100644
--- a/pages/workspace.tsx
+++ b/pages/workspace.tsx
@@ -1,12 +1,8 @@
import * as React from 'react';
-import { Box } from '@mui/joy';
+import { AppPlaceholder } from '../src/apps/AppPlaceholder';
-// import { AppWorkspace } from '../src/apps/personas/AppWorkspace';
-
-import { withLayout } from '~/common/layout/withLayout';
+import { withNextJSPerPageLayout } from '~/common/layout/withLayout';
-export default function PersonasPage() {
- return withLayout({ type: 'optima' }, );
-}
\ No newline at end of file
+export default withNextJSPerPageLayout({ type: 'optima' }, () => );
diff --git a/src/common/layout/withLayout.tsx b/src/common/layout/withLayout.tsx
index 8dd133595..959fc82c5 100644
--- a/src/common/layout/withLayout.tsx
+++ b/src/common/layout/withLayout.tsx
@@ -1,10 +1,12 @@
import * as React from 'react';
+import type { NextPageWithLayout } from '~/common/types/next.page';
+
import { OptimaLayout } from './optima/OptimaLayout';
import { PlainLayout } from './plain/PlainLayout';
-type WithLayout = {
+type PerPageLayoutOptions = {
type: 'optima';
suspendAutoModelsSetup?: boolean;
} | {
@@ -13,23 +15,49 @@ type WithLayout = {
/**
- * Dynamic page-level layouting: a wrapper that adds the layout around the children.
+ * Next.js page-level layouting: a wrapper that adds the layout around the page as a layout function.
*/
-export function withLayout(layoutOptions: WithLayout, children: React.ReactNode): React.ReactElement {
+export function withNextJSPerPageLayout(options: PerPageLayoutOptions, page: NextPageWithLayout): NextPageWithLayout {
- const { type, ...rest } = layoutOptions;
+ const { type, ...rest } = options;
switch (type) {
case 'optima':
- return {children};
+ page.getLayout = (page: React.ReactElement) => {page};
+ return page;
case 'plain':
- return {children};
+ page.getLayout = (page: React.ReactElement) => {page};
+ return page;
default:
console.error('No layout specified for this top-level page');
- return <>{children}>;
+ return page;
}
}
+
+
+// /**
+// * Dynamic page-level layouting: a wrapper that adds the layout around the children.
+// */
+// export function withLayout(layoutOptions: LayoutOptions, children: React.ReactNode): React.ReactElement {
+//
+// const { type, ...rest } = layoutOptions;
+//
+// switch (type) {
+//
+// case 'optima':
+// return {children};
+//
+// case 'plain':
+// return {children};
+//
+// default:
+// console.error('No layout specified for this top-level page');
+// return <>{children}>;
+//
+// }
+// }
+//
diff --git a/src/common/types/next.page.d.ts b/src/common/types/next.page.d.ts
index 5d21920ab..e7fac3e1e 100644
--- a/src/common/types/next.page.d.ts
+++ b/src/common/types/next.page.d.ts
@@ -1,17 +1,20 @@
+import type { ReactElement, ReactNode } from 'react';
+import type { NextPage } from 'next';
import type { EmotionCache } from '@emotion/react';
-// export type NextPageWithLayout = NextPage
& {
-// // require .layoutOptions on the page component
-// layoutOptions: LayoutOptions;
-// };
+export type NextPageWithLayout
= NextPage
& {
+ // definition of the per-page layout function, as per:
+ // https://nextjs.org/docs/pages/building-your-application/routing/pages-and-layouts#per-page-layouts
+ getLayout?: (page: ReactElement) => ReactNode;
+}
// Extend the AppProps type with the custom page component type
declare module 'next/app' {
import { AppProps } from 'next/app';
type MyAppProps = AppProps & {
- // Component: NextPageWithLayout;
+ Component: NextPageWithLayout
emotionCache?: EmotionCache;
};
-}
\ No newline at end of file
+}