fnglish-notebook
Version:
A cross-platform CLI tool for English learning with translation, voice pronunciation, and Notion integration. Supports Windows, macOS, and Linux.
120 lines • 8.18 kB
JavaScript
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import { useState } from 'react';
import { Text, Box } from 'ink';
import SelectInput from 'ink-select-input';
import Spinner from 'ink-spinner';
import { Logo } from './Logo.js';
import { ClaudeInput } from './ClaudeInput.js';
import { ENGLISH_LEVELS } from '../constants.js';
import { GrokService } from '../services/grok.js';
import { NotionService } from '../services/notion.js';
export const Setup = ({ onComplete }) => {
const [step, setStep] = useState('level');
const [config, setConfig] = useState({});
const [input, setInput] = useState('');
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState('');
const handleLevelSelect = (item) => {
setConfig(prev => ({ ...prev, englishLevel: item.value }));
setStep('grok');
};
const handleInput = async (value) => {
setInput('');
setError('');
setIsLoading(true);
try {
switch (step) {
case 'grok':
// 测试Grok API
const tempConfig = { ...config, grokApiKey: value };
const grokService = new GrokService(tempConfig);
const grokConnected = await grokService.testConnection();
if (!grokConnected) {
setError('Grok API密钥无效,请检查后重新输入');
setIsLoading(false);
return;
}
setConfig(prev => ({ ...prev, grokApiKey: value }));
setStep('notion_token');
break;
case 'notion_token':
setConfig(prev => ({ ...prev, notionToken: value }));
setStep('notion_database');
break;
case 'notion_database':
// 验证数据库ID
const notionConfigDb = {
...config,
notionToken: config.notionToken,
notionDatabaseId: value
};
const notionServiceDb = new NotionService(notionConfigDb);
const dbConnected = await notionServiceDb.testConnection();
if (!dbConnected) {
setError('无法访问Notion数据库,请检查Token和数据库ID');
setIsLoading(false);
return;
}
setConfig(prev => ({ ...prev, notionDatabaseId: value }));
setStep('notion_template');
break;
case 'notion_template':
setConfig(prev => ({ ...prev, notionTemplateId: value }));
setStep('notion_deck');
break;
case 'notion_deck':
// Validate deck id (which is a page ID)
// We can reuse testConnection style logic or just a quick page retrieve
// But NotionService needs to be fully instantiated to check properly
// For now, let's just save it. Validation happens when adding words usually.
// Or we can try to retrieve the page to confirm it exists.
const notionConfigFull = {
...config,
notionDeckId: value
};
// Optional: Verify deck page exists
const notionServiceDeck = new NotionService(notionConfigFull);
// We will add a helper to check page existence later in service if needed
// For now, assume it's valid if user provides it.
setConfig(prev => ({ ...prev, notionDeckId: value }));
setStep('testing');
// 进行最终测试
await new Promise(resolve => setTimeout(resolve, 1000));
setStep('complete');
onComplete(notionConfigFull);
break;
}
}
catch (err) {
setError(err instanceof Error ? err.message : '连接测试失败');
}
setIsLoading(false);
};
const renderStep = () => {
if (isLoading) {
return (_jsxs(Box, { children: [_jsx(Spinner, { type: "dots" }), _jsx(Text, { children: " \u6B63\u5728\u9A8C\u8BC1\u914D\u7F6E..." })] }));
}
switch (step) {
case 'level':
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { color: "yellow", bold: true, children: "\uD83C\uDFAF \u9009\u62E9\u82F1\u6587\u6C34\u5E73:" }), _jsx(SelectInput, { items: ENGLISH_LEVELS, onSelect: handleLevelSelect, indicatorComponent: ({ isSelected }) => (_jsx(Box, { marginRight: 1, children: _jsx(Text, { color: isSelected ? 'cyan' : 'gray', children: isSelected ? '▶' : ' ' }) })), itemComponent: ({ isSelected, label }) => (_jsx(Text, { color: isSelected ? 'cyan' : 'white', bold: isSelected, children: label })) })] }));
case 'grok':
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(ClaudeInput, { value: input, onChange: setInput, onSubmit: handleInput, placeholder: "\u8F93\u5165API\u5BC6\u94A5...", label: "\uD83E\uDD16 Grok API Key:", mask: "*" }), _jsx(Text, { color: "gray", dimColor: true, children: "docs.x.ai/docs" })] }));
case 'notion_token':
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(ClaudeInput, { value: input, onChange: setInput, onSubmit: handleInput, placeholder: "\u8F93\u5165Token...", label: "\uD83D\uDCDD Notion Token:", mask: "*" }), _jsx(Text, { color: "gray", dimColor: true, children: "notion.so/my-integrations" })] }));
case 'notion_database':
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(ClaudeInput, { value: input, onChange: setInput, onSubmit: handleInput, placeholder: "\u8F93\u5165\u6570\u636E\u5E93ID...", label: "\uD83D\uDDC4\uFE0F Notion\u6570\u636E\u5E93ID:" }), _jsx(Text, { color: "gray", dimColor: true, children: "\u4ECE\u6570\u636E\u5E93\u9875\u9762URL\u590D\u5236ID" })] }));
case 'notion_template':
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(ClaudeInput, { value: input, onChange: setInput, onSubmit: handleInput, placeholder: "\u8F93\u5165\u6A21\u7248\u9875\u9762ID...", label: "\uD83D\uDCCB Notion\u6A21\u7248\u9875\u9762ID:" }), _jsx(Text, { color: "gray", dimColor: true, children: "\u7528\u4E8E\u590D\u5236\u56FE\u6807\u548C\u5C01\u9762\u7684\u9875\u9762ID" })] }));
case 'notion_deck':
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(ClaudeInput, { value: input, onChange: setInput, onSubmit: handleInput, placeholder: "\u8F93\u5165\u724C\u7EC4\u9875\u9762ID...", label: "\uD83C\uDFB4 Notion\u724C\u7EC4\u9875\u9762ID:" }), _jsx(Text, { color: "gray", dimColor: true, children: "\u5355\u8BCD\u5C06\u81EA\u52A8\u5173\u8054\u5230\u6B64\u724C\u7EC4(Page ID)" })] }));
case 'testing':
return (_jsxs(Box, { children: [_jsx(Spinner, { type: "dots" }), _jsx(Text, { children: " \u6B63\u5728\u4FDD\u5B58\u914D\u7F6E..." })] }));
case 'complete':
return (_jsx(Text, { color: "green", children: "\u2705 \u914D\u7F6E\u5B8C\u6210\uFF01\u6B63\u5728\u542F\u52A8\u5E94\u7528..." }));
default:
return null;
}
};
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Logo, {}), _jsxs(Box, { flexDirection: "row", justifyContent: "space-between", children: [_jsx(Text, { color: "cyan", bold: true, children: "\uD83D\uDE80 \u6B22\u8FCE\u4F7F\u7528 Fnglish Notebook!" }), _jsx(Text, { color: "gray", dimColor: true, children: "\u9996\u6B21\u914D\u7F6E" })] }), error && (_jsx(Box, { marginTop: 1, children: _jsxs(Text, { color: "red", children: ["\u274C ", error] }) })), _jsx(Box, { marginTop: 1, children: renderStep() })] }));
};
//# sourceMappingURL=Setup.js.map