floq 0.2.3 → 0.3.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.
Files changed (36) hide show
  1. package/README.ja.md +4 -0
  2. package/README.md +4 -0
  3. package/dist/i18n/en.d.ts +16 -0
  4. package/dist/i18n/en.js +9 -0
  5. package/dist/i18n/ja.js +9 -0
  6. package/dist/ui/App.js +116 -58
  7. package/dist/ui/SplashScreen.js +1 -1
  8. package/dist/ui/components/HelpModal.js +3 -2
  9. package/dist/ui/components/KanbanBoard.js +100 -40
  10. package/dist/ui/history/HistoryContext.d.ts +29 -0
  11. package/dist/ui/history/HistoryContext.js +44 -0
  12. package/dist/ui/history/HistoryManager.d.ts +56 -0
  13. package/dist/ui/history/HistoryManager.js +137 -0
  14. package/dist/ui/history/commands/ConvertToProjectCommand.d.ts +19 -0
  15. package/dist/ui/history/commands/ConvertToProjectCommand.js +37 -0
  16. package/dist/ui/history/commands/CreateCommentCommand.d.ts +18 -0
  17. package/dist/ui/history/commands/CreateCommentCommand.js +23 -0
  18. package/dist/ui/history/commands/CreateTaskCommand.d.ts +18 -0
  19. package/dist/ui/history/commands/CreateTaskCommand.js +24 -0
  20. package/dist/ui/history/commands/DeleteCommentCommand.d.ts +17 -0
  21. package/dist/ui/history/commands/DeleteCommentCommand.js +26 -0
  22. package/dist/ui/history/commands/DeleteTaskCommand.d.ts +18 -0
  23. package/dist/ui/history/commands/DeleteTaskCommand.js +51 -0
  24. package/dist/ui/history/commands/LinkTaskCommand.d.ts +20 -0
  25. package/dist/ui/history/commands/LinkTaskCommand.js +37 -0
  26. package/dist/ui/history/commands/MoveTaskCommand.d.ts +25 -0
  27. package/dist/ui/history/commands/MoveTaskCommand.js +43 -0
  28. package/dist/ui/history/commands/index.d.ts +7 -0
  29. package/dist/ui/history/commands/index.js +7 -0
  30. package/dist/ui/history/index.d.ts +6 -0
  31. package/dist/ui/history/index.js +8 -0
  32. package/dist/ui/history/types.d.ts +26 -0
  33. package/dist/ui/history/types.js +4 -0
  34. package/dist/ui/history/useHistory.d.ts +24 -0
  35. package/dist/ui/history/useHistory.js +31 -0
  36. package/package.json +1 -1
package/README.ja.md CHANGED
@@ -61,6 +61,8 @@ floq
61
61
  | `Esc/b` | 戻る |
62
62
  | `/` | タスク検索 |
63
63
  | `r` | 更新 |
64
+ | `u` | 元に戻す(Undo) |
65
+ | `Ctrl+r` | やり直し(Redo) |
64
66
  | `?` | ヘルプ |
65
67
  | `q` | 終了 |
66
68
 
@@ -107,6 +109,8 @@ floq
107
109
  | `Enter` | タスク詳細を開く |
108
110
  | `/` | タスク検索 |
109
111
  | `r` | 更新 |
112
+ | `u` | 元に戻す(Undo) |
113
+ | `Ctrl+r` | やり直し(Redo) |
110
114
  | `?` | ヘルプ |
111
115
  | `q` | 終了 |
112
116
 
package/README.md CHANGED
@@ -61,6 +61,8 @@ floq
61
61
  | `Esc/b` | Back |
62
62
  | `/` | Search tasks |
63
63
  | `r` | Refresh |
64
+ | `u` | Undo |
65
+ | `Ctrl+r` | Redo |
64
66
  | `?` | Help |
65
67
  | `q` | Quit |
66
68
 
@@ -107,6 +109,8 @@ floq
107
109
  | `Enter` | Open task detail |
108
110
  | `/` | Search tasks |
109
111
  | `r` | Refresh |
112
+ | `u` | Undo |
113
+ | `Ctrl+r` | Redo |
110
114
  | `?` | Help |
111
115
  | `q` | Quit |
112
116
 
package/dist/i18n/en.d.ts CHANGED
@@ -136,6 +136,8 @@ export declare const en: {
136
136
  other: string;
137
137
  showHelp: string;
138
138
  quit: string;
139
+ undo: string;
140
+ redo: string;
139
141
  closeHint: string;
140
142
  };
141
143
  whatsNew: {
@@ -181,6 +183,12 @@ export declare const en: {
181
183
  deleteConfirm: string;
182
184
  deleted: string;
183
185
  deleteCancelled: string;
186
+ undone: string;
187
+ redone: string;
188
+ nothingToUndo: string;
189
+ nothingToRedo: string;
190
+ undoFailed: string;
191
+ redoFailed: string;
184
192
  comments: string;
185
193
  projectTasks: string;
186
194
  search: {
@@ -289,6 +297,8 @@ export type HelpTranslations = {
289
297
  other: string;
290
298
  showHelp: string;
291
299
  quit: string;
300
+ undo: string;
301
+ redo: string;
292
302
  closeHint: string;
293
303
  };
294
304
  export type WhatsNewTranslations = {
@@ -407,6 +417,12 @@ export type TuiTranslations = {
407
417
  deleteConfirm: string;
408
418
  deleted: string;
409
419
  deleteCancelled: string;
420
+ undone: string;
421
+ redone: string;
422
+ nothingToUndo: string;
423
+ nothingToRedo: string;
424
+ undoFailed: string;
425
+ redoFailed: string;
410
426
  comments: string;
411
427
  projectTasks: string;
412
428
  };
package/dist/i18n/en.js CHANGED
@@ -145,6 +145,8 @@ export const en = {
145
145
  other: 'Other',
146
146
  showHelp: 'Show this help',
147
147
  quit: 'Quit',
148
+ undo: 'Undo',
149
+ redo: 'Redo',
148
150
  closeHint: 'Esc/q: close',
149
151
  },
150
152
  // What's New / Changelog
@@ -192,6 +194,13 @@ export const en = {
192
194
  deleteConfirm: 'Delete "{title}"? (y/n)',
193
195
  deleted: 'Deleted: "{title}"',
194
196
  deleteCancelled: 'Delete cancelled',
197
+ // Undo/Redo
198
+ undone: 'Undone: {action}',
199
+ redone: 'Redone: {action}',
200
+ nothingToUndo: 'Nothing to undo',
201
+ nothingToRedo: 'Nothing to redo',
202
+ undoFailed: 'Undo failed',
203
+ redoFailed: 'Redo failed',
195
204
  comments: 'Comments',
196
205
  projectTasks: 'Tasks',
197
206
  // Search
package/dist/i18n/ja.js CHANGED
@@ -145,6 +145,8 @@ export const ja = {
145
145
  other: 'その他',
146
146
  showHelp: 'このヘルプを表示',
147
147
  quit: '終了',
148
+ undo: '元に戻す',
149
+ redo: 'やり直し',
148
150
  closeHint: 'Esc/q: 閉じる',
149
151
  },
150
152
  // What's New / Changelog
@@ -192,6 +194,13 @@ export const ja = {
192
194
  deleteConfirm: '「{title}」を削除しますか? (y/n)',
193
195
  deleted: '削除しました: 「{title}」',
194
196
  deleteCancelled: '削除をキャンセルしました',
197
+ // Undo/Redo
198
+ undone: '元に戻しました: {action}',
199
+ redone: 'やり直しました: {action}',
200
+ nothingToUndo: '元に戻す操作がありません',
201
+ nothingToRedo: 'やり直す操作がありません',
202
+ undoFailed: '元に戻す操作に失敗しました',
203
+ redoFailed: 'やり直しに失敗しました',
195
204
  comments: 'コメント',
196
205
  projectTasks: 'タスク一覧',
197
206
  // Search
package/dist/ui/App.js CHANGED
@@ -19,6 +19,7 @@ import { ThemeProvider, useTheme } from './theme/index.js';
19
19
  import { getThemeName, getViewMode, setThemeName, setViewMode, setLocale, isTursoEnabled } from '../config.js';
20
20
  import { KanbanBoard } from './components/KanbanBoard.js';
21
21
  import { VERSION } from '../version.js';
22
+ import { HistoryProvider, useHistory, CreateTaskCommand, DeleteTaskCommand, MoveTaskCommand, LinkTaskCommand, ConvertToProjectCommand, CreateCommentCommand, DeleteCommentCommand, } from './history/index.js';
22
23
  const TABS = ['inbox', 'next', 'waiting', 'someday', 'projects', 'done'];
23
24
  export function App() {
24
25
  const [themeName, setThemeNameState] = useState(getThemeName);
@@ -53,11 +54,12 @@ export function App() {
53
54
  if (settingsMode === 'lang-select') {
54
55
  return (_jsx(ThemeProvider, { themeName: themeName, children: _jsx(LanguageSelector, { onSelect: handleLocaleSelect, onCancel: handleSettingsCancel }) }));
55
56
  }
56
- return (_jsx(ThemeProvider, { themeName: themeName, children: viewMode === 'kanban' ? (_jsx(KanbanBoard, { onOpenSettings: setSettingsMode })) : (_jsx(AppContent, { onOpenSettings: setSettingsMode })) }));
57
+ return (_jsx(ThemeProvider, { themeName: themeName, children: _jsx(HistoryProvider, { children: viewMode === 'kanban' ? (_jsx(KanbanBoard, { onOpenSettings: setSettingsMode })) : (_jsx(AppContent, { onOpenSettings: setSettingsMode })) }) }));
57
58
  }
58
59
  function AppContent({ onOpenSettings }) {
59
60
  const theme = useTheme();
60
61
  const { exit } = useApp();
62
+ const history = useHistory();
61
63
  const [mode, setMode] = useState('splash');
62
64
  const [inputValue, setInputValue] = useState('');
63
65
  const [currentListIndex, setCurrentListIndex] = useState(0);
@@ -189,39 +191,49 @@ function AppContent({ onOpenSettings }) {
189
191
  const addTask = useCallback(async (title, parentId) => {
190
192
  if (!title.trim())
191
193
  return;
192
- const db = getDb();
193
194
  const now = new Date();
194
- await db.insert(schema.tasks)
195
- .values({
196
- id: uuidv4(),
197
- title: title.trim(),
198
- status: parentId ? 'next' : 'inbox',
199
- parentId: parentId || null,
200
- createdAt: now,
201
- updatedAt: now,
195
+ const taskId = uuidv4();
196
+ const command = new CreateTaskCommand({
197
+ task: {
198
+ id: taskId,
199
+ title: title.trim(),
200
+ status: parentId ? 'next' : 'inbox',
201
+ parentId: parentId || null,
202
+ createdAt: now,
203
+ updatedAt: now,
204
+ },
205
+ description: fmt(i18n.tui.added, { title: title.trim() }),
202
206
  });
207
+ await history.execute(command);
203
208
  setMessage(fmt(i18n.tui.added, { title: title.trim() }));
204
209
  await loadTasks();
205
- }, [i18n.tui.added, loadTasks]);
210
+ }, [i18n.tui.added, loadTasks, history]);
206
211
  const addCommentToTask = useCallback(async (task, content) => {
207
- const db = getDb();
208
- await db.insert(schema.comments).values({
209
- id: uuidv4(),
210
- taskId: task.id,
211
- content: content.trim(),
212
- createdAt: new Date(),
212
+ const commentId = uuidv4();
213
+ const command = new CreateCommentCommand({
214
+ comment: {
215
+ id: commentId,
216
+ taskId: task.id,
217
+ content: content.trim(),
218
+ createdAt: new Date(),
219
+ },
220
+ description: i18n.tui.commentAdded || 'Comment added',
213
221
  });
222
+ await history.execute(command);
214
223
  setMessage(i18n.tui.commentAdded || 'Comment added');
215
224
  await loadTaskComments(task.id);
216
- }, [i18n.tui.commentAdded, loadTaskComments]);
225
+ }, [i18n.tui.commentAdded, loadTaskComments, history]);
217
226
  const deleteComment = useCallback(async (comment) => {
218
- const db = getDb();
219
- await db.delete(schema.comments).where(eq(schema.comments.id, comment.id));
227
+ const command = new DeleteCommentCommand({
228
+ comment,
229
+ description: i18n.tui.commentDeleted || 'Comment deleted',
230
+ });
231
+ await history.execute(command);
220
232
  setMessage(i18n.tui.commentDeleted || 'Comment deleted');
221
233
  if (selectedTask) {
222
234
  await loadTaskComments(selectedTask.id);
223
235
  }
224
- }, [i18n.tui.commentDeleted, loadTaskComments, selectedTask]);
236
+ }, [i18n.tui.commentDeleted, loadTaskComments, selectedTask, history]);
225
237
  const handleInputSubmit = async (value) => {
226
238
  if (mode === 'move-to-waiting' && taskToWaiting) {
227
239
  if (value.trim()) {
@@ -272,54 +284,74 @@ function AppContent({ onOpenSettings }) {
272
284
  setInputValue('');
273
285
  };
274
286
  const linkTaskToProject = useCallback(async (task, project) => {
275
- const db = getDb();
276
- await db.update(schema.tasks)
277
- .set({ parentId: project.id, updatedAt: new Date() })
278
- .where(eq(schema.tasks.id, task.id));
287
+ const command = new LinkTaskCommand({
288
+ taskId: task.id,
289
+ fromParentId: task.parentId,
290
+ toParentId: project.id,
291
+ description: fmt(i18n.tui.linkedToProject || 'Linked "{title}" to {project}', { title: task.title, project: project.title }),
292
+ });
293
+ await history.execute(command);
279
294
  setMessage(fmt(i18n.tui.linkedToProject || 'Linked "{title}" to {project}', { title: task.title, project: project.title }));
280
295
  await loadTasks();
281
- }, [i18n.tui.linkedToProject, loadTasks]);
296
+ }, [i18n.tui.linkedToProject, loadTasks, history]);
282
297
  const markTaskDone = useCallback(async (task) => {
283
- const db = getDb();
284
- await db.update(schema.tasks)
285
- .set({ status: 'done', updatedAt: new Date() })
286
- .where(eq(schema.tasks.id, task.id));
298
+ const command = new MoveTaskCommand({
299
+ taskId: task.id,
300
+ fromStatus: task.status,
301
+ toStatus: 'done',
302
+ fromWaitingFor: task.waitingFor,
303
+ toWaitingFor: null,
304
+ description: fmt(i18n.tui.completed, { title: task.title }),
305
+ });
306
+ await history.execute(command);
287
307
  setMessage(fmt(i18n.tui.completed, { title: task.title }));
288
308
  await loadTasks();
289
- }, [i18n.tui.completed, loadTasks]);
309
+ }, [i18n.tui.completed, loadTasks, history]);
290
310
  const moveTaskToStatus = useCallback(async (task, status) => {
291
- const db = getDb();
292
- await db.update(schema.tasks)
293
- .set({ status, waitingFor: null, updatedAt: new Date() })
294
- .where(eq(schema.tasks.id, task.id));
311
+ const command = new MoveTaskCommand({
312
+ taskId: task.id,
313
+ fromStatus: task.status,
314
+ toStatus: status,
315
+ fromWaitingFor: task.waitingFor,
316
+ toWaitingFor: null,
317
+ description: fmt(i18n.tui.movedTo, { title: task.title, status: i18n.status[status] }),
318
+ });
319
+ await history.execute(command);
295
320
  setMessage(fmt(i18n.tui.movedTo, { title: task.title, status: i18n.status[status] }));
296
321
  await loadTasks();
297
- }, [i18n.tui.movedTo, i18n.status, loadTasks]);
322
+ }, [i18n.tui.movedTo, i18n.status, loadTasks, history]);
298
323
  const moveTaskToWaiting = useCallback(async (task, waitingFor) => {
299
- const db = getDb();
300
- await db.update(schema.tasks)
301
- .set({ status: 'waiting', waitingFor: waitingFor.trim(), updatedAt: new Date() })
302
- .where(eq(schema.tasks.id, task.id));
324
+ const command = new MoveTaskCommand({
325
+ taskId: task.id,
326
+ fromStatus: task.status,
327
+ toStatus: 'waiting',
328
+ fromWaitingFor: task.waitingFor,
329
+ toWaitingFor: waitingFor.trim(),
330
+ description: fmt(i18n.tui.movedToWaiting, { title: task.title, person: waitingFor.trim() }),
331
+ });
332
+ await history.execute(command);
303
333
  setMessage(fmt(i18n.tui.movedToWaiting, { title: task.title, person: waitingFor.trim() }));
304
334
  await loadTasks();
305
- }, [i18n.tui.movedToWaiting, loadTasks]);
335
+ }, [i18n.tui.movedToWaiting, loadTasks, history]);
306
336
  const makeTaskProject = useCallback(async (task) => {
307
- const db = getDb();
308
- await db.update(schema.tasks)
309
- .set({ isProject: true, status: 'next', updatedAt: new Date() })
310
- .where(eq(schema.tasks.id, task.id));
337
+ const command = new ConvertToProjectCommand({
338
+ taskId: task.id,
339
+ originalStatus: task.status,
340
+ description: fmt(i18n.tui.madeProject || 'Made project: {title}', { title: task.title }),
341
+ });
342
+ await history.execute(command);
311
343
  setMessage(fmt(i18n.tui.madeProject || 'Made project: {title}', { title: task.title }));
312
344
  await loadTasks();
313
- }, [i18n.tui.madeProject, loadTasks]);
345
+ }, [i18n.tui.madeProject, loadTasks, history]);
314
346
  const deleteTask = useCallback(async (task) => {
315
- const db = getDb();
316
- // Delete comments first
317
- await db.delete(schema.comments).where(eq(schema.comments.taskId, task.id));
318
- // Delete the task
319
- await db.delete(schema.tasks).where(eq(schema.tasks.id, task.id));
347
+ const command = new DeleteTaskCommand({
348
+ task,
349
+ description: fmt(i18n.tui.deleted || 'Deleted: "{title}"', { title: task.title }),
350
+ });
351
+ await history.execute(command);
320
352
  setMessage(fmt(i18n.tui.deleted || 'Deleted: "{title}"', { title: task.title }));
321
353
  await loadTasks();
322
- }, [i18n.tui.deleted, loadTasks]);
354
+ }, [i18n.tui.deleted, loadTasks, history]);
323
355
  const getTabLabel = (tab) => {
324
356
  switch (tab) {
325
357
  case 'inbox':
@@ -342,10 +374,6 @@ function AppContent({ onOpenSettings }) {
342
374
  setMode('normal');
343
375
  return;
344
376
  }
345
- // Handle help mode - let HelpModal handle input
346
- if (mode === 'help') {
347
- return;
348
- }
349
377
  // Handle search mode
350
378
  if (mode === 'search') {
351
379
  if (key.escape) {
@@ -760,12 +788,42 @@ function AppContent({ onOpenSettings }) {
760
788
  return;
761
789
  }
762
790
  // Refresh
763
- if (input === 'r') {
791
+ if (input === 'r' && !(key.ctrl)) {
764
792
  loadTasks();
765
793
  setMessage(i18n.tui.refreshed);
766
794
  return;
767
795
  }
768
- });
796
+ // Undo (u key) - only in normal mode
797
+ if (input === 'u' && mode === 'normal') {
798
+ history.undo().then((didUndo) => {
799
+ if (didUndo) {
800
+ setMessage(fmt(i18n.tui.undone, { action: history.undoDescription || '' }));
801
+ loadTasks();
802
+ }
803
+ else {
804
+ setMessage(i18n.tui.nothingToUndo);
805
+ }
806
+ }).catch(() => {
807
+ setMessage(i18n.tui.undoFailed);
808
+ });
809
+ return;
810
+ }
811
+ // Redo (Ctrl+r) - only in normal mode
812
+ if (key.ctrl && input === 'r' && mode === 'normal') {
813
+ history.redo().then((didRedo) => {
814
+ if (didRedo) {
815
+ setMessage(fmt(i18n.tui.redone, { action: history.redoDescription || '' }));
816
+ loadTasks();
817
+ }
818
+ else {
819
+ setMessage(i18n.tui.nothingToRedo);
820
+ }
821
+ }).catch(() => {
822
+ setMessage(i18n.tui.redoFailed);
823
+ });
824
+ return;
825
+ }
826
+ }, { isActive: mode !== 'help' });
769
827
  // Splash screen
770
828
  if (mode === 'splash') {
771
829
  return _jsx(SplashScreen, { onComplete: () => setMode('normal') });
@@ -57,5 +57,5 @@ export function SplashScreen({ onComplete, duration = 1500 }) {
57
57
  const visibleLines = Math.min(Math.floor(frame * logoLines.length / 10), logoLines.length);
58
58
  return (_jsxs(Box, { flexDirection: "column", alignItems: "center", justifyContent: "center", padding: 2, children: [_jsx(Box, { flexDirection: "column", alignItems: "center", children: logoLines.slice(0, visibleLines).map((line, index) => (_jsx(Text, { color: theme.colors.secondary, bold: true, children: line }, index))) }), showTagline && (_jsx(Box, { marginTop: 1, children: _jsx(Text, { color: theme.colors.textMuted, italic: !isDosStyle, children: isDosStyle ? `[ ${TAGLINE.toUpperCase()} ]` : TAGLINE }) })), _jsx(Box, { marginTop: 2, children: _jsx(Text, { color: theme.colors.primary, children: frame < 10
59
59
  ? filled.repeat(frame) + empty.repeat(10 - frame)
60
- : filled.repeat(10) }) }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { color: theme.colors.textMuted, dimColor: !isDosStyle, children: isDosStyle ? `VER ${VERSION}` : `v${VERSION}` }) })] }));
60
+ : filled.repeat(10) }) }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { color: isDosStyle ? theme.colors.textMuted : theme.colors.muted, children: isDosStyle ? `VER ${VERSION}` : `v${VERSION}` }) })] }));
61
61
  }
@@ -87,6 +87,7 @@ export function HelpModal({ onClose, isKanban = false }) {
87
87
  // Close modal
88
88
  if (key.escape || key.return || input === 'q' || input === ' ') {
89
89
  onClose();
90
+ return;
90
91
  }
91
92
  });
92
93
  const formatTitle = (title) => theme.style.headerUppercase ? title.toUpperCase() : title;
@@ -99,14 +100,14 @@ function GTDKeybindingsContent() {
99
100
  const help = i18n.tui.help;
100
101
  const theme = useTheme();
101
102
  const formatTitle = (title) => theme.style.headerUppercase ? title.toUpperCase() : title;
102
- return (_jsxs(_Fragment, { children: [_jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [_jsx(Text, { bold: true, color: theme.colors.accent, children: formatTitle(help.navigation) }), _jsxs(Box, { paddingLeft: 2, flexDirection: "column", children: [_jsxs(Text, { color: theme.colors.text, children: [_jsx(Text, { color: theme.colors.textHighlight, children: "1-6" }), " ", help.tabSwitch] }), _jsxs(Text, { color: theme.colors.text, children: [_jsx(Text, { color: theme.colors.textHighlight, children: "h/l \u2190/\u2192" }), " ", help.prevNextTab] }), _jsxs(Text, { color: theme.colors.text, children: [_jsx(Text, { color: theme.colors.textHighlight, children: "j/k \u2191/\u2193" }), " ", help.taskSelect] })] })] }), _jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [_jsx(Text, { bold: true, color: theme.colors.accent, children: formatTitle(help.actions) }), _jsxs(Box, { paddingLeft: 2, flexDirection: "column", children: [_jsxs(Text, { color: theme.colors.text, children: [_jsx(Text, { color: theme.colors.textHighlight, children: "a" }), " ", help.addTask] }), _jsxs(Text, { color: theme.colors.text, children: [_jsx(Text, { color: theme.colors.textHighlight, children: "d" }), " ", help.completeTask] }), _jsxs(Text, { color: theme.colors.text, children: [_jsx(Text, { color: theme.colors.textHighlight, children: "n" }), " ", help.moveToNext] }), _jsxs(Text, { color: theme.colors.text, children: [_jsx(Text, { color: theme.colors.textHighlight, children: "s" }), " ", help.moveToSomeday] }), _jsxs(Text, { color: theme.colors.text, children: [_jsx(Text, { color: theme.colors.textHighlight, children: "w" }), " ", help.moveToWaiting] }), _jsxs(Text, { color: theme.colors.text, children: [_jsx(Text, { color: theme.colors.textHighlight, children: "i" }), " ", help.moveToInbox] }), _jsxs(Text, { color: theme.colors.text, children: [_jsx(Text, { color: theme.colors.textHighlight, children: "r" }), " ", help.refresh] })] })] }), _jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [_jsx(Text, { bold: true, color: theme.colors.accent, children: formatTitle(help.projects) }), _jsxs(Box, { paddingLeft: 2, flexDirection: "column", children: [_jsxs(Text, { color: theme.colors.text, children: [_jsx(Text, { color: theme.colors.textHighlight, children: "p" }), " ", help.makeProject] }), _jsxs(Text, { color: theme.colors.text, children: [_jsx(Text, { color: theme.colors.textHighlight, children: "P" }), " ", help.linkToProject] }), _jsxs(Text, { color: theme.colors.text, children: [_jsx(Text, { color: theme.colors.textHighlight, children: "Enter" }), " ", help.openProject] }), _jsxs(Text, { color: theme.colors.text, children: [_jsx(Text, { color: theme.colors.textHighlight, children: "Esc/b" }), " ", help.backFromProject] })] })] }), _jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [_jsx(Text, { bold: true, color: theme.colors.accent, children: formatTitle(help.settings) }), _jsxs(Box, { paddingLeft: 2, flexDirection: "column", children: [_jsxs(Text, { color: theme.colors.text, children: [_jsx(Text, { color: theme.colors.textHighlight, children: "T" }), " ", help.changeTheme] }), _jsxs(Text, { color: theme.colors.text, children: [_jsx(Text, { color: theme.colors.textHighlight, children: "V" }), " ", help.changeViewMode] }), _jsxs(Text, { color: theme.colors.text, children: [_jsx(Text, { color: theme.colors.textHighlight, children: "L" }), " ", help.changeLanguage] })] })] }), _jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [_jsx(Text, { bold: true, color: theme.colors.accent, children: formatTitle(help.other) }), _jsxs(Box, { paddingLeft: 2, flexDirection: "column", children: [_jsxs(Text, { color: theme.colors.text, children: [_jsx(Text, { color: theme.colors.textHighlight, children: "/" }), " ", help.searchTasks] }), _jsxs(Text, { color: theme.colors.text, children: [_jsx(Text, { color: theme.colors.textHighlight, children: "?" }), " ", help.showHelp] }), _jsxs(Text, { color: theme.colors.text, children: [_jsx(Text, { color: theme.colors.textHighlight, children: "q" }), " ", help.quit] })] })] })] }));
103
+ return (_jsxs(_Fragment, { children: [_jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [_jsx(Text, { bold: true, color: theme.colors.accent, children: formatTitle(help.navigation) }), _jsxs(Box, { paddingLeft: 2, flexDirection: "column", children: [_jsxs(Text, { color: theme.colors.text, children: [_jsx(Text, { color: theme.colors.textHighlight, children: "1-6" }), " ", help.tabSwitch] }), _jsxs(Text, { color: theme.colors.text, children: [_jsx(Text, { color: theme.colors.textHighlight, children: "h/l \u2190/\u2192" }), " ", help.prevNextTab] }), _jsxs(Text, { color: theme.colors.text, children: [_jsx(Text, { color: theme.colors.textHighlight, children: "j/k \u2191/\u2193" }), " ", help.taskSelect] })] })] }), _jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [_jsx(Text, { bold: true, color: theme.colors.accent, children: formatTitle(help.actions) }), _jsxs(Box, { paddingLeft: 2, flexDirection: "column", children: [_jsxs(Text, { color: theme.colors.text, children: [_jsx(Text, { color: theme.colors.textHighlight, children: "a" }), " ", help.addTask] }), _jsxs(Text, { color: theme.colors.text, children: [_jsx(Text, { color: theme.colors.textHighlight, children: "d" }), " ", help.completeTask] }), _jsxs(Text, { color: theme.colors.text, children: [_jsx(Text, { color: theme.colors.textHighlight, children: "n" }), " ", help.moveToNext] }), _jsxs(Text, { color: theme.colors.text, children: [_jsx(Text, { color: theme.colors.textHighlight, children: "s" }), " ", help.moveToSomeday] }), _jsxs(Text, { color: theme.colors.text, children: [_jsx(Text, { color: theme.colors.textHighlight, children: "w" }), " ", help.moveToWaiting] }), _jsxs(Text, { color: theme.colors.text, children: [_jsx(Text, { color: theme.colors.textHighlight, children: "i" }), " ", help.moveToInbox] }), _jsxs(Text, { color: theme.colors.text, children: [_jsx(Text, { color: theme.colors.textHighlight, children: "r" }), " ", help.refresh] }), _jsxs(Text, { color: theme.colors.text, children: [_jsx(Text, { color: theme.colors.textHighlight, children: "u" }), " ", help.undo] }), _jsxs(Text, { color: theme.colors.text, children: [_jsx(Text, { color: theme.colors.textHighlight, children: "Ctrl+r" }), " ", help.redo] })] })] }), _jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [_jsx(Text, { bold: true, color: theme.colors.accent, children: formatTitle(help.projects) }), _jsxs(Box, { paddingLeft: 2, flexDirection: "column", children: [_jsxs(Text, { color: theme.colors.text, children: [_jsx(Text, { color: theme.colors.textHighlight, children: "p" }), " ", help.makeProject] }), _jsxs(Text, { color: theme.colors.text, children: [_jsx(Text, { color: theme.colors.textHighlight, children: "P" }), " ", help.linkToProject] }), _jsxs(Text, { color: theme.colors.text, children: [_jsx(Text, { color: theme.colors.textHighlight, children: "Enter" }), " ", help.openProject] }), _jsxs(Text, { color: theme.colors.text, children: [_jsx(Text, { color: theme.colors.textHighlight, children: "Esc/b" }), " ", help.backFromProject] })] })] }), _jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [_jsx(Text, { bold: true, color: theme.colors.accent, children: formatTitle(help.settings) }), _jsxs(Box, { paddingLeft: 2, flexDirection: "column", children: [_jsxs(Text, { color: theme.colors.text, children: [_jsx(Text, { color: theme.colors.textHighlight, children: "T" }), " ", help.changeTheme] }), _jsxs(Text, { color: theme.colors.text, children: [_jsx(Text, { color: theme.colors.textHighlight, children: "V" }), " ", help.changeViewMode] }), _jsxs(Text, { color: theme.colors.text, children: [_jsx(Text, { color: theme.colors.textHighlight, children: "L" }), " ", help.changeLanguage] })] })] }), _jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [_jsx(Text, { bold: true, color: theme.colors.accent, children: formatTitle(help.other) }), _jsxs(Box, { paddingLeft: 2, flexDirection: "column", children: [_jsxs(Text, { color: theme.colors.text, children: [_jsx(Text, { color: theme.colors.textHighlight, children: "/" }), " ", help.searchTasks] }), _jsxs(Text, { color: theme.colors.text, children: [_jsx(Text, { color: theme.colors.textHighlight, children: "?" }), " ", help.showHelp] }), _jsxs(Text, { color: theme.colors.text, children: [_jsx(Text, { color: theme.colors.textHighlight, children: "q" }), " ", help.quit] })] })] })] }));
103
104
  }
104
105
  function KanbanKeybindingsContent() {
105
106
  const i18n = t();
106
107
  const help = i18n.tui.kanbanHelp;
107
108
  const theme = useTheme();
108
109
  const formatTitle = (title) => theme.style.headerUppercase ? title.toUpperCase() : title;
109
- return (_jsxs(_Fragment, { children: [_jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [_jsx(Text, { bold: true, color: theme.colors.accent, children: formatTitle(help.navigation) }), _jsxs(Box, { paddingLeft: 2, flexDirection: "column", children: [_jsxs(Text, { color: theme.colors.text, children: [_jsx(Text, { color: theme.colors.textHighlight, children: "h/l \u2190/\u2192" }), " ", help.columnSwitch] }), _jsxs(Text, { color: theme.colors.text, children: [_jsx(Text, { color: theme.colors.textHighlight, children: "1-3" }), " ", help.columnDirect] }), _jsxs(Text, { color: theme.colors.text, children: [_jsx(Text, { color: theme.colors.textHighlight, children: "j/k \u2191/\u2193" }), " ", help.taskSelect] })] })] }), _jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [_jsx(Text, { bold: true, color: theme.colors.accent, children: formatTitle(help.actions) }), _jsxs(Box, { paddingLeft: 2, flexDirection: "column", children: [_jsxs(Text, { color: theme.colors.text, children: [_jsx(Text, { color: theme.colors.textHighlight, children: "a" }), " ", help.addTask] }), _jsxs(Text, { color: theme.colors.text, children: [_jsx(Text, { color: theme.colors.textHighlight, children: "d" }), " ", help.completeTask] }), _jsxs(Text, { color: theme.colors.text, children: [_jsx(Text, { color: theme.colors.textHighlight, children: "Enter" }), " ", help.moveRight] }), _jsxs(Text, { color: theme.colors.text, children: [_jsx(Text, { color: theme.colors.textHighlight, children: "BS" }), " ", help.moveLeft] })] })] }), _jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [_jsx(Text, { bold: true, color: theme.colors.accent, children: formatTitle(help.settings) }), _jsxs(Box, { paddingLeft: 2, flexDirection: "column", children: [_jsxs(Text, { color: theme.colors.text, children: [_jsx(Text, { color: theme.colors.textHighlight, children: "T" }), " ", help.changeTheme] }), _jsxs(Text, { color: theme.colors.text, children: [_jsx(Text, { color: theme.colors.textHighlight, children: "V" }), " ", help.changeViewMode] }), _jsxs(Text, { color: theme.colors.text, children: [_jsx(Text, { color: theme.colors.textHighlight, children: "L" }), " ", help.changeLanguage] })] })] }), _jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [_jsx(Text, { bold: true, color: theme.colors.accent, children: formatTitle(help.other) }), _jsxs(Box, { paddingLeft: 2, flexDirection: "column", children: [_jsxs(Text, { color: theme.colors.text, children: [_jsx(Text, { color: theme.colors.textHighlight, children: "/" }), " ", help.searchTasks] }), _jsxs(Text, { color: theme.colors.text, children: [_jsx(Text, { color: theme.colors.textHighlight, children: "?" }), " ", help.showHelp] }), _jsxs(Text, { color: theme.colors.text, children: [_jsx(Text, { color: theme.colors.textHighlight, children: "q" }), " ", help.quit] })] })] })] }));
110
+ return (_jsxs(_Fragment, { children: [_jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [_jsx(Text, { bold: true, color: theme.colors.accent, children: formatTitle(help.navigation) }), _jsxs(Box, { paddingLeft: 2, flexDirection: "column", children: [_jsxs(Text, { color: theme.colors.text, children: [_jsx(Text, { color: theme.colors.textHighlight, children: "h/l \u2190/\u2192" }), " ", help.columnSwitch] }), _jsxs(Text, { color: theme.colors.text, children: [_jsx(Text, { color: theme.colors.textHighlight, children: "1-3" }), " ", help.columnDirect] }), _jsxs(Text, { color: theme.colors.text, children: [_jsx(Text, { color: theme.colors.textHighlight, children: "j/k \u2191/\u2193" }), " ", help.taskSelect] })] })] }), _jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [_jsx(Text, { bold: true, color: theme.colors.accent, children: formatTitle(help.actions) }), _jsxs(Box, { paddingLeft: 2, flexDirection: "column", children: [_jsxs(Text, { color: theme.colors.text, children: [_jsx(Text, { color: theme.colors.textHighlight, children: "a" }), " ", help.addTask] }), _jsxs(Text, { color: theme.colors.text, children: [_jsx(Text, { color: theme.colors.textHighlight, children: "d" }), " ", help.completeTask] }), _jsxs(Text, { color: theme.colors.text, children: [_jsx(Text, { color: theme.colors.textHighlight, children: "Enter" }), " ", help.moveRight] }), _jsxs(Text, { color: theme.colors.text, children: [_jsx(Text, { color: theme.colors.textHighlight, children: "BS" }), " ", help.moveLeft] }), _jsxs(Text, { color: theme.colors.text, children: [_jsx(Text, { color: theme.colors.textHighlight, children: "u" }), " Undo"] }), _jsxs(Text, { color: theme.colors.text, children: [_jsx(Text, { color: theme.colors.textHighlight, children: "Ctrl+r" }), " Redo"] })] })] }), _jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [_jsx(Text, { bold: true, color: theme.colors.accent, children: formatTitle(help.settings) }), _jsxs(Box, { paddingLeft: 2, flexDirection: "column", children: [_jsxs(Text, { color: theme.colors.text, children: [_jsx(Text, { color: theme.colors.textHighlight, children: "T" }), " ", help.changeTheme] }), _jsxs(Text, { color: theme.colors.text, children: [_jsx(Text, { color: theme.colors.textHighlight, children: "V" }), " ", help.changeViewMode] }), _jsxs(Text, { color: theme.colors.text, children: [_jsx(Text, { color: theme.colors.textHighlight, children: "L" }), " ", help.changeLanguage] })] })] }), _jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [_jsx(Text, { bold: true, color: theme.colors.accent, children: formatTitle(help.other) }), _jsxs(Box, { paddingLeft: 2, flexDirection: "column", children: [_jsxs(Text, { color: theme.colors.text, children: [_jsx(Text, { color: theme.colors.textHighlight, children: "/" }), " ", help.searchTasks] }), _jsxs(Text, { color: theme.colors.text, children: [_jsx(Text, { color: theme.colors.textHighlight, children: "?" }), " ", help.showHelp] }), _jsxs(Text, { color: theme.colors.text, children: [_jsx(Text, { color: theme.colors.textHighlight, children: "q" }), " ", help.quit] })] })] })] }));
110
111
  }
111
112
  function InfoContent() {
112
113
  const i18n = t();