Files
big-agi/src/common/layout/optima/useOptimaLayout.tsx
T
Sorawit Kongnurat f38be4aff3 feat: replace useGlobalShortcut with useGlobalShortcuts
Ignore alt key for mac users.
2024-07-06 15:41:45 +07:00

163 lines
4.6 KiB
TypeScript

import * as React from 'react';
import type { DLLMId } from '~/modules/llms/store-llms';
import { GlobalShortcutItem, useGlobalShortcuts } from '~/common/components/useGlobalShortcuts';
import { isMacUser } from '~/common/util/pwaUtils';
const DEBUG_OPTIMA_LAYOUT_PLUGGING = false;
export const PreferencesTab = {
None: 0,
Chat: 1,
Voice: 2,
Draw: 3,
Tools: 4,
} as const;
type PreferencesTabType = typeof PreferencesTab[keyof typeof PreferencesTab];
type PC = React.JSX.Element | null;
interface OptimaLayoutState {
// pluggable UI
appDrawerContent: PC;
appBarItems: PC;
appMenuItems: PC;
// optima modals that can overlay anything
showPreferencesTab: PreferencesTabType;
showModelsSetup: boolean;
showLlmOptions: DLLMId | null;
showShortcuts: boolean;
// misc/temp
isFocusedMode: boolean; // when active, the Mobile App menu is not displayed
}
const initialState: OptimaLayoutState = {
appDrawerContent: null,
appBarItems: null,
appMenuItems: null,
showPreferencesTab: 0, // 0 = closed, 1+ open tab n-1
showModelsSetup: false,
showLlmOptions: null,
showShortcuts: false,
isFocusedMode: false,
};
interface OptimaLayoutActions {
setPluggableComponents: (
appDrawerContent: PC,
appBarItems: PC,
appMenuItems: PC,
) => void;
// commands to open/close optima modals
openPreferencesTab: (tab?: PreferencesTabType) => void;
closePreferences: () => void;
openModelsSetup: () => void;
closeModelsSetup: () => void;
openLlmOptions: (id: DLLMId) => void;
closeLlmOptions: () => void;
openShortcuts: () => void;
closeShortcuts: () => void;
setIsFocusedMode: (isFocusedMode: boolean) => void;
}
// React Context with ...state and ...actions
const UseOptimaLayout = React.createContext<
(OptimaLayoutState & OptimaLayoutActions) | undefined
>(undefined);
export function OptimaLayoutProvider(props: { children: React.ReactNode }) {
// optima state, only modified by the static actions
const [state, setState] = React.useState<OptimaLayoutState>(initialState);
// actions
const actions: OptimaLayoutActions = React.useMemo(() => ({
setPluggableComponents: (appDrawerContent: PC, appBarItems: PC, appMenuItems: PC) =>
setState(state => ({ ...state, appDrawerContent, appBarItems, appMenuItems })),
openPreferencesTab: (tab?: PreferencesTabType) => setState(state => ({ ...state, showPreferencesTab: tab || PreferencesTab.Chat })),
closePreferences: () => setState(state => ({ ...state, showPreferencesTab: 0 })),
openModelsSetup: () => setState(state => ({ ...state, showModelsSetup: true })),
closeModelsSetup: () => setState(state => ({ ...state, showModelsSetup: false })),
openLlmOptions: (id: DLLMId) => setState(state => ({ ...state, showLlmOptions: id })),
closeLlmOptions: () => setState(state => ({ ...state, showLlmOptions: null })),
openShortcuts: () => setState(state => ({ ...state, showShortcuts: true })),
closeShortcuts: () => setState(state => ({ ...state, showShortcuts: false })),
setIsFocusedMode: (isFocusedMode: boolean) => setState(state => ({ ...state, isFocusedMode })),
}), []);
// global shortcuts for Optima
const shortcuts = React.useMemo((): GlobalShortcutItem[] => [
[isMacUser ? '/' : '?', true, true, false, actions.openShortcuts],
['m', true, true, false, actions.openModelsSetup],
['p', true, true, false, actions.openPreferencesTab],
], [actions]);
useGlobalShortcuts(shortcuts);
return (
<UseOptimaLayout.Provider value={{ ...state, ...actions }}>
{props.children}
</UseOptimaLayout.Provider>
);
}
/**
* Optima Layout accessor for getting state and actions
*/
export const useOptimaLayout = (): OptimaLayoutState & OptimaLayoutActions => {
const context = React.useContext(UseOptimaLayout);
if (!context)
throw new Error('useOptimaLayout must be used within an OptimaLayoutProvider');
return context;
};
/**
* used by the active UI client to register its components (and unregister on cleanup)
*/
export const usePluggableOptimaLayout = (appDrawerContent: PC, appBarItems: PC, appMenuItems: PC, debugCallerName: string) => {
const { setPluggableComponents } = useOptimaLayout();
React.useEffect(() => {
if (DEBUG_OPTIMA_LAYOUT_PLUGGING)
console.log(' +PLUG layout', debugCallerName);
setPluggableComponents(appDrawerContent, appBarItems, appMenuItems);
return () => {
if (DEBUG_OPTIMA_LAYOUT_PLUGGING)
console.log(' -UNplug layout', debugCallerName);
setPluggableComponents(null, null, null);
};
}, [appBarItems, appMenuItems, appDrawerContent, debugCallerName, setPluggableComponents]);
};