Skip to content

Commit

Permalink
New UI - Part 1 - Details inside:
Browse files Browse the repository at this point in the history
 - Optima Layout: new Context based pluggable layout system
   - Now children have context functions, for better behaviors
   - Removed `store-applayout`
   - using withLayout on top-level Pages
 - ScrollToBottom: grounds-up subsystem for smooth scrolling with snap-to-bottom
 - Panes subsystem: use react-resizeable-panels together with our Panes subsystem
   - New: Split window chats, Drag to close windows, Button to split
   - using: https://github.com/bvaughn/react-resizable-panels
 - Cosmetic: Colors: update Light and Dark themes
 - Bootstrap Logic provider: will enable Mobile use cases
 - Removed NoSSR (the backend provided natually acts as the same)
 - Next load progress: loading indicator for slower pages (>300ms)
 - withLayout() system

Additional benefits include: no-pluggable-flashing, pane-ready,
fixed X-scrolling on Firefox, and more.

Closes #308, #304, #255, #59.
Progress on #305, #201, #296, #233, #208, #203.
  • Loading branch information
enricoros committed Dec 28, 2023
2 parents a9e1a96 + 2eb3397 commit d775d47
Show file tree
Hide file tree
Showing 65 changed files with 1,240 additions and 515 deletions.
2 changes: 1 addition & 1 deletion LICENSE
@@ -1,6 +1,6 @@
MIT License

Copyright (c) 2023 Enrico Ros
Copyright (c) 2023-2024 Enrico Ros

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
23 changes: 23 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions package.json
Expand Up @@ -34,13 +34,15 @@
"eventsource-parser": "^1.1.1",
"idb-keyval": "^6.2.1",
"next": "^14.0.4",
"nprogress": "^0.2.0",
"pdfjs-dist": "4.0.269",
"plantuml-encoder": "^1.4.0",
"prismjs": "^1.29.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-katex": "^3.0.1",
"react-markdown": "^9.0.1",
"react-resizable-panels": "^1.0.5",
"react-timeago": "^7.2.0",
"remark-gfm": "^4.0.0",
"superjson": "^2.2.1",
Expand All @@ -52,6 +54,7 @@
"devDependencies": {
"@cloudflare/puppeteer": "^0.0.5",
"@types/node": "^20.10.5",
"@types/nprogress": "^0.2.3",
"@types/plantuml-encoder": "^1.4.2",
"@types/prismjs": "^1.26.3",
"@types/react": "^18.2.45",
Expand Down
27 changes: 15 additions & 12 deletions pages/_app.tsx
Expand Up @@ -10,11 +10,12 @@ import 'katex/dist/katex.min.css';
import '~/common/styles/CodePrism.css';
import '~/common/styles/GithubMarkdown.css';

import { ProviderBackend } from '~/common/state/ProviderBackend';
import { ProviderSingleTab } from '~/common/state/ProviderSingleTab';
import { ProviderSnacks } from '~/common/state/ProviderSnacks';
import { ProviderTRPCQueryClient } from '~/common/state/ProviderTRPCQueryClient';
import { ProviderTheming } from '~/common/state/ProviderTheming';
import { ProviderBackendAndNoSSR } from '~/common/providers/ProviderBackendAndNoSSR';
import { ProviderBootstrapLogic } from '~/common/providers/ProviderBootstrapLogic';
import { ProviderSingleTab } from '~/common/providers/ProviderSingleTab';
import { ProviderSnacks } from '~/common/providers/ProviderSnacks';
import { ProviderTRPCQueryClient } from '~/common/providers/ProviderTRPCQueryClient';
import { ProviderTheming } from '~/common/providers/ProviderTheming';


const MyApp = ({ Component, emotionCache, pageProps }: MyAppProps) =>
Expand All @@ -27,13 +28,15 @@ const MyApp = ({ Component, emotionCache, pageProps }: MyAppProps) =>

<ProviderTheming emotionCache={emotionCache}>
<ProviderSingleTab>
<ProviderTRPCQueryClient>
<ProviderSnacks>
<ProviderBackend>
<Component {...pageProps} />
</ProviderBackend>
</ProviderSnacks>
</ProviderTRPCQueryClient>
<ProviderBootstrapLogic>
<ProviderTRPCQueryClient>
<ProviderSnacks>
<ProviderBackendAndNoSSR>
<Component {...pageProps} />
</ProviderBackendAndNoSSR>
</ProviderSnacks>
</ProviderTRPCQueryClient>
</ProviderBootstrapLogic>
</ProviderSingleTab>
</ProviderTheming>

Expand Down
8 changes: 2 additions & 6 deletions pages/call.tsx
Expand Up @@ -2,13 +2,9 @@ import * as React from 'react';

import { AppCall } from '../src/apps/call/AppCall';

import { AppLayout } from '~/common/layout/AppLayout';
import { withLayout } from '~/common/layout/withLayout';


export default function CallPage() {
return (
<AppLayout>
<AppCall />
</AppLayout>
);
return withLayout({ type: 'optima' }, <AppCall />);
}
14 changes: 5 additions & 9 deletions pages/index.tsx
@@ -1,18 +1,14 @@
import * as React from 'react';

import { AppChat } from '../src/apps/chat/AppChat';
import { useShowNewsOnUpdate } from '../src/apps/news/news.hooks';
import { useRedirectToNewsOnUpdates } from '../src/apps/news/news.hooks';

import { AppLayout } from '~/common/layout/AppLayout';
import { withLayout } from '~/common/layout/withLayout';


export default function ChatPage() {
// show the News page on updates
useShowNewsOnUpdate();
// show the News page if there are unseen updates
useRedirectToNewsOnUpdates();

return (
<AppLayout>
<AppChat />
</AppLayout>
);
return withLayout({ type: 'optima' }, <AppChat />);
}
16 changes: 6 additions & 10 deletions pages/link/callback_openrouter.tsx
Expand Up @@ -5,11 +5,11 @@ import { Box, Typography } from '@mui/joy';

import { useModelsStore } from '~/modules/llms/store-llms';

import { AppLayout } from '~/common/layout/AppLayout';
import { InlineError } from '~/common/components/InlineError';
import { apiQuery } from '~/common/util/trpc.client';
import { navigateToIndex } from '~/common/app.routes';
import { openLayoutModelsSetup } from '~/common/layout/store-applayout';
import { themeBgApp } from '~/common/app.theme';
import { withLayout } from '~/common/layout/withLayout';


function CallbackOpenRouterPage(props: { openRouterCode: string | undefined }) {
Expand All @@ -36,14 +36,14 @@ function CallbackOpenRouterPage(props: { openRouterCode: string | undefined }) {
useModelsStore.getState().setOpenRoutersKey(openRouterKey);

// 2. Navigate to the chat app
navigateToIndex(true).then(() => openLayoutModelsSetup());
void navigateToIndex(true); //.then(openModelsSetup);

}, [isSuccess, openRouterKey]);

return (
<Box sx={{
flexGrow: 1,
backgroundColor: 'background.level1',
backgroundColor: themeBgApp,
overflowY: 'auto',
display: 'flex', justifyContent: 'center',
p: { xs: 3, md: 6 },
Expand Down Expand Up @@ -84,15 +84,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 Page() {
export default function CallbackPage() {

// get the 'code=...' from the URL
const { query } = useRouter();
const { code: openRouterCode } = query;

return (
<AppLayout suspendAutoModelsSetup>
<CallbackOpenRouterPage openRouterCode={openRouterCode as (string | undefined)} />
</AppLayout>
);
return withLayout({ type: 'plain' }, <CallbackOpenRouterPage openRouterCode={openRouterCode as (string | undefined)} />);
}
8 changes: 2 additions & 6 deletions pages/link/chat/[chatLinkId].tsx
Expand Up @@ -3,16 +3,12 @@ import { useRouter } from 'next/router';

import { AppChatLink } from '../../../src/apps/link/AppChatLink';

import { AppLayout } from '~/common/layout/AppLayout';
import { withLayout } from '~/common/layout/withLayout';


export default function ChatLinkPage() {
const { query } = useRouter();
const chatLinkId = query?.chatLinkId as string ?? '';

return (
<AppLayout suspendAutoModelsSetup>
<AppChatLink linkId={chatLinkId} />
</AppLayout>
);
return withLayout({ type: 'optima', suspendAutoModelsSetup: true }, <AppChatLink linkId={chatLinkId} />);
}
13 changes: 5 additions & 8 deletions pages/link/share_target.tsx
Expand Up @@ -8,10 +8,11 @@ import { setComposerStartupText } from '../../src/apps/chat/components/composer/

import { callBrowseFetchPage } from '~/modules/browse/browse.client';

import { AppLayout } from '~/common/layout/AppLayout';
import { LogoProgress } from '~/common/components/LogoProgress';
import { asValidURL } from '~/common/util/urlUtils';
import { navigateToIndex } from '~/common/app.routes';
import { themeBgApp } from '~/common/app.theme';
import { withLayout } from '~/common/layout/withLayout';


/**
Expand Down Expand Up @@ -90,7 +91,7 @@ function AppShareTarget() {
return (

<Box sx={{
backgroundColor: 'background.level2',
backgroundColor: themeBgApp,
display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center',
flexGrow: 1,
}}>
Expand Down Expand Up @@ -132,10 +133,6 @@ 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 LaunchPage() {
return (
<AppLayout>
<AppShareTarget />
</AppLayout>
);
export default function ShareTargetPage() {
return withLayout({ type: 'plain' }, <AppShareTarget />);
}
10 changes: 3 additions & 7 deletions pages/news.tsx
Expand Up @@ -3,16 +3,12 @@ import * as React from 'react';
import { AppNews } from '../src/apps/news/AppNews';
import { useMarkNewsAsSeen } from '../src/apps/news/news.hooks';

import { AppLayout } from '~/common/layout/AppLayout';
import { withLayout } from '~/common/layout/withLayout';


export default function NewsPage() {
// update the last seen news version
// 'touch' the last seen news version
useMarkNewsAsSeen();

return (
<AppLayout suspendAutoModelsSetup>
<AppNews />
</AppLayout>
);
return withLayout({ type: 'optima', suspendAutoModelsSetup: true }, <AppNews />);
}
8 changes: 2 additions & 6 deletions pages/personas.tsx
Expand Up @@ -2,13 +2,9 @@ import * as React from 'react';

import { AppPersonas } from '../src/apps/personas/AppPersonas';

import { AppLayout } from '~/common/layout/AppLayout';
import { withLayout } from '~/common/layout/withLayout';


export default function PersonasPage() {
return (
<AppLayout>
<AppPersonas />
</AppLayout>
);
return withLayout({ type: 'optima' }, <AppPersonas />);
}
9 changes: 5 additions & 4 deletions src/apps/call/CallUI.tsx
Expand Up @@ -22,12 +22,13 @@ import { Link } from '~/common/components/Link';
import { SpeechResult, useSpeechRecognition } from '~/common/components/useSpeechRecognition';
import { conversationTitle, createDMessage, DMessage, useChatStore } from '~/common/state/store-chats';
import { playSoundUrl, usePlaySoundUrl } from '~/common/util/audioUtils';
import { useLayoutPluggable } from '~/common/layout/store-applayout';
import { usePluggableOptimaLayout } from '~/common/layout/optima/useOptimaLayout';

import { CallAvatar } from './components/CallAvatar';
import { CallButton } from './components/CallButton';
import { CallMessage } from './components/CallMessage';
import { CallStatus } from './components/CallStatus';
import { ROUTE_APP_CHAT } from '~/common/app.routes';


function CallMenuItems(props: {
Expand Down Expand Up @@ -178,7 +179,7 @@ export function CallUI(props: {
case 'Goodbye.':
setStage('ended');
setTimeout(() => {
void routerPush('/');
void routerPush(ROUTE_APP_CHAT);
}, 2000);
return;
// command: regenerate answer
Expand Down Expand Up @@ -272,7 +273,7 @@ export function CallUI(props: {
, [overridePersonaVoice, pushToTalk],
);

useLayoutPluggable(chatLLMDropdown, null, menuItems);
usePluggableOptimaLayout(null, chatLLMDropdown, menuItems, 'CallUI');


return <>
Expand Down Expand Up @@ -366,7 +367,7 @@ export function CallUI(props: {
)}

{/* [ended] Back / Call Again */}
{(isEnded || isDeclined) && <Link noLinkStyle href='/'><CallButton Icon={ArrowBackIcon} text='Back' variant='soft' /></Link>}
{(isEnded || isDeclined) && <Link noLinkStyle href={ROUTE_APP_CHAT}><CallButton Icon={ArrowBackIcon} text='Back' variant='soft' /></Link>}
{(isEnded || isDeclined) && <CallButton Icon={CallIcon} text='Call Again' color='success' variant='soft' onClick={() => setStage('connected')} />}

</Box>
Expand Down
5 changes: 3 additions & 2 deletions src/apps/call/CallWizard.tsx
Expand Up @@ -11,9 +11,9 @@ import RecordVoiceOverIcon from '@mui/icons-material/RecordVoiceOver';
import WarningIcon from '@mui/icons-material/Warning';

import { navigateBack } from '~/common/app.routes';
import { openLayoutPreferences } from '~/common/layout/store-applayout';
import { useCapabilityBrowserSpeechRecognition, useCapabilityElevenLabs } from '~/common/components/useCapabilities';
import { useChatStore } from '~/common/state/store-chats';
import { useOptimaLayout } from '~/common/layout/optima/useOptimaLayout';
import { useUICounter } from '~/common/state/store-ui';


Expand Down Expand Up @@ -81,6 +81,7 @@ export function CallWizard(props: { strict?: boolean, conversationId: string, ch
const [recognitionOverride, setRecognitionOverride] = React.useState(false);

// external state
const { openPreferences } = useOptimaLayout();
const recognition = useCapabilityBrowserSpeechRecognition();
const synthesis = useCapabilityElevenLabs();
const chatIsEmpty = useChatStore(state => {
Expand All @@ -103,7 +104,7 @@ export function CallWizard(props: { strict?: boolean, conversationId: string, ch
const handleOverrideRecognition = () => setRecognitionOverride(true);

const handleConfigureElevenLabs = () => {
openLayoutPreferences(3);
openPreferences(3);
};

const handleFinishButton = () => {
Expand Down

0 comments on commit d775d47

Please sign in to comment.