feat: 实现模块2 - TUI输入组件 (textinput)
This commit is contained in:
@@ -26,12 +26,13 @@
|
|||||||
## 当前正实现
|
## 当前正实现
|
||||||
- [x] TUI界面模块拆分计划 ✅ 已制定
|
- [x] TUI界面模块拆分计划 ✅ 已制定
|
||||||
- [x] 模块1: TUI框架搭建 ✅ 已完成
|
- [x] 模块1: TUI框架搭建 ✅ 已完成
|
||||||
|
- [x] 模块2: 输入组件 ✅ 已完成
|
||||||
|
|
||||||
## TUI界面实现计划 (v0.6.0)
|
## TUI界面实现计划 (v0.6.0)
|
||||||
| 步骤 | 模块 | 内容 | 状态 |
|
| 步骤 | 模块 | 内容 | 状态 |
|
||||||
|------|------|------|------|
|
|------|------|------|------|
|
||||||
| 1 | TUI框架搭建 | bubbletea基础App结构、运行循环 | ✅ 已完成 |
|
| 1 | TUI框架搭建 | bubbletea基础App结构、运行循环 | ✅ 已完成 |
|
||||||
| 2 | 输入组件 | 文本输入框、光标、基础编辑 | ⏳ 待实现 |
|
| 2 | 输入组件 | 文本输入框、光标、基础编辑 | ✅ 已完成 |
|
||||||
| 3 | 翻译显示区 | 结果展示、格式化、滚动 | ⏳ 待实现 |
|
| 3 | 翻译显示区 | 结果展示、格式化、滚动 | ⏳ 待实现 |
|
||||||
| 4 | 状态栏/主题 | 底部状态栏、语言选择、主题配色 | ⏳ 待实现 |
|
| 4 | 状态栏/主题 | 底部状态栏、语言选择、主题配色 | ⏳ 待实现 |
|
||||||
| 5 | 快捷键系统 | 退出、清空、切换语言等 | ⏳ 待实现 |
|
| 5 | 快捷键系统 | 退出、清空、切换语言等 | ⏳ 待实现 |
|
||||||
@@ -48,7 +49,7 @@
|
|||||||
|
|
||||||
**变更内容**:
|
**变更内容**:
|
||||||
- ✅ 模块1: TUI框架搭建 - 添加bubbletea依赖,实现基础App结构
|
- ✅ 模块1: TUI框架搭建 - 添加bubbletea依赖,实现基础App结构
|
||||||
- ⏳ 模块2: 输入组件 - 待实现
|
- ✅ 模块2: 输入组件 - textinput组件、基础输入处理
|
||||||
- ⏳ 模块3: 翻译显示区 - 待实现
|
- ⏳ 模块3: 翻译显示区 - 待实现
|
||||||
- ⏳ 模块4: 状态栏/主题 - 待实现
|
- ⏳ 模块4: 状态栏/主题 - 待实现
|
||||||
- ⏳ 模块5: 快捷键系统 - 待实现
|
- ⏳ 模块5: 快捷键系统 - 待实现
|
||||||
@@ -64,7 +65,7 @@
|
|||||||
- [TUI界面模块拆分计划](taolun.md#2026-04-06-1000-版本-060---tui界面模块拆分计划)
|
- [TUI界面模块拆分计划](taolun.md#2026-04-06-1000-版本-060---tui界面模块拆分计划)
|
||||||
|
|
||||||
**下一步**:
|
**下一步**:
|
||||||
- 实现模块2: 输入组件
|
- 实现模块3: 翻译显示区
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
package tui
|
package tui
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/charmbracelet/bubbles/textinput"
|
||||||
"github.com/charmbracelet/bubbletea"
|
"github.com/charmbracelet/bubbletea"
|
||||||
|
"github.com/charmbracelet/lipgloss"
|
||||||
"github.com/titor/fanyi/internal/config"
|
"github.com/titor/fanyi/internal/config"
|
||||||
"github.com/titor/fanyi/internal/translator"
|
"github.com/titor/fanyi/internal/translator"
|
||||||
)
|
)
|
||||||
@@ -9,12 +11,29 @@ import (
|
|||||||
type model struct {
|
type model struct {
|
||||||
config *config.Config
|
config *config.Config
|
||||||
translator *translator.Translator
|
translator *translator.Translator
|
||||||
|
textInput textinput.Model
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
inputStyle = lipgloss.NewStyle().
|
||||||
|
Foreground(lipgloss.Color("#FAFAFA")).
|
||||||
|
Background(lipgloss.Color("#1A1A2E"))
|
||||||
|
focusedStyle = lipgloss.NewStyle().
|
||||||
|
Foreground(lipgloss.Color("#FAFAFA")).
|
||||||
|
Background(lipgloss.Color("#16213E"))
|
||||||
|
)
|
||||||
|
|
||||||
func NewApp(cfg *config.Config, t *translator.Translator) *tea.Program {
|
func NewApp(cfg *config.Config, t *translator.Translator) *tea.Program {
|
||||||
|
ti := textinput.New()
|
||||||
|
ti.Placeholder = "输入要翻译的文本..."
|
||||||
|
ti.Focus()
|
||||||
|
ti.Prompt = "> "
|
||||||
|
ti.TextStyle = inputStyle
|
||||||
|
|
||||||
return tea.NewProgram(model{
|
return tea.NewProgram(model{
|
||||||
config: cfg,
|
config: cfg,
|
||||||
translator: t,
|
translator: t,
|
||||||
|
textInput: ti,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -23,9 +42,26 @@ func (m model) Init() tea.Cmd {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||||
return m, nil
|
var cmd tea.Cmd
|
||||||
|
|
||||||
|
switch msg := msg.(type) {
|
||||||
|
case tea.KeyMsg:
|
||||||
|
switch msg.Type {
|
||||||
|
case tea.KeyEnter:
|
||||||
|
// 回车键处理,后续模块会添加翻译逻辑
|
||||||
|
case tea.KeyCtrlC, tea.KeyEsc:
|
||||||
|
return m, tea.Quit
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m.textInput, cmd = m.textInput.Update(msg)
|
||||||
|
return m, cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m model) View() string {
|
func (m model) View() string {
|
||||||
return "YOYO翻译 TUI\n\n(基础框架搭建中...)\n"
|
return "\n" +
|
||||||
|
" YOYO翻译\n" +
|
||||||
|
" ─────────────────────\n\n" +
|
||||||
|
" " + m.textInput.View() + "\n\n" +
|
||||||
|
" 按 Ctrl+C 退出\n"
|
||||||
}
|
}
|
||||||
|
|||||||
31
memory.md
31
memory.md
@@ -587,3 +587,34 @@ func NewApp(cfg, translator) *tea.Program {
|
|||||||
- 版本检查(--version)需要在interactive模式检查之前
|
- 版本检查(--version)需要在interactive模式检查之前
|
||||||
- 避免interactive模式在非TTY环境启动
|
- 避免interactive模式在非TTY环境启动
|
||||||
- Run()需要两个返回值: `_, err := app.Run()`
|
- Run()需要两个返回值: `_, err := app.Run()`
|
||||||
|
|
||||||
|
### TextInput组件使用
|
||||||
|
```go
|
||||||
|
import "github.com/charmbracelet/bubbles/textinput"
|
||||||
|
|
||||||
|
// model中添加字段
|
||||||
|
type model struct {
|
||||||
|
textInput textinput.Model
|
||||||
|
}
|
||||||
|
|
||||||
|
// 初始化
|
||||||
|
ti := textinput.New()
|
||||||
|
ti.Placeholder = "输入文本..."
|
||||||
|
ti.Focus() // 获取焦点
|
||||||
|
ti.Prompt = "> " // 提示符
|
||||||
|
|
||||||
|
// Update中处理
|
||||||
|
m.textInput, cmd = m.textInput.Update(msg)
|
||||||
|
|
||||||
|
// View中显示
|
||||||
|
m.textInput.View()
|
||||||
|
```
|
||||||
|
|
||||||
|
### Lipgloss样式定义
|
||||||
|
```go
|
||||||
|
var style = lipgloss.NewStyle().
|
||||||
|
Foreground(lipgloss.Color("#FAFAFA")).
|
||||||
|
Background(lipgloss.Color("#1A1A2E"))
|
||||||
|
|
||||||
|
ti.TextStyle = style // 应用到textinput
|
||||||
|
```
|
||||||
38
taolun.md
38
taolun.md
@@ -443,3 +443,41 @@ func NewApp(cfg *config.Config, t *translator.Translator) *tea.Program {
|
|||||||
|
|
||||||
**关联文档**:
|
**关联文档**:
|
||||||
- [changelog.md#0.6.0](changelog.md#060)
|
- [changelog.md#0.6.0](changelog.md#060)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### [2026-04-06 11:00] 版本 0.6.0 - 模块2: 输入组件 (已完成)
|
||||||
|
**原因**: 实现TUI输入功能
|
||||||
|
**分析**:
|
||||||
|
- 使用bubbletea的textinput组件
|
||||||
|
- 需要焦点管理和键盘事件处理
|
||||||
|
|
||||||
|
**解决方案**:
|
||||||
|
1. 添加textinput字段到model
|
||||||
|
2. 初始化时设置placeholder和prompt
|
||||||
|
3. Update中处理KeyMsg
|
||||||
|
4. View中渲染输入框
|
||||||
|
5. 支持Ctrl+C和Esc退出
|
||||||
|
|
||||||
|
**技术实现**:
|
||||||
|
```go
|
||||||
|
type model struct {
|
||||||
|
textInput textinput.Model
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||||
|
switch msg := msg.(type) {
|
||||||
|
case tea.KeyMsg:
|
||||||
|
if msg.Type == tea.KeyCtrlC || msg.Type == tea.KeyEsc {
|
||||||
|
return m, tea.Quit
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m.textInput, cmd = m.textInput.Update(msg)
|
||||||
|
return m, cmd
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**下一步**: 实现模块3: 翻译显示区
|
||||||
|
|
||||||
|
**关联文档**:
|
||||||
|
- [changelog.md#0.6.0](changelog.md#060)
|
||||||
Reference in New Issue
Block a user