/
aqa
/
claude-code
Обзор
Документация
Войти
/
aqa
/
claude-code
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
components/ExportDialog.tsx
128 строк
19 KB
kuberwastaken
new initial commit (history rewritten)
01 апр 2026, 14:57
01 апр 2026, 14:57
c1996f2
Код
Авторство
О чём код?
import { join } from 'path'; import React, { useCallback, useState } from 'react'; import type { ExitState } from '../hooks/useExitOnCtrlCDWithKeybindings.js'; import { useTerminalSize } from '../hooks/useTerminalSize.js'; import { setClipboard } from '../ink/termio/osc.js'; import { Box, Text } from '../ink.js'; import { useKeybinding } from '../keybindings/useKeybinding.js'; import { getCwd } from '../utils/cwd.js'; import { writeFileSync_DEPRECATED } from '../utils/slowOperations.js'; import { ConfigurableShortcutHint } from './ConfigurableShortcutHint.js'; import { Select } from './CustomSelect/select.js'; import { Byline } from './design-system/Byline.js'; import { Dialog } from './design-system/Dialog.js'; import { KeyboardShortcutHint } from './design-system/KeyboardShortcutHint.js'; import TextInput from './TextInput.js'; type ExportDialogProps = { content: string; defaultFilename: string; onDone: (result: { success: boolean; message: string; }) => void; }; type ExportOption = 'clipboard' | 'file'; export function ExportDialog({ content, defaultFilename, onDone }: ExportDialogProps): React.ReactNode { const [, setSelectedOption] = useState<ExportOption | null>(null); const [filename, setFilename] = useState<string>(defaultFilename); const [cursorOffset, setCursorOffset] = useState<number>(defaultFilename.length); const [showFilenameInput, setShowFilenameInput] = useState(false); const { columns } = useTerminalSize(); // Handle going back from filename input to option selection const handleGoBack = useCallback(() => { setShowFilenameInput(false); setSelectedOption(null); }, []); const handleSelectOption = async (value: string): Promise<void> => { if (value === 'clipboard') { // Copy to clipboard immediately const raw = await setClipboard(content); if (raw) process.stdout.write(raw); onDone({ success: true, message: 'Conversation copied to clipboard' }); } else if (value === 'file') { setSelectedOption('file'); setShowFilenameInput(true); } }; const handleFilenameSubmit = () => { const finalFilename = filename.endsWith('.txt') ? filename : filename.replace(/\.[^.]+$/, '') + '.txt'; const filepath = join(getCwd(), finalFilename); try { writeFileSync_DEPRECATED(filepath, content, { encoding: 'utf-8', flush: true }); onDone({ success: true, message: `Conversation exported to: ${filepath}` }); } catch (error) { onDone({ success: false, message: `Failed to export conversation: ${error instanceof Error ? error.message : 'Unknown error'}` }); } }; // Dialog calls onCancel when Escape is pressed. If we are in the filename // input sub-screen, go back to the option list instead of closing entirely. const handleCancel = useCallback(() => { if (showFilenameInput) { handleGoBack(); } else { onDone({ success: false, message: 'Export cancelled' }); } }, [showFilenameInput, handleGoBack, onDone]); const options = [{ label: 'Copy to clipboard', value: 'clipboard', description: 'Copy the conversation to your system clipboard' }, { label: 'Save to file', value: 'file', description: 'Save the conversation to a file in the current directory' }]; // Custom input guide that changes based on dialog state function renderInputGuide(exitState: ExitState): React.ReactNode { if (showFilenameInput) { return <Byline> <KeyboardShortcutHint shortcut="Enter" action="save" /> <ConfigurableShortcutHint action="confirm:no" context="Confirmation" fallback="Esc" description="go back" /> </Byline>; } if (exitState.pending) { return <Text>Press {exitState.keyName} again to exit</Text>; } return <ConfigurableShortcutHint action="confirm:no" context="Confirmation" fallback="Esc" description="cancel" />; } // Use Settings context so 'n' key doesn't cancel (allows typing 'n' in filename input) useKeybinding('confirm:no', handleCancel, { context: 'Settings', isActive: showFilenameInput }); return <Dialog title="Export Conversation" subtitle="Select export method:" color="permission" onCancel={handleCancel} inputGuide={renderInputGuide} isCancelActive={!showFilenameInput}> {!showFilenameInput ? <Select options={options} onChange={handleSelectOption} onCancel={handleCancel} /> : <Box flexDirection="column"> <Text>Enter filename:</Text> <Box flexDirection="row" gap={1} marginTop={1}> <Text>></Text> <TextInput value={filename} onChange={setFilename} onSubmit={handleFilenameSubmit} focus={true} showCursor={true} columns={columns} cursorOffset={cursorOffset} onChangeCursorOffset={setCursorOffset} /> </Box> </Box>} </Dialog>; } //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJqb2luIiwiUmVhY3QiLCJ1c2VDYWxsYmFjayIsInVzZVN0YXRlIiwiRXhpdFN0YXRlIiwidXNlVGVybWluYWxTaXplIiwic2V0Q2xpcGJv … [Строка слишком длинная. Вы можете скачать файл]