floq 0.0.1 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.ja.md +157 -29
- package/README.md +157 -29
- package/dist/changelog.d.ts +13 -0
- package/dist/changelog.js +95 -0
- package/dist/cli.js +70 -1
- package/dist/commands/add.js +5 -6
- package/dist/commands/comment.d.ts +2 -0
- package/dist/commands/comment.js +67 -0
- package/dist/commands/config.d.ts +7 -0
- package/dist/commands/config.js +163 -14
- package/dist/commands/done.js +4 -6
- package/dist/commands/list.js +9 -13
- package/dist/commands/move.js +4 -6
- package/dist/commands/project.js +18 -26
- package/dist/commands/setup.d.ts +1 -0
- package/dist/commands/setup.js +13 -0
- package/dist/config.d.ts +15 -1
- package/dist/config.js +53 -2
- package/dist/db/index.d.ts +5 -4
- package/dist/db/index.js +127 -32
- package/dist/db/schema.d.ts +83 -0
- package/dist/db/schema.js +6 -0
- package/dist/i18n/en.d.ts +258 -0
- package/dist/i18n/en.js +138 -3
- package/dist/i18n/ja.js +138 -3
- package/dist/index.js +33 -1
- package/dist/paths.d.ts +4 -0
- package/dist/paths.js +63 -5
- package/dist/ui/App.js +384 -136
- package/dist/ui/ModeSelector.d.ts +7 -0
- package/dist/ui/ModeSelector.js +37 -0
- package/dist/ui/SetupWizard.d.ts +6 -0
- package/dist/ui/SetupWizard.js +321 -0
- package/dist/ui/ThemeSelector.d.ts +1 -1
- package/dist/ui/ThemeSelector.js +23 -10
- package/dist/ui/components/FunctionKeyBar.d.ts +5 -4
- package/dist/ui/components/FunctionKeyBar.js +19 -15
- package/dist/ui/components/HelpModal.d.ts +2 -1
- package/dist/ui/components/HelpModal.js +118 -4
- package/dist/ui/components/KanbanBoard.d.ts +6 -0
- package/dist/ui/components/KanbanBoard.js +508 -0
- package/dist/ui/components/KanbanColumn.d.ts +12 -0
- package/dist/ui/components/KanbanColumn.js +11 -0
- package/dist/ui/components/ProgressBar.d.ts +7 -0
- package/dist/ui/components/ProgressBar.js +13 -0
- package/dist/ui/components/SearchBar.d.ts +8 -0
- package/dist/ui/components/SearchBar.js +11 -0
- package/dist/ui/components/SearchResults.d.ts +9 -0
- package/dist/ui/components/SearchResults.js +18 -0
- package/dist/ui/components/TaskItem.d.ts +6 -1
- package/dist/ui/components/TaskItem.js +3 -2
- package/dist/ui/theme/themes.d.ts +12 -0
- package/dist/ui/theme/themes.js +495 -3
- package/dist/ui/theme/types.d.ts +1 -1
- package/package.json +2 -1
package/dist/ui/App.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useState, useEffect } from 'react';
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { useState, useEffect, useCallback } from 'react';
|
|
3
3
|
import { Box, Text, useInput, useApp } from 'ink';
|
|
4
4
|
import TextInput from 'ink-text-input';
|
|
5
5
|
import { eq, and } from 'drizzle-orm';
|
|
@@ -7,15 +7,20 @@ import { v4 as uuidv4 } from 'uuid';
|
|
|
7
7
|
import { TaskItem } from './components/TaskItem.js';
|
|
8
8
|
import { HelpModal } from './components/HelpModal.js';
|
|
9
9
|
import { FunctionKeyBar } from './components/FunctionKeyBar.js';
|
|
10
|
+
import { SearchBar } from './components/SearchBar.js';
|
|
11
|
+
import { SearchResults } from './components/SearchResults.js';
|
|
10
12
|
import { SplashScreen } from './SplashScreen.js';
|
|
11
13
|
import { getDb, schema } from '../db/index.js';
|
|
12
14
|
import { t, fmt } from '../i18n/index.js';
|
|
13
15
|
import { ThemeProvider, useTheme } from './theme/index.js';
|
|
14
|
-
import { getThemeName } from '../config.js';
|
|
15
|
-
|
|
16
|
+
import { getThemeName, getViewMode, isTursoEnabled, getTursoConfig } from '../config.js';
|
|
17
|
+
import { KanbanBoard } from './components/KanbanBoard.js';
|
|
18
|
+
import { VERSION } from '../version.js';
|
|
19
|
+
const TABS = ['inbox', 'next', 'waiting', 'someday', 'projects', 'done'];
|
|
16
20
|
export function App() {
|
|
17
21
|
const themeName = getThemeName();
|
|
18
|
-
|
|
22
|
+
const viewMode = getViewMode();
|
|
23
|
+
return (_jsx(ThemeProvider, { themeName: themeName, children: viewMode === 'kanban' ? _jsx(KanbanBoard, {}) : _jsx(AppContent, {}) }));
|
|
19
24
|
}
|
|
20
25
|
function AppContent() {
|
|
21
26
|
const theme = useTheme();
|
|
@@ -30,14 +35,24 @@ function AppContent() {
|
|
|
30
35
|
waiting: [],
|
|
31
36
|
someday: [],
|
|
32
37
|
projects: [],
|
|
38
|
+
done: [],
|
|
33
39
|
});
|
|
34
40
|
const [message, setMessage] = useState(null);
|
|
35
41
|
const [selectedProject, setSelectedProject] = useState(null);
|
|
36
42
|
const [projectTasks, setProjectTasks] = useState([]);
|
|
37
43
|
const [taskToLink, setTaskToLink] = useState(null);
|
|
38
44
|
const [projectSelectIndex, setProjectSelectIndex] = useState(0);
|
|
45
|
+
const [selectedTask, setSelectedTask] = useState(null);
|
|
46
|
+
const [taskComments, setTaskComments] = useState([]);
|
|
47
|
+
const [selectedCommentIndex, setSelectedCommentIndex] = useState(0);
|
|
48
|
+
const [taskToWaiting, setTaskToWaiting] = useState(null);
|
|
49
|
+
const [projectProgress, setProjectProgress] = useState({});
|
|
50
|
+
// Search state
|
|
51
|
+
const [searchQuery, setSearchQuery] = useState('');
|
|
52
|
+
const [searchResults, setSearchResults] = useState([]);
|
|
53
|
+
const [searchResultIndex, setSearchResultIndex] = useState(0);
|
|
39
54
|
const i18n = t();
|
|
40
|
-
const loadTasks = () => {
|
|
55
|
+
const loadTasks = useCallback(async () => {
|
|
41
56
|
const db = getDb();
|
|
42
57
|
const newTasks = {
|
|
43
58
|
inbox: [],
|
|
@@ -45,50 +60,92 @@ function AppContent() {
|
|
|
45
60
|
waiting: [],
|
|
46
61
|
someday: [],
|
|
47
62
|
projects: [],
|
|
63
|
+
done: [],
|
|
48
64
|
};
|
|
49
65
|
// Load all tasks (including project children) by status
|
|
50
|
-
const statusList = ['inbox', 'next', 'waiting', 'someday'];
|
|
66
|
+
const statusList = ['inbox', 'next', 'waiting', 'someday', 'done'];
|
|
51
67
|
for (const status of statusList) {
|
|
52
|
-
newTasks[status] = db
|
|
68
|
+
newTasks[status] = await db
|
|
53
69
|
.select()
|
|
54
70
|
.from(schema.tasks)
|
|
55
|
-
.where(and(eq(schema.tasks.status, status), eq(schema.tasks.isProject, false)))
|
|
56
|
-
.all();
|
|
71
|
+
.where(and(eq(schema.tasks.status, status), eq(schema.tasks.isProject, false)));
|
|
57
72
|
}
|
|
58
73
|
// Load projects (isProject = true, not done)
|
|
59
|
-
newTasks.projects = db
|
|
74
|
+
newTasks.projects = await db
|
|
60
75
|
.select()
|
|
61
76
|
.from(schema.tasks)
|
|
62
|
-
.where(and(eq(schema.tasks.isProject, true), eq(schema.tasks.status, 'next')))
|
|
63
|
-
|
|
77
|
+
.where(and(eq(schema.tasks.isProject, true), eq(schema.tasks.status, 'next')));
|
|
78
|
+
// Calculate progress for each project
|
|
79
|
+
const progress = {};
|
|
80
|
+
for (const project of newTasks.projects) {
|
|
81
|
+
const children = await db
|
|
82
|
+
.select()
|
|
83
|
+
.from(schema.tasks)
|
|
84
|
+
.where(eq(schema.tasks.parentId, project.id));
|
|
85
|
+
const total = children.length;
|
|
86
|
+
const completed = children.filter(t => t.status === 'done').length;
|
|
87
|
+
progress[project.id] = { completed, total };
|
|
88
|
+
}
|
|
89
|
+
setProjectProgress(progress);
|
|
64
90
|
setTasks(newTasks);
|
|
65
|
-
};
|
|
91
|
+
}, []);
|
|
66
92
|
// Get parent project for a task
|
|
67
93
|
const getParentProject = (parentId) => {
|
|
68
94
|
if (!parentId)
|
|
69
95
|
return undefined;
|
|
70
96
|
return tasks.projects.find(p => p.id === parentId);
|
|
71
97
|
};
|
|
72
|
-
const loadProjectTasks = (projectId) => {
|
|
98
|
+
const loadProjectTasks = useCallback(async (projectId) => {
|
|
73
99
|
const db = getDb();
|
|
74
|
-
const children = db
|
|
100
|
+
const children = await db
|
|
75
101
|
.select()
|
|
76
102
|
.from(schema.tasks)
|
|
77
|
-
.where(eq(schema.tasks.parentId, projectId))
|
|
78
|
-
.all();
|
|
103
|
+
.where(eq(schema.tasks.parentId, projectId));
|
|
79
104
|
setProjectTasks(children);
|
|
80
|
-
};
|
|
105
|
+
}, []);
|
|
106
|
+
const loadTaskComments = useCallback(async (taskId) => {
|
|
107
|
+
const db = getDb();
|
|
108
|
+
const comments = await db
|
|
109
|
+
.select()
|
|
110
|
+
.from(schema.comments)
|
|
111
|
+
.where(eq(schema.comments.taskId, taskId));
|
|
112
|
+
setTaskComments(comments);
|
|
113
|
+
}, []);
|
|
81
114
|
useEffect(() => {
|
|
82
115
|
loadTasks();
|
|
83
|
-
}, []);
|
|
116
|
+
}, [loadTasks]);
|
|
84
117
|
const currentTab = TABS[currentListIndex];
|
|
85
118
|
const currentTasks = mode === 'project-detail' ? projectTasks : tasks[currentTab];
|
|
86
|
-
|
|
119
|
+
// Get all tasks for search (across all statuses)
|
|
120
|
+
const getAllTasks = useCallback(() => {
|
|
121
|
+
const allTasks = [];
|
|
122
|
+
for (const tab of TABS) {
|
|
123
|
+
allTasks.push(...tasks[tab]);
|
|
124
|
+
}
|
|
125
|
+
return allTasks;
|
|
126
|
+
}, [tasks]);
|
|
127
|
+
// Search tasks by query
|
|
128
|
+
const searchTasks = useCallback((query) => {
|
|
129
|
+
if (!query.trim())
|
|
130
|
+
return [];
|
|
131
|
+
const lowerQuery = query.toLowerCase();
|
|
132
|
+
const allTasks = getAllTasks();
|
|
133
|
+
return allTasks.filter(task => task.title.toLowerCase().includes(lowerQuery) ||
|
|
134
|
+
(task.description && task.description.toLowerCase().includes(lowerQuery)));
|
|
135
|
+
}, [getAllTasks]);
|
|
136
|
+
// Handle search query change
|
|
137
|
+
const handleSearchChange = useCallback((value) => {
|
|
138
|
+
setSearchQuery(value);
|
|
139
|
+
const results = searchTasks(value);
|
|
140
|
+
setSearchResults(results);
|
|
141
|
+
setSearchResultIndex(0);
|
|
142
|
+
}, [searchTasks]);
|
|
143
|
+
const addTask = useCallback(async (title, parentId) => {
|
|
87
144
|
if (!title.trim())
|
|
88
145
|
return;
|
|
89
146
|
const db = getDb();
|
|
90
147
|
const now = new Date();
|
|
91
|
-
db.insert(schema.tasks)
|
|
148
|
+
await db.insert(schema.tasks)
|
|
92
149
|
.values({
|
|
93
150
|
id: uuidv4(),
|
|
94
151
|
title: title.trim(),
|
|
@@ -96,37 +153,120 @@ function AppContent() {
|
|
|
96
153
|
parentId: parentId || null,
|
|
97
154
|
createdAt: now,
|
|
98
155
|
updatedAt: now,
|
|
99
|
-
})
|
|
100
|
-
.run();
|
|
156
|
+
});
|
|
101
157
|
setMessage(fmt(i18n.tui.added, { title: title.trim() }));
|
|
102
|
-
loadTasks();
|
|
103
|
-
};
|
|
104
|
-
const
|
|
158
|
+
await loadTasks();
|
|
159
|
+
}, [i18n.tui.added, loadTasks]);
|
|
160
|
+
const addCommentToTask = useCallback(async (task, content) => {
|
|
161
|
+
const db = getDb();
|
|
162
|
+
await db.insert(schema.comments).values({
|
|
163
|
+
id: uuidv4(),
|
|
164
|
+
taskId: task.id,
|
|
165
|
+
content: content.trim(),
|
|
166
|
+
createdAt: new Date(),
|
|
167
|
+
});
|
|
168
|
+
setMessage(i18n.tui.commentAdded || 'Comment added');
|
|
169
|
+
await loadTaskComments(task.id);
|
|
170
|
+
}, [i18n.tui.commentAdded, loadTaskComments]);
|
|
171
|
+
const deleteComment = useCallback(async (comment) => {
|
|
172
|
+
const db = getDb();
|
|
173
|
+
await db.delete(schema.comments).where(eq(schema.comments.id, comment.id));
|
|
174
|
+
setMessage(i18n.tui.commentDeleted || 'Comment deleted');
|
|
175
|
+
if (selectedTask) {
|
|
176
|
+
await loadTaskComments(selectedTask.id);
|
|
177
|
+
}
|
|
178
|
+
}, [i18n.tui.commentDeleted, loadTaskComments, selectedTask]);
|
|
179
|
+
const handleInputSubmit = async (value) => {
|
|
180
|
+
if (mode === 'move-to-waiting' && taskToWaiting) {
|
|
181
|
+
if (value.trim()) {
|
|
182
|
+
await moveTaskToWaiting(taskToWaiting, value);
|
|
183
|
+
}
|
|
184
|
+
setTaskToWaiting(null);
|
|
185
|
+
setMode('normal');
|
|
186
|
+
setInputValue('');
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
// Handle search mode submit
|
|
190
|
+
if (mode === 'search') {
|
|
191
|
+
if (searchResults.length > 0) {
|
|
192
|
+
const task = searchResults[searchResultIndex];
|
|
193
|
+
setSelectedTask(task);
|
|
194
|
+
loadTaskComments(task.id);
|
|
195
|
+
setMode('task-detail');
|
|
196
|
+
}
|
|
197
|
+
else {
|
|
198
|
+
setMode('normal');
|
|
199
|
+
}
|
|
200
|
+
setSearchQuery('');
|
|
201
|
+
setSearchResults([]);
|
|
202
|
+
setSearchResultIndex(0);
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
105
205
|
if (value.trim()) {
|
|
106
|
-
if (mode === 'add-
|
|
107
|
-
|
|
108
|
-
|
|
206
|
+
if (mode === 'add-comment' && selectedTask) {
|
|
207
|
+
await addCommentToTask(selectedTask, value);
|
|
208
|
+
setMode('task-detail');
|
|
209
|
+
}
|
|
210
|
+
else if (mode === 'add-to-project' && selectedProject) {
|
|
211
|
+
await addTask(value, selectedProject.id);
|
|
212
|
+
await loadProjectTasks(selectedProject.id);
|
|
109
213
|
setMode('project-detail');
|
|
110
214
|
}
|
|
111
215
|
else {
|
|
112
|
-
addTask(value);
|
|
216
|
+
await addTask(value);
|
|
113
217
|
setMode('normal');
|
|
114
218
|
}
|
|
115
219
|
}
|
|
116
220
|
else {
|
|
117
|
-
|
|
221
|
+
if (mode === 'add-comment') {
|
|
222
|
+
setMode('task-detail');
|
|
223
|
+
}
|
|
224
|
+
else {
|
|
225
|
+
setMode(mode === 'add-to-project' ? 'project-detail' : 'normal');
|
|
226
|
+
}
|
|
118
227
|
}
|
|
119
228
|
setInputValue('');
|
|
120
229
|
};
|
|
121
|
-
const linkTaskToProject = (task, project) => {
|
|
230
|
+
const linkTaskToProject = useCallback(async (task, project) => {
|
|
122
231
|
const db = getDb();
|
|
123
|
-
db.update(schema.tasks)
|
|
232
|
+
await db.update(schema.tasks)
|
|
124
233
|
.set({ parentId: project.id, updatedAt: new Date() })
|
|
125
|
-
.where(eq(schema.tasks.id, task.id))
|
|
126
|
-
.run();
|
|
234
|
+
.where(eq(schema.tasks.id, task.id));
|
|
127
235
|
setMessage(fmt(i18n.tui.linkedToProject || 'Linked "{title}" to {project}', { title: task.title, project: project.title }));
|
|
128
|
-
loadTasks();
|
|
129
|
-
};
|
|
236
|
+
await loadTasks();
|
|
237
|
+
}, [i18n.tui.linkedToProject, loadTasks]);
|
|
238
|
+
const markTaskDone = useCallback(async (task) => {
|
|
239
|
+
const db = getDb();
|
|
240
|
+
await db.update(schema.tasks)
|
|
241
|
+
.set({ status: 'done', updatedAt: new Date() })
|
|
242
|
+
.where(eq(schema.tasks.id, task.id));
|
|
243
|
+
setMessage(fmt(i18n.tui.completed, { title: task.title }));
|
|
244
|
+
await loadTasks();
|
|
245
|
+
}, [i18n.tui.completed, loadTasks]);
|
|
246
|
+
const moveTaskToStatus = useCallback(async (task, status) => {
|
|
247
|
+
const db = getDb();
|
|
248
|
+
await db.update(schema.tasks)
|
|
249
|
+
.set({ status, waitingFor: null, updatedAt: new Date() })
|
|
250
|
+
.where(eq(schema.tasks.id, task.id));
|
|
251
|
+
setMessage(fmt(i18n.tui.movedTo, { title: task.title, status: i18n.status[status] }));
|
|
252
|
+
await loadTasks();
|
|
253
|
+
}, [i18n.tui.movedTo, i18n.status, loadTasks]);
|
|
254
|
+
const moveTaskToWaiting = useCallback(async (task, waitingFor) => {
|
|
255
|
+
const db = getDb();
|
|
256
|
+
await db.update(schema.tasks)
|
|
257
|
+
.set({ status: 'waiting', waitingFor: waitingFor.trim(), updatedAt: new Date() })
|
|
258
|
+
.where(eq(schema.tasks.id, task.id));
|
|
259
|
+
setMessage(fmt(i18n.tui.movedToWaiting, { title: task.title, person: waitingFor.trim() }));
|
|
260
|
+
await loadTasks();
|
|
261
|
+
}, [i18n.tui.movedToWaiting, loadTasks]);
|
|
262
|
+
const makeTaskProject = useCallback(async (task) => {
|
|
263
|
+
const db = getDb();
|
|
264
|
+
await db.update(schema.tasks)
|
|
265
|
+
.set({ isProject: true, status: 'next', updatedAt: new Date() })
|
|
266
|
+
.where(eq(schema.tasks.id, task.id));
|
|
267
|
+
setMessage(fmt(i18n.tui.madeProject || 'Made project: {title}', { title: task.title }));
|
|
268
|
+
await loadTasks();
|
|
269
|
+
}, [i18n.tui.madeProject, loadTasks]);
|
|
130
270
|
const getTabLabel = (tab) => {
|
|
131
271
|
switch (tab) {
|
|
132
272
|
case 'inbox':
|
|
@@ -139,6 +279,8 @@ function AppContent() {
|
|
|
139
279
|
return i18n.tui.tabSomeday;
|
|
140
280
|
case 'projects':
|
|
141
281
|
return i18n.tui.tabProjects || 'Projects';
|
|
282
|
+
case 'done':
|
|
283
|
+
return i18n.tui.tabDone || 'Done';
|
|
142
284
|
}
|
|
143
285
|
};
|
|
144
286
|
useInput((input, key) => {
|
|
@@ -147,25 +289,111 @@ function AppContent() {
|
|
|
147
289
|
setMode('normal');
|
|
148
290
|
return;
|
|
149
291
|
}
|
|
150
|
-
// Handle help mode -
|
|
292
|
+
// Handle help mode - let HelpModal handle input
|
|
151
293
|
if (mode === 'help') {
|
|
152
|
-
|
|
294
|
+
return;
|
|
295
|
+
}
|
|
296
|
+
// Handle search mode
|
|
297
|
+
if (mode === 'search') {
|
|
298
|
+
if (key.escape) {
|
|
299
|
+
setSearchQuery('');
|
|
300
|
+
setSearchResults([]);
|
|
301
|
+
setSearchResultIndex(0);
|
|
302
|
+
setMode('normal');
|
|
303
|
+
return;
|
|
304
|
+
}
|
|
305
|
+
// Navigate search results with Ctrl+j/k or Ctrl+n/p
|
|
306
|
+
if (key.ctrl && (input === 'j' || input === 'n')) {
|
|
307
|
+
setSearchResultIndex((prev) => prev < searchResults.length - 1 ? prev + 1 : 0);
|
|
308
|
+
return;
|
|
309
|
+
}
|
|
310
|
+
if (key.ctrl && (input === 'k' || input === 'p')) {
|
|
311
|
+
setSearchResultIndex((prev) => prev > 0 ? prev - 1 : Math.max(0, searchResults.length - 1));
|
|
312
|
+
return;
|
|
313
|
+
}
|
|
314
|
+
// Let TextInput handle other keys
|
|
153
315
|
return;
|
|
154
316
|
}
|
|
155
317
|
// Handle add mode
|
|
156
|
-
if (mode === 'add' || mode === 'add-to-project') {
|
|
318
|
+
if (mode === 'add' || mode === 'add-to-project' || mode === 'add-comment' || mode === 'move-to-waiting') {
|
|
157
319
|
if (key.escape) {
|
|
158
320
|
setInputValue('');
|
|
159
|
-
|
|
321
|
+
if (mode === 'move-to-waiting') {
|
|
322
|
+
setTaskToWaiting(null);
|
|
323
|
+
setMode('normal');
|
|
324
|
+
}
|
|
325
|
+
else if (mode === 'add-comment') {
|
|
326
|
+
setMode('task-detail');
|
|
327
|
+
}
|
|
328
|
+
else if (mode === 'add-to-project') {
|
|
329
|
+
setMode('project-detail');
|
|
330
|
+
}
|
|
331
|
+
else {
|
|
332
|
+
setMode('normal');
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
return;
|
|
336
|
+
}
|
|
337
|
+
// Handle task-detail mode
|
|
338
|
+
if (mode === 'task-detail') {
|
|
339
|
+
if (key.escape || key.backspace || input === 'b') {
|
|
340
|
+
// If came from project-detail, go back to project-detail
|
|
341
|
+
if (selectedProject) {
|
|
342
|
+
setMode('project-detail');
|
|
343
|
+
// Find the task index in project tasks
|
|
344
|
+
const taskIndex = projectTasks.findIndex(t => t.id === selectedTask?.id);
|
|
345
|
+
if (taskIndex >= 0) {
|
|
346
|
+
setSelectedTaskIndex(taskIndex);
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
else {
|
|
350
|
+
setMode('normal');
|
|
351
|
+
}
|
|
352
|
+
setSelectedTask(null);
|
|
353
|
+
setTaskComments([]);
|
|
354
|
+
setSelectedCommentIndex(0);
|
|
355
|
+
return;
|
|
356
|
+
}
|
|
357
|
+
// Navigate comments
|
|
358
|
+
if (key.upArrow || input === 'k') {
|
|
359
|
+
setSelectedCommentIndex((prev) => (prev > 0 ? prev - 1 : Math.max(0, taskComments.length - 1)));
|
|
360
|
+
return;
|
|
361
|
+
}
|
|
362
|
+
if (key.downArrow || input === 'j') {
|
|
363
|
+
setSelectedCommentIndex((prev) => (prev < taskComments.length - 1 ? prev + 1 : 0));
|
|
364
|
+
return;
|
|
365
|
+
}
|
|
366
|
+
// Delete comment
|
|
367
|
+
if (input === 'd' && taskComments.length > 0) {
|
|
368
|
+
const comment = taskComments[selectedCommentIndex];
|
|
369
|
+
deleteComment(comment).then(() => {
|
|
370
|
+
if (selectedCommentIndex >= taskComments.length - 1) {
|
|
371
|
+
setSelectedCommentIndex(Math.max(0, selectedCommentIndex - 1));
|
|
372
|
+
}
|
|
373
|
+
});
|
|
374
|
+
return;
|
|
375
|
+
}
|
|
376
|
+
// Add comment
|
|
377
|
+
if (input === 'i') {
|
|
378
|
+
setMode('add-comment');
|
|
379
|
+
return;
|
|
380
|
+
}
|
|
381
|
+
// Link to project (P key)
|
|
382
|
+
if (input === 'P' && tasks.projects.length > 0) {
|
|
383
|
+
setTaskToLink(selectedTask);
|
|
384
|
+
setProjectSelectIndex(0);
|
|
385
|
+
setMode('select-project');
|
|
386
|
+
return;
|
|
160
387
|
}
|
|
161
388
|
return;
|
|
162
389
|
}
|
|
163
390
|
// Handle select-project mode
|
|
164
391
|
if (mode === 'select-project') {
|
|
165
392
|
if (key.escape) {
|
|
393
|
+
const wasFromTaskDetail = selectedTask !== null;
|
|
166
394
|
setTaskToLink(null);
|
|
167
395
|
setProjectSelectIndex(0);
|
|
168
|
-
setMode('normal');
|
|
396
|
+
setMode(wasFromTaskDetail ? 'task-detail' : 'normal');
|
|
169
397
|
return;
|
|
170
398
|
}
|
|
171
399
|
// Navigate projects
|
|
@@ -180,10 +408,11 @@ function AppContent() {
|
|
|
180
408
|
// Select project with Enter
|
|
181
409
|
if (key.return && taskToLink && tasks.projects.length > 0) {
|
|
182
410
|
const project = tasks.projects[projectSelectIndex];
|
|
411
|
+
const wasFromTaskDetail = selectedTask !== null;
|
|
183
412
|
linkTaskToProject(taskToLink, project);
|
|
184
413
|
setTaskToLink(null);
|
|
185
414
|
setProjectSelectIndex(0);
|
|
186
|
-
setMode('normal');
|
|
415
|
+
setMode(wasFromTaskDetail ? 'task-detail' : 'normal');
|
|
187
416
|
return;
|
|
188
417
|
}
|
|
189
418
|
return;
|
|
@@ -214,16 +443,19 @@ function AppContent() {
|
|
|
214
443
|
// Mark child task as done
|
|
215
444
|
if (input === 'd' && projectTasks.length > 0) {
|
|
216
445
|
const task = projectTasks[selectedTaskIndex];
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
446
|
+
markTaskDone(task).then(() => {
|
|
447
|
+
if (selectedProject) {
|
|
448
|
+
loadProjectTasks(selectedProject.id);
|
|
449
|
+
}
|
|
450
|
+
});
|
|
451
|
+
return;
|
|
452
|
+
}
|
|
453
|
+
// Enter to view task details
|
|
454
|
+
if (key.return && projectTasks.length > 0) {
|
|
455
|
+
const task = projectTasks[selectedTaskIndex];
|
|
456
|
+
setSelectedTask(task);
|
|
457
|
+
loadTaskComments(task.id);
|
|
458
|
+
setMode('task-detail');
|
|
227
459
|
return;
|
|
228
460
|
}
|
|
229
461
|
return;
|
|
@@ -247,31 +479,21 @@ function AppContent() {
|
|
|
247
479
|
if ((input === '\x1bOR' || input === '\x1b[13~') && currentTasks.length > 0) {
|
|
248
480
|
// F3 - Done
|
|
249
481
|
const task = currentTasks[selectedTaskIndex];
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
setMessage(fmt(i18n.tui.completed, { title: task.title }));
|
|
256
|
-
loadTasks();
|
|
257
|
-
if (selectedTaskIndex >= currentTasks.length - 1) {
|
|
258
|
-
setSelectedTaskIndex(Math.max(0, selectedTaskIndex - 1));
|
|
259
|
-
}
|
|
482
|
+
markTaskDone(task).then(() => {
|
|
483
|
+
if (selectedTaskIndex >= currentTasks.length - 1) {
|
|
484
|
+
setSelectedTaskIndex(Math.max(0, selectedTaskIndex - 1));
|
|
485
|
+
}
|
|
486
|
+
});
|
|
260
487
|
return;
|
|
261
488
|
}
|
|
262
489
|
if ((input === '\x1bOS' || input === '\x1b[14~') && currentTasks.length > 0 && currentTab !== 'next' && currentTab !== 'projects') {
|
|
263
490
|
// F4 - Move to Next
|
|
264
491
|
const task = currentTasks[selectedTaskIndex];
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
setMessage(fmt(i18n.tui.movedTo, { title: task.title, status: i18n.status.next }));
|
|
271
|
-
loadTasks();
|
|
272
|
-
if (selectedTaskIndex >= currentTasks.length - 1) {
|
|
273
|
-
setSelectedTaskIndex(Math.max(0, selectedTaskIndex - 1));
|
|
274
|
-
}
|
|
492
|
+
moveTaskToStatus(task, 'next').then(() => {
|
|
493
|
+
if (selectedTaskIndex >= currentTasks.length - 1) {
|
|
494
|
+
setSelectedTaskIndex(Math.max(0, selectedTaskIndex - 1));
|
|
495
|
+
}
|
|
496
|
+
});
|
|
275
497
|
return;
|
|
276
498
|
}
|
|
277
499
|
if (input === '\x1b[15~') {
|
|
@@ -290,6 +512,14 @@ function AppContent() {
|
|
|
290
512
|
setMode('help');
|
|
291
513
|
return;
|
|
292
514
|
}
|
|
515
|
+
// Search mode
|
|
516
|
+
if (input === '/') {
|
|
517
|
+
setMode('search');
|
|
518
|
+
setSearchQuery('');
|
|
519
|
+
setSearchResults([]);
|
|
520
|
+
setSearchResultIndex(0);
|
|
521
|
+
return;
|
|
522
|
+
}
|
|
293
523
|
// Quit
|
|
294
524
|
if (input === 'q' || (key.ctrl && input === 'c')) {
|
|
295
525
|
exit();
|
|
@@ -326,6 +556,11 @@ function AppContent() {
|
|
|
326
556
|
setSelectedTaskIndex(0);
|
|
327
557
|
return;
|
|
328
558
|
}
|
|
559
|
+
if (input === '6') {
|
|
560
|
+
setCurrentListIndex(5);
|
|
561
|
+
setSelectedTaskIndex(0);
|
|
562
|
+
return;
|
|
563
|
+
}
|
|
329
564
|
// Navigate between lists
|
|
330
565
|
if (key.leftArrow || input === 'h') {
|
|
331
566
|
setCurrentListIndex((prev) => (prev > 0 ? prev - 1 : TABS.length - 1));
|
|
@@ -355,87 +590,77 @@ function AppContent() {
|
|
|
355
590
|
setSelectedTaskIndex(0);
|
|
356
591
|
return;
|
|
357
592
|
}
|
|
593
|
+
// Enter to view task details (on non-projects tabs)
|
|
594
|
+
if (key.return && currentTab !== 'projects' && currentTasks.length > 0) {
|
|
595
|
+
const task = currentTasks[selectedTaskIndex];
|
|
596
|
+
setSelectedTask(task);
|
|
597
|
+
loadTaskComments(task.id);
|
|
598
|
+
setMode('task-detail');
|
|
599
|
+
return;
|
|
600
|
+
}
|
|
358
601
|
// Mark as project (p key)
|
|
359
|
-
if (input === 'p' && currentTasks.length > 0 && currentTab !== 'projects') {
|
|
602
|
+
if (input === 'p' && currentTasks.length > 0 && currentTab !== 'projects' && currentTab !== 'done') {
|
|
360
603
|
const task = currentTasks[selectedTaskIndex];
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
setMessage(fmt(i18n.tui.madeProject || 'Made project: {title}', { title: task.title }));
|
|
367
|
-
loadTasks();
|
|
368
|
-
if (selectedTaskIndex >= currentTasks.length - 1) {
|
|
369
|
-
setSelectedTaskIndex(Math.max(0, selectedTaskIndex - 1));
|
|
370
|
-
}
|
|
604
|
+
makeTaskProject(task).then(() => {
|
|
605
|
+
if (selectedTaskIndex >= currentTasks.length - 1) {
|
|
606
|
+
setSelectedTaskIndex(Math.max(0, selectedTaskIndex - 1));
|
|
607
|
+
}
|
|
608
|
+
});
|
|
371
609
|
return;
|
|
372
610
|
}
|
|
373
611
|
// Link to project (P key - shift+p)
|
|
374
|
-
if (input === 'P' && currentTasks.length > 0 && currentTab !== 'projects' && tasks.projects.length > 0) {
|
|
612
|
+
if (input === 'P' && currentTasks.length > 0 && currentTab !== 'projects' && currentTab !== 'done' && tasks.projects.length > 0) {
|
|
375
613
|
const task = currentTasks[selectedTaskIndex];
|
|
376
614
|
setTaskToLink(task);
|
|
377
615
|
setProjectSelectIndex(0);
|
|
378
616
|
setMode('select-project');
|
|
379
617
|
return;
|
|
380
618
|
}
|
|
381
|
-
// Mark as done
|
|
382
|
-
if (input === 'd' && currentTasks.length > 0) {
|
|
619
|
+
// Mark as done (not available on done tab)
|
|
620
|
+
if (input === 'd' && currentTasks.length > 0 && currentTab !== 'done') {
|
|
383
621
|
const task = currentTasks[selectedTaskIndex];
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
setMessage(fmt(i18n.tui.completed, { title: task.title }));
|
|
390
|
-
loadTasks();
|
|
391
|
-
if (selectedTaskIndex >= currentTasks.length - 1) {
|
|
392
|
-
setSelectedTaskIndex(Math.max(0, selectedTaskIndex - 1));
|
|
393
|
-
}
|
|
622
|
+
markTaskDone(task).then(() => {
|
|
623
|
+
if (selectedTaskIndex >= currentTasks.length - 1) {
|
|
624
|
+
setSelectedTaskIndex(Math.max(0, selectedTaskIndex - 1));
|
|
625
|
+
}
|
|
626
|
+
});
|
|
394
627
|
return;
|
|
395
628
|
}
|
|
396
629
|
// Move to next actions
|
|
397
|
-
if (input === 'n' && currentTasks.length > 0 && currentTab !== 'next' && currentTab !== 'projects') {
|
|
630
|
+
if (input === 'n' && currentTasks.length > 0 && currentTab !== 'next' && currentTab !== 'projects' && currentTab !== 'done') {
|
|
398
631
|
const task = currentTasks[selectedTaskIndex];
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
setMessage(fmt(i18n.tui.movedTo, { title: task.title, status: i18n.status.next }));
|
|
405
|
-
loadTasks();
|
|
406
|
-
if (selectedTaskIndex >= currentTasks.length - 1) {
|
|
407
|
-
setSelectedTaskIndex(Math.max(0, selectedTaskIndex - 1));
|
|
408
|
-
}
|
|
632
|
+
moveTaskToStatus(task, 'next').then(() => {
|
|
633
|
+
if (selectedTaskIndex >= currentTasks.length - 1) {
|
|
634
|
+
setSelectedTaskIndex(Math.max(0, selectedTaskIndex - 1));
|
|
635
|
+
}
|
|
636
|
+
});
|
|
409
637
|
return;
|
|
410
638
|
}
|
|
411
639
|
// Move to someday
|
|
412
|
-
if (input === 's' && currentTasks.length > 0 && currentTab !== 'someday' && currentTab !== 'projects') {
|
|
640
|
+
if (input === 's' && currentTasks.length > 0 && currentTab !== 'someday' && currentTab !== 'projects' && currentTab !== 'done') {
|
|
413
641
|
const task = currentTasks[selectedTaskIndex];
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
642
|
+
moveTaskToStatus(task, 'someday').then(() => {
|
|
643
|
+
if (selectedTaskIndex >= currentTasks.length - 1) {
|
|
644
|
+
setSelectedTaskIndex(Math.max(0, selectedTaskIndex - 1));
|
|
645
|
+
}
|
|
646
|
+
});
|
|
647
|
+
return;
|
|
648
|
+
}
|
|
649
|
+
// Move to waiting
|
|
650
|
+
if (input === 'w' && currentTasks.length > 0 && currentTab !== 'waiting' && currentTab !== 'projects' && currentTab !== 'done') {
|
|
651
|
+
const task = currentTasks[selectedTaskIndex];
|
|
652
|
+
setTaskToWaiting(task);
|
|
653
|
+
setMode('move-to-waiting');
|
|
424
654
|
return;
|
|
425
655
|
}
|
|
426
656
|
// Move to inbox
|
|
427
|
-
if (input === 'i' && currentTasks.length > 0 && currentTab !== 'inbox' && currentTab !== 'projects') {
|
|
657
|
+
if (input === 'i' && currentTasks.length > 0 && currentTab !== 'inbox' && currentTab !== 'projects' && currentTab !== 'done') {
|
|
428
658
|
const task = currentTasks[selectedTaskIndex];
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
setMessage(fmt(i18n.tui.movedTo, { title: task.title, status: i18n.status.inbox }));
|
|
435
|
-
loadTasks();
|
|
436
|
-
if (selectedTaskIndex >= currentTasks.length - 1) {
|
|
437
|
-
setSelectedTaskIndex(Math.max(0, selectedTaskIndex - 1));
|
|
438
|
-
}
|
|
659
|
+
moveTaskToStatus(task, 'inbox').then(() => {
|
|
660
|
+
if (selectedTaskIndex >= currentTasks.length - 1) {
|
|
661
|
+
setSelectedTaskIndex(Math.max(0, selectedTaskIndex - 1));
|
|
662
|
+
}
|
|
663
|
+
});
|
|
439
664
|
return;
|
|
440
665
|
}
|
|
441
666
|
// Refresh
|
|
@@ -458,15 +683,38 @@ function AppContent() {
|
|
|
458
683
|
const [open, close] = theme.style.tabBrackets;
|
|
459
684
|
return `${open}${label}${close}`;
|
|
460
685
|
};
|
|
461
|
-
|
|
686
|
+
// Turso 接続情報を取得
|
|
687
|
+
const tursoEnabled = isTursoEnabled();
|
|
688
|
+
const tursoHost = tursoEnabled ? (() => {
|
|
689
|
+
const config = getTursoConfig();
|
|
690
|
+
if (config) {
|
|
691
|
+
try {
|
|
692
|
+
return new URL(config.url).host;
|
|
693
|
+
}
|
|
694
|
+
catch {
|
|
695
|
+
return config.url;
|
|
696
|
+
}
|
|
697
|
+
}
|
|
698
|
+
return '';
|
|
699
|
+
})() : '';
|
|
700
|
+
return (_jsxs(Box, { flexDirection: "column", padding: 1, children: [_jsxs(Box, { marginBottom: 1, justifyContent: "space-between", children: [_jsxs(Box, { children: [_jsx(Text, { bold: true, color: theme.colors.primary, children: formatTitle(i18n.tui.title) }), _jsx(Text, { color: theme.colors.textMuted, children: theme.name === 'modern' ? ` v${VERSION}` : ` VER ${VERSION}` }), tursoEnabled && (_jsxs(Text, { color: theme.colors.accent, children: [theme.name === 'modern' ? ' ☁️ ' : ' [SYNC] ', tursoHost] })), !tursoEnabled && (_jsx(Text, { color: theme.colors.textMuted, children: theme.name === 'modern' ? ' 💾 local' : ' [LOCAL]' }))] }), _jsx(Text, { color: theme.colors.textMuted, children: i18n.tui.helpHint })] }), _jsx(Box, { marginBottom: 1, children: TABS.map((tab, index) => {
|
|
462
701
|
const isActive = index === currentListIndex && mode !== 'project-detail';
|
|
463
702
|
const count = tasks[tab].length;
|
|
464
703
|
const label = `${index + 1}:${getTabLabel(tab)}(${count})`;
|
|
465
704
|
return (_jsx(Box, { marginRight: 1, children: _jsx(Text, { color: isActive ? theme.colors.textSelected : theme.colors.textMuted, bold: isActive, inverse: isActive && theme.style.tabActiveInverse, children: formatTabLabel(` ${label} `, isActive) }) }, tab));
|
|
466
|
-
}) }), mode === 'project-detail' && selectedProject && (_jsxs(Box, { marginBottom: 1, children: [_jsxs(Text, { color: theme.colors.accent, bold: true, children: [theme.name === 'modern' ? '📁 ' : '>> ', selectedProject.title] }), _jsxs(Text, { color: theme.colors.textMuted, children: [" (Esc/b: ", i18n.tui.back || 'back', ")"] })] })), _jsx(Box, { flexDirection: "column", borderStyle: theme.borders.list, borderColor: theme.colors.border, paddingX: 1, paddingY: 1, minHeight:
|
|
705
|
+
}) }), mode === 'project-detail' && selectedProject && (_jsxs(_Fragment, { children: [_jsxs(Box, { marginBottom: 1, children: [_jsxs(Text, { color: theme.colors.accent, bold: true, children: [theme.name === 'modern' ? '📁 ' : '>> ', selectedProject.title] }), _jsxs(Text, { color: theme.colors.textMuted, children: [" (Esc/b: ", i18n.tui.back || 'back', ")"] })] }), _jsx(Box, { marginBottom: 1, children: _jsxs(Text, { color: theme.colors.secondary, bold: true, children: [i18n.tui.projectTasks || 'Tasks', " (", projectTasks.length, ")"] }) })] })), (mode === 'task-detail' || mode === 'add-comment') && selectedTask && (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Box, { marginBottom: 1, children: [_jsxs(Text, { color: theme.colors.accent, bold: true, children: [theme.name === 'modern' ? '📋 ' : '>> ', i18n.tui.taskDetailTitle || 'Task Details'] }), _jsxs(Text, { color: theme.colors.textMuted, children: [" (Esc/b: ", i18n.tui.back || 'back', ", ", i18n.tui.commentHint || 'i: add comment', ")"] })] }), _jsxs(Box, { flexDirection: "column", borderStyle: theme.borders.list, borderColor: theme.colors.border, paddingX: 1, paddingY: 1, marginBottom: 1, children: [_jsx(Text, { color: theme.colors.text, bold: true, children: selectedTask.title }), selectedTask.description && (_jsx(Text, { color: theme.colors.textMuted, children: selectedTask.description })), _jsxs(Text, { color: theme.colors.textMuted, children: [i18n.status[selectedTask.status], selectedTask.waitingFor && ` - ${selectedTask.waitingFor}`] })] }), _jsx(Box, { marginBottom: 1, children: _jsxs(Text, { color: theme.colors.secondary, bold: true, children: [i18n.tui.comments || 'Comments', " (", taskComments.length, ")"] }) }), _jsx(Box, { flexDirection: "column", borderStyle: theme.borders.list, borderColor: theme.colors.border, paddingX: 1, paddingY: 1, minHeight: 5, children: taskComments.length === 0 ? (_jsx(Text, { color: theme.colors.textMuted, italic: true, children: i18n.tui.noComments || 'No comments yet' })) : (taskComments.map((comment, index) => {
|
|
706
|
+
const isSelected = index === selectedCommentIndex && mode === 'task-detail';
|
|
707
|
+
return (_jsxs(Box, { flexDirection: "row", marginBottom: 1, children: [_jsx(Text, { color: isSelected ? theme.colors.textSelected : theme.colors.textMuted, children: isSelected ? theme.style.selectedPrefix : theme.style.unselectedPrefix }), _jsxs(Box, { flexDirection: "column", children: [_jsxs(Text, { color: theme.colors.textMuted, children: ["[", comment.createdAt.toLocaleString(), "]"] }), _jsx(Text, { color: isSelected ? theme.colors.textSelected : theme.colors.text, bold: isSelected, children: comment.content })] })] }, comment.id));
|
|
708
|
+
})) }), mode === 'add-comment' && (_jsxs(Box, { marginTop: 1, children: [_jsx(Text, { color: theme.colors.secondary, bold: true, children: i18n.tui.addComment || 'New comment: ' }), _jsx(TextInput, { value: inputValue, onChange: setInputValue, onSubmit: handleInputSubmit, placeholder: "" }), _jsxs(Text, { color: theme.colors.textMuted, children: [" ", i18n.tui.inputHelp] })] }))] })), mode === 'search' && searchQuery && (_jsx(SearchResults, { results: searchResults, selectedIndex: searchResultIndex, query: searchQuery })), mode !== 'task-detail' && mode !== 'add-comment' && mode !== 'search' && (_jsx(Box, { flexDirection: "column", borderStyle: theme.borders.list, borderColor: theme.colors.border, paddingX: 1, paddingY: 1, minHeight: 10, children: currentTasks.length === 0 ? (_jsx(Text, { color: theme.colors.textMuted, italic: true, children: i18n.tui.noTasks })) : (currentTasks.map((task, index) => {
|
|
467
709
|
const parentProject = getParentProject(task.parentId);
|
|
468
|
-
|
|
469
|
-
|
|
710
|
+
const progress = currentTab === 'projects' ? projectProgress[task.id] : undefined;
|
|
711
|
+
return (_jsx(TaskItem, { task: task, isSelected: index === selectedTaskIndex, projectName: parentProject?.title, progress: progress }, task.id));
|
|
712
|
+
})) })), (mode === 'add' || mode === 'add-to-project') && (_jsxs(Box, { marginTop: 1, children: [_jsx(Text, { color: theme.colors.secondary, bold: true, children: mode === 'add-to-project' && selectedProject
|
|
470
713
|
? `${i18n.tui.newTask}[${selectedProject.title}] `
|
|
471
|
-
: i18n.tui.newTask }), _jsx(TextInput, { value: inputValue, onChange: setInputValue, onSubmit: handleInputSubmit, placeholder: i18n.tui.placeholder }), _jsxs(Text, { color: theme.colors.textMuted, children: [" ", i18n.tui.inputHelp] })] })), mode === 'select-project' && taskToLink && (_jsxs(Box, { flexDirection: "column", marginTop: 1, children: [_jsxs(Text, { color: theme.colors.secondary, bold: true, children: [i18n.tui.selectProject || 'Select project for', ": ", taskToLink.title] }), _jsx(Box, { flexDirection: "column", marginTop: 1, borderStyle: theme.borders.list, borderColor: theme.colors.borderActive, paddingX: 1, children: tasks.projects.map((project, index) => (_jsxs(Text, { color: index === projectSelectIndex ? theme.colors.textSelected : theme.colors.text, bold: index === projectSelectIndex, children: [index === projectSelectIndex ? theme.style.selectedPrefix : theme.style.unselectedPrefix, project.title] }, project.id))) }), _jsx(Text, { color: theme.colors.textMuted, children: i18n.tui.selectProjectHelp || 'j/k: select, Enter: confirm, Esc: cancel' })] })), message && mode === 'normal' && (_jsx(Box, { marginTop: 1, children: _jsx(Text, { color: theme.colors.textHighlight, children: message }) })), _jsx(Box, { marginTop: 1, children: theme.style.showFunctionKeys ? (_jsx(FunctionKeyBar, {
|
|
714
|
+
: i18n.tui.newTask }), _jsx(TextInput, { value: inputValue, onChange: setInputValue, onSubmit: handleInputSubmit, placeholder: i18n.tui.placeholder }), _jsxs(Text, { color: theme.colors.textMuted, children: [" ", i18n.tui.inputHelp] })] })), mode === 'move-to-waiting' && taskToWaiting && (_jsxs(Box, { marginTop: 1, children: [_jsx(Text, { color: theme.colors.secondary, bold: true, children: i18n.tui.waitingFor }), _jsx(TextInput, { value: inputValue, onChange: setInputValue, onSubmit: handleInputSubmit, placeholder: "" }), _jsxs(Text, { color: theme.colors.textMuted, children: [" ", i18n.tui.inputHelp] })] })), mode === 'select-project' && taskToLink && (_jsxs(Box, { flexDirection: "column", marginTop: 1, children: [_jsxs(Text, { color: theme.colors.secondary, bold: true, children: [i18n.tui.selectProject || 'Select project for', ": ", taskToLink.title] }), _jsx(Box, { flexDirection: "column", marginTop: 1, borderStyle: theme.borders.list, borderColor: theme.colors.borderActive, paddingX: 1, children: tasks.projects.map((project, index) => (_jsxs(Text, { color: index === projectSelectIndex ? theme.colors.textSelected : theme.colors.text, bold: index === projectSelectIndex, children: [index === projectSelectIndex ? theme.style.selectedPrefix : theme.style.unselectedPrefix, project.title] }, project.id))) }), _jsx(Text, { color: theme.colors.textMuted, children: i18n.tui.selectProjectHelp || 'j/k: select, Enter: confirm, Esc: cancel' })] })), mode === 'search' && (_jsx(SearchBar, { value: searchQuery, onChange: handleSearchChange, onSubmit: handleInputSubmit })), message && mode === 'normal' && (_jsx(Box, { marginTop: 1, children: _jsx(Text, { color: theme.colors.textHighlight, children: message }) })), _jsx(Box, { marginTop: 1, children: (mode === 'task-detail' || mode === 'add-comment') ? (theme.style.showFunctionKeys ? (_jsx(FunctionKeyBar, { keys: [
|
|
715
|
+
{ key: 'i', label: i18n.tui.keyBar.comment },
|
|
716
|
+
{ key: 'd', label: i18n.tui.keyBar.delete },
|
|
717
|
+
{ key: 'P', label: i18n.tui.keyBar.project },
|
|
718
|
+
{ key: 'b', label: i18n.tui.keyBar.back },
|
|
719
|
+
] })) : (_jsx(Text, { color: theme.colors.textMuted, children: i18n.tui.taskDetailFooter }))) : theme.style.showFunctionKeys ? (_jsx(FunctionKeyBar, {})) : (_jsx(Text, { color: theme.colors.textMuted, children: i18n.tui.footer })) })] }));
|
|
472
720
|
}
|