mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-04-30 15:04:16 -07:00
Revert "feat(accessibility): implement centralized screen reader layo… (#9255)
This commit is contained in:
@@ -32,46 +32,6 @@ vi.mock('./components/QuittingDisplay.js', () => ({
|
|||||||
QuittingDisplay: () => <Text>Quitting...</Text>,
|
QuittingDisplay: () => <Text>Quitting...</Text>,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
vi.mock('./components/Footer.js', () => ({
|
|
||||||
Footer: () => <Text>Footer</Text>,
|
|
||||||
}));
|
|
||||||
|
|
||||||
vi.mock('./semantic-colors.js', () => ({
|
|
||||||
theme: {
|
|
||||||
status: {
|
|
||||||
warning: 'yellow',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
|
|
||||||
// Don't mock the layout components - let them render normally so tests can see the Ctrl messages
|
|
||||||
|
|
||||||
vi.mock('./hooks/useLayoutConfig.js', () => ({
|
|
||||||
useLayoutConfig: () => ({
|
|
||||||
mode: 'default',
|
|
||||||
shouldUseStatic: true,
|
|
||||||
shouldShowFooterInComposer: true,
|
|
||||||
}),
|
|
||||||
}));
|
|
||||||
|
|
||||||
vi.mock('./hooks/useFooterProps.js', () => ({
|
|
||||||
useFooterProps: () => ({
|
|
||||||
model: 'test-model',
|
|
||||||
targetDir: '/test',
|
|
||||||
debugMode: false,
|
|
||||||
branchName: 'test-branch',
|
|
||||||
debugMessage: '',
|
|
||||||
corgiMode: false,
|
|
||||||
errorCount: 0,
|
|
||||||
showErrorDetails: false,
|
|
||||||
showMemoryUsage: false,
|
|
||||||
promptTokenCount: 0,
|
|
||||||
nightly: false,
|
|
||||||
isTrustedFolder: true,
|
|
||||||
vimMode: undefined,
|
|
||||||
}),
|
|
||||||
}));
|
|
||||||
|
|
||||||
describe('App', () => {
|
describe('App', () => {
|
||||||
const mockUIState: Partial<UIState> = {
|
const mockUIState: Partial<UIState> = {
|
||||||
streamingState: StreamingState.Idle,
|
streamingState: StreamingState.Idle,
|
||||||
@@ -95,6 +55,7 @@ describe('App', () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
expect(lastFrame()).toContain('MainContent');
|
expect(lastFrame()).toContain('MainContent');
|
||||||
|
expect(lastFrame()).toContain('Notifications');
|
||||||
expect(lastFrame()).toContain('Composer');
|
expect(lastFrame()).toContain('Composer');
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -126,6 +87,7 @@ describe('App', () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
expect(lastFrame()).toContain('MainContent');
|
expect(lastFrame()).toContain('MainContent');
|
||||||
|
expect(lastFrame()).toContain('Notifications');
|
||||||
expect(lastFrame()).toContain('DialogManager');
|
expect(lastFrame()).toContain('DialogManager');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
+36
-10
@@ -4,16 +4,18 @@
|
|||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { useUIState } from './contexts/UIStateContext.js';
|
import { Box, Text } from 'ink';
|
||||||
import { StreamingContext } from './contexts/StreamingContext.js';
|
import { StreamingContext } from './contexts/StreamingContext.js';
|
||||||
|
import { Notifications } from './components/Notifications.js';
|
||||||
|
import { MainContent } from './components/MainContent.js';
|
||||||
|
import { DialogManager } from './components/DialogManager.js';
|
||||||
|
import { Composer } from './components/Composer.js';
|
||||||
|
import { useUIState } from './contexts/UIStateContext.js';
|
||||||
import { QuittingDisplay } from './components/QuittingDisplay.js';
|
import { QuittingDisplay } from './components/QuittingDisplay.js';
|
||||||
import { useLayoutConfig } from './hooks/useLayoutConfig.js';
|
import { theme } from './semantic-colors.js';
|
||||||
import { ScreenReaderAppLayout } from './layouts/ScreenReaderAppLayout.js';
|
|
||||||
import { DefaultAppLayout } from './layouts/DefaultAppLayout.js';
|
|
||||||
|
|
||||||
export const App = () => {
|
export const App = () => {
|
||||||
const uiState = useUIState();
|
const uiState = useUIState();
|
||||||
const layout = useLayoutConfig();
|
|
||||||
|
|
||||||
if (uiState.quittingMessages) {
|
if (uiState.quittingMessages) {
|
||||||
return <QuittingDisplay />;
|
return <QuittingDisplay />;
|
||||||
@@ -21,11 +23,35 @@ export const App = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<StreamingContext.Provider value={uiState.streamingState}>
|
<StreamingContext.Provider value={uiState.streamingState}>
|
||||||
{layout.mode === 'screenReader' ? (
|
<Box flexDirection="column" width="90%">
|
||||||
<ScreenReaderAppLayout />
|
<MainContent />
|
||||||
) : (
|
|
||||||
<DefaultAppLayout />
|
<Box flexDirection="column" ref={uiState.mainControlsRef}>
|
||||||
)}
|
<Notifications />
|
||||||
|
|
||||||
|
{uiState.dialogsVisible ? (
|
||||||
|
<DialogManager addItem={uiState.historyManager.addItem} />
|
||||||
|
) : (
|
||||||
|
<Composer />
|
||||||
|
)}
|
||||||
|
|
||||||
|
{uiState.dialogsVisible && uiState.ctrlCPressedOnce && (
|
||||||
|
<Box marginTop={1}>
|
||||||
|
<Text color={theme.status.warning}>
|
||||||
|
Press Ctrl+C again to exit.
|
||||||
|
</Text>
|
||||||
|
</Box>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{uiState.dialogsVisible && uiState.ctrlDPressedOnce && (
|
||||||
|
<Box marginTop={1}>
|
||||||
|
<Text color={theme.status.warning}>
|
||||||
|
Press Ctrl+D again to exit.
|
||||||
|
</Text>
|
||||||
|
</Box>
|
||||||
|
)}
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
</StreamingContext.Provider>
|
</StreamingContext.Provider>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -26,12 +26,10 @@ import { useSettings } from '../contexts/SettingsContext.js';
|
|||||||
import { ApprovalMode } from '@google/gemini-cli-core';
|
import { ApprovalMode } from '@google/gemini-cli-core';
|
||||||
import { StreamingState } from '../types.js';
|
import { StreamingState } from '../types.js';
|
||||||
import { ConfigInitDisplay } from '../components/ConfigInitDisplay.js';
|
import { ConfigInitDisplay } from '../components/ConfigInitDisplay.js';
|
||||||
import { useLayoutConfig } from '../hooks/useLayoutConfig.js';
|
|
||||||
|
|
||||||
export const Composer = () => {
|
export const Composer = () => {
|
||||||
const config = useConfig();
|
const config = useConfig();
|
||||||
const settings = useSettings();
|
const settings = useSettings();
|
||||||
const layout = useLayoutConfig();
|
|
||||||
const uiState = useUIState();
|
const uiState = useUIState();
|
||||||
const uiActions = useUIActions();
|
const uiActions = useUIActions();
|
||||||
const { vimEnabled, vimMode } = useVimMode();
|
const { vimEnabled, vimMode } = useVimMode();
|
||||||
@@ -178,7 +176,7 @@ export const Composer = () => {
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{!settings.merged.ui?.hideFooter && layout.shouldShowFooterInComposer && (
|
{!settings.merged.ui?.hideFooter && (
|
||||||
<Footer {...footerProps} vimMode={vimEnabled ? vimMode : undefined} />
|
<Footer {...footerProps} vimMode={vimEnabled ? vimMode : undefined} />
|
||||||
)}
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
|
|||||||
@@ -1,36 +0,0 @@
|
|||||||
/**
|
|
||||||
* @license
|
|
||||||
* Copyright 2025 Google LLC
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { HistoryItemDisplay } from './HistoryItemDisplay.js';
|
|
||||||
import type { HistoryItem } from '../types.js';
|
|
||||||
import type { SlashCommand } from '../commands/types.js';
|
|
||||||
|
|
||||||
interface HistoryListProps {
|
|
||||||
history: HistoryItem[];
|
|
||||||
terminalWidth: number;
|
|
||||||
staticAreaMaxItemHeight: number;
|
|
||||||
slashCommands: readonly SlashCommand[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export const HistoryList = ({
|
|
||||||
history,
|
|
||||||
terminalWidth,
|
|
||||||
staticAreaMaxItemHeight,
|
|
||||||
slashCommands,
|
|
||||||
}: HistoryListProps) => (
|
|
||||||
<>
|
|
||||||
{history.map((h) => (
|
|
||||||
<HistoryItemDisplay
|
|
||||||
terminalWidth={terminalWidth}
|
|
||||||
availableTerminalHeight={staticAreaMaxItemHeight}
|
|
||||||
key={h.id}
|
|
||||||
item={h}
|
|
||||||
isPending={false}
|
|
||||||
commands={slashCommands}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
@@ -5,19 +5,16 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { Box, Static } from 'ink';
|
import { Box, Static } from 'ink';
|
||||||
import { HistoryList } from './HistoryList.js';
|
import { HistoryItemDisplay } from './HistoryItemDisplay.js';
|
||||||
import { PendingHistoryList } from './PendingHistoryList.js';
|
|
||||||
import { ShowMoreLines } from './ShowMoreLines.js';
|
import { ShowMoreLines } from './ShowMoreLines.js';
|
||||||
import { OverflowProvider } from '../contexts/OverflowContext.js';
|
import { OverflowProvider } from '../contexts/OverflowContext.js';
|
||||||
import { useUIState } from '../contexts/UIStateContext.js';
|
import { useUIState } from '../contexts/UIStateContext.js';
|
||||||
import { useAppContext } from '../contexts/AppContext.js';
|
import { useAppContext } from '../contexts/AppContext.js';
|
||||||
import { AppHeader } from './AppHeader.js';
|
import { AppHeader } from './AppHeader.js';
|
||||||
import { useLayoutConfig } from '../hooks/useLayoutConfig.js';
|
|
||||||
|
|
||||||
export const MainContent = () => {
|
export const MainContent = () => {
|
||||||
const { version } = useAppContext();
|
const { version } = useAppContext();
|
||||||
const uiState = useUIState();
|
const uiState = useUIState();
|
||||||
const layout = useLayoutConfig();
|
|
||||||
const {
|
const {
|
||||||
pendingHistoryItems,
|
pendingHistoryItems,
|
||||||
mainAreaWidth,
|
mainAreaWidth,
|
||||||
@@ -25,60 +22,42 @@ export const MainContent = () => {
|
|||||||
availableTerminalHeight,
|
availableTerminalHeight,
|
||||||
} = uiState;
|
} = uiState;
|
||||||
|
|
||||||
// In screen reader mode, use regular layout without Static component
|
|
||||||
if (!layout.shouldUseStatic) {
|
|
||||||
return (
|
|
||||||
<OverflowProvider>
|
|
||||||
<Box flexDirection="column">
|
|
||||||
<AppHeader version={version} />
|
|
||||||
<HistoryList
|
|
||||||
history={uiState.history}
|
|
||||||
terminalWidth={mainAreaWidth}
|
|
||||||
staticAreaMaxItemHeight={staticAreaMaxItemHeight}
|
|
||||||
slashCommands={uiState.slashCommands}
|
|
||||||
/>
|
|
||||||
<PendingHistoryList
|
|
||||||
pendingHistoryItems={pendingHistoryItems}
|
|
||||||
terminalWidth={mainAreaWidth}
|
|
||||||
availableTerminalHeight={availableTerminalHeight}
|
|
||||||
constrainHeight={uiState.constrainHeight}
|
|
||||||
isEditorDialogOpen={uiState.isEditorDialogOpen}
|
|
||||||
/>
|
|
||||||
<ShowMoreLines constrainHeight={uiState.constrainHeight} />
|
|
||||||
</Box>
|
|
||||||
</OverflowProvider>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Default mode with Static component
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Static
|
<Static
|
||||||
key={uiState.historyRemountKey}
|
key={uiState.historyRemountKey}
|
||||||
items={[
|
items={[
|
||||||
<AppHeader key="app-header" version={version} />,
|
<AppHeader key="app-header" version={version} />,
|
||||||
<HistoryList
|
...uiState.history.map((h) => (
|
||||||
key="history-list"
|
<HistoryItemDisplay
|
||||||
history={uiState.history}
|
terminalWidth={mainAreaWidth}
|
||||||
terminalWidth={mainAreaWidth}
|
availableTerminalHeight={staticAreaMaxItemHeight}
|
||||||
staticAreaMaxItemHeight={staticAreaMaxItemHeight}
|
key={h.id}
|
||||||
slashCommands={uiState.slashCommands}
|
item={h}
|
||||||
/>,
|
isPending={false}
|
||||||
|
commands={uiState.slashCommands}
|
||||||
|
/>
|
||||||
|
)),
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
{(item) => item}
|
{(item) => item}
|
||||||
</Static>
|
</Static>
|
||||||
<OverflowProvider>
|
<OverflowProvider>
|
||||||
<Box flexDirection="column">
|
<Box flexDirection="column">
|
||||||
<PendingHistoryList
|
{pendingHistoryItems.map((item, i) => (
|
||||||
pendingHistoryItems={pendingHistoryItems}
|
<HistoryItemDisplay
|
||||||
terminalWidth={mainAreaWidth}
|
key={i}
|
||||||
availableTerminalHeight={availableTerminalHeight}
|
availableTerminalHeight={
|
||||||
constrainHeight={uiState.constrainHeight}
|
uiState.constrainHeight ? availableTerminalHeight : undefined
|
||||||
isEditorDialogOpen={uiState.isEditorDialogOpen}
|
}
|
||||||
activePtyId={uiState.activePtyId?.toString()}
|
terminalWidth={mainAreaWidth}
|
||||||
embeddedShellFocused={uiState.embeddedShellFocused}
|
item={{ ...item, id: 0 }}
|
||||||
/>
|
isPending={true}
|
||||||
|
isFocused={!uiState.isEditorDialogOpen}
|
||||||
|
activeShellPtyId={uiState.activePtyId}
|
||||||
|
embeddedShellFocused={uiState.embeddedShellFocused}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
<ShowMoreLines constrainHeight={uiState.constrainHeight} />
|
<ShowMoreLines constrainHeight={uiState.constrainHeight} />
|
||||||
</Box>
|
</Box>
|
||||||
</OverflowProvider>
|
</OverflowProvider>
|
||||||
|
|||||||
@@ -1,45 +0,0 @@
|
|||||||
/**
|
|
||||||
* @license
|
|
||||||
* Copyright 2025 Google LLC
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { HistoryItemDisplay } from './HistoryItemDisplay.js';
|
|
||||||
import type { HistoryItemWithoutId } from '../types.js';
|
|
||||||
|
|
||||||
interface PendingHistoryListProps {
|
|
||||||
pendingHistoryItems: HistoryItemWithoutId[];
|
|
||||||
terminalWidth: number;
|
|
||||||
availableTerminalHeight?: number;
|
|
||||||
constrainHeight?: boolean;
|
|
||||||
isEditorDialogOpen: boolean;
|
|
||||||
activePtyId?: string;
|
|
||||||
embeddedShellFocused?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const PendingHistoryList = ({
|
|
||||||
pendingHistoryItems,
|
|
||||||
terminalWidth,
|
|
||||||
availableTerminalHeight,
|
|
||||||
constrainHeight,
|
|
||||||
isEditorDialogOpen,
|
|
||||||
activePtyId,
|
|
||||||
embeddedShellFocused,
|
|
||||||
}: PendingHistoryListProps) => (
|
|
||||||
<>
|
|
||||||
{pendingHistoryItems.map((item, i) => (
|
|
||||||
<HistoryItemDisplay
|
|
||||||
key={i}
|
|
||||||
availableTerminalHeight={
|
|
||||||
constrainHeight ? availableTerminalHeight : undefined
|
|
||||||
}
|
|
||||||
terminalWidth={terminalWidth}
|
|
||||||
item={{ ...item, id: 0 }}
|
|
||||||
isPending={true}
|
|
||||||
isFocused={!isEditorDialogOpen}
|
|
||||||
activeShellPtyId={activePtyId ? parseInt(activePtyId, 10) : null}
|
|
||||||
embeddedShellFocused={embeddedShellFocused}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
/**
|
|
||||||
* @license
|
|
||||||
* Copyright 2025 Google LLC
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { useUIState } from '../contexts/UIStateContext.js';
|
|
||||||
import { useConfig } from '../contexts/ConfigContext.js';
|
|
||||||
import { useSettings } from '../contexts/SettingsContext.js';
|
|
||||||
|
|
||||||
export const useFooterProps = () => {
|
|
||||||
const uiState = useUIState();
|
|
||||||
const config = useConfig();
|
|
||||||
const settings = useSettings();
|
|
||||||
|
|
||||||
return {
|
|
||||||
model: config.getModel(),
|
|
||||||
targetDir: config.getTargetDir(),
|
|
||||||
debugMode: config.getDebugMode(),
|
|
||||||
branchName: uiState.branchName,
|
|
||||||
debugMessage: uiState.debugMessage,
|
|
||||||
corgiMode: uiState.corgiMode,
|
|
||||||
errorCount: uiState.errorCount,
|
|
||||||
showErrorDetails: uiState.showErrorDetails,
|
|
||||||
showMemoryUsage:
|
|
||||||
config.getDebugMode() || settings.merged.ui?.showMemoryUsage || false,
|
|
||||||
promptTokenCount: uiState.sessionStats.lastPromptTokenCount,
|
|
||||||
nightly: uiState.nightly,
|
|
||||||
isTrustedFolder: uiState.isTrustedFolder,
|
|
||||||
vimMode: undefined,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
/**
|
|
||||||
* @license
|
|
||||||
* Copyright 2025 Google LLC
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { useIsScreenReaderEnabled } from 'ink';
|
|
||||||
|
|
||||||
export interface LayoutConfig {
|
|
||||||
shouldUseStatic: boolean;
|
|
||||||
shouldShowFooterInComposer: boolean;
|
|
||||||
mode: 'default' | 'screenReader';
|
|
||||||
allowStaticToggle?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface LayoutConfigOptions {
|
|
||||||
forceStaticMode?: boolean;
|
|
||||||
allowToggle?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const useLayoutConfig = (
|
|
||||||
options?: LayoutConfigOptions,
|
|
||||||
): LayoutConfig => {
|
|
||||||
const isScreenReader = useIsScreenReaderEnabled();
|
|
||||||
|
|
||||||
// Allow overriding static behavior when toggle is enabled
|
|
||||||
const shouldUseStatic =
|
|
||||||
options?.forceStaticMode !== undefined
|
|
||||||
? options.forceStaticMode
|
|
||||||
: !isScreenReader;
|
|
||||||
|
|
||||||
return {
|
|
||||||
shouldUseStatic,
|
|
||||||
shouldShowFooterInComposer: !isScreenReader,
|
|
||||||
mode: isScreenReader ? 'screenReader' : 'default',
|
|
||||||
allowStaticToggle: options?.allowToggle ?? false,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
@@ -1,50 +0,0 @@
|
|||||||
/**
|
|
||||||
* @license
|
|
||||||
* Copyright 2025 Google LLC
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
import type React from 'react';
|
|
||||||
import { Box, Text } from 'ink';
|
|
||||||
import { Notifications } from '../components/Notifications.js';
|
|
||||||
import { MainContent } from '../components/MainContent.js';
|
|
||||||
import { DialogManager } from '../components/DialogManager.js';
|
|
||||||
import { Composer } from '../components/Composer.js';
|
|
||||||
import { useUIState } from '../contexts/UIStateContext.js';
|
|
||||||
import { theme } from '../semantic-colors.js';
|
|
||||||
|
|
||||||
export const DefaultAppLayout: React.FC = () => {
|
|
||||||
const uiState = useUIState();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Box flexDirection="column" width="90%">
|
|
||||||
<MainContent />
|
|
||||||
|
|
||||||
<Box flexDirection="column" ref={uiState.mainControlsRef}>
|
|
||||||
<Notifications />
|
|
||||||
|
|
||||||
{uiState.dialogsVisible ? (
|
|
||||||
<DialogManager addItem={uiState.historyManager.addItem} />
|
|
||||||
) : (
|
|
||||||
<Composer />
|
|
||||||
)}
|
|
||||||
|
|
||||||
{uiState.dialogsVisible && uiState.ctrlCPressedOnce && (
|
|
||||||
<Box marginTop={1}>
|
|
||||||
<Text color={theme.status.warning}>
|
|
||||||
Press Ctrl+C again to exit.
|
|
||||||
</Text>
|
|
||||||
</Box>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{uiState.dialogsVisible && uiState.ctrlDPressedOnce && (
|
|
||||||
<Box marginTop={1}>
|
|
||||||
<Text color={theme.status.warning}>
|
|
||||||
Press Ctrl+D again to exit.
|
|
||||||
</Text>
|
|
||||||
</Box>
|
|
||||||
)}
|
|
||||||
</Box>
|
|
||||||
</Box>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
/**
|
|
||||||
* @license
|
|
||||||
* Copyright 2025 Google LLC
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
import type React from 'react';
|
|
||||||
import { Box, Text } from 'ink';
|
|
||||||
import { Notifications } from '../components/Notifications.js';
|
|
||||||
import { MainContent } from '../components/MainContent.js';
|
|
||||||
import { DialogManager } from '../components/DialogManager.js';
|
|
||||||
import { Composer } from '../components/Composer.js';
|
|
||||||
import { Footer } from '../components/Footer.js';
|
|
||||||
import { useUIState } from '../contexts/UIStateContext.js';
|
|
||||||
import { useFooterProps } from '../hooks/useFooterProps.js';
|
|
||||||
import { theme } from '../semantic-colors.js';
|
|
||||||
|
|
||||||
export const ScreenReaderAppLayout: React.FC = () => {
|
|
||||||
const uiState = useUIState();
|
|
||||||
const footerProps = useFooterProps();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Box flexDirection="column" width="90%" height="100%">
|
|
||||||
<Notifications />
|
|
||||||
<Footer {...footerProps} />
|
|
||||||
<Box flexGrow={1} overflow="hidden">
|
|
||||||
<MainContent />
|
|
||||||
</Box>
|
|
||||||
{uiState.dialogsVisible ? (
|
|
||||||
<DialogManager addItem={uiState.historyManager.addItem} />
|
|
||||||
) : (
|
|
||||||
<Composer />
|
|
||||||
)}
|
|
||||||
|
|
||||||
{uiState.dialogsVisible && uiState.ctrlDPressedOnce && (
|
|
||||||
<Box marginTop={1}>
|
|
||||||
<Text color={theme.status.warning}>Press Ctrl+C again to exit.</Text>
|
|
||||||
</Box>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{uiState.dialogsVisible && uiState.ctrlDPressedOnce && (
|
|
||||||
<Box marginTop={1}>
|
|
||||||
<Text color={theme.status.warning}>Press Ctrl+D again to exit.</Text>
|
|
||||||
</Box>
|
|
||||||
)}
|
|
||||||
</Box>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
Reference in New Issue
Block a user