floq 0.2.2 → 0.2.3
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 +9 -0
- package/README.md +9 -0
- package/dist/i18n/en.js +1 -1
- package/dist/i18n/ja.js +1 -1
- package/dist/ui/App.js +16 -6
- package/dist/ui/components/KanbanBoard.js +28 -6
- package/dist/ui/components/SearchResults.js +2 -2
- package/package.json +1 -1
package/README.ja.md
CHANGED
|
@@ -64,6 +64,15 @@ floq
|
|
|
64
64
|
| `?` | ヘルプ |
|
|
65
65
|
| `q` | 終了 |
|
|
66
66
|
|
|
67
|
+
#### 検索
|
|
68
|
+
|
|
69
|
+
| キー | アクション |
|
|
70
|
+
|------|-----------|
|
|
71
|
+
| `/` | 検索モード開始 |
|
|
72
|
+
| `↑/↓` または `Ctrl+j/k` | 検索結果をナビゲート |
|
|
73
|
+
| `Enter` | 選択したタスクのタブに移動して選択 |
|
|
74
|
+
| `Esc` | キャンセル |
|
|
75
|
+
|
|
67
76
|
#### プロジェクト詳細画面
|
|
68
77
|
|
|
69
78
|
| キー | アクション |
|
package/README.md
CHANGED
|
@@ -64,6 +64,15 @@ floq
|
|
|
64
64
|
| `?` | Help |
|
|
65
65
|
| `q` | Quit |
|
|
66
66
|
|
|
67
|
+
#### Search
|
|
68
|
+
|
|
69
|
+
| Key | Action |
|
|
70
|
+
|-----|--------|
|
|
71
|
+
| `/` | Start search mode |
|
|
72
|
+
| `↑/↓` or `Ctrl+j/k` | Navigate search results |
|
|
73
|
+
| `Enter` | Jump to selected task's tab and select it |
|
|
74
|
+
| `Esc` | Cancel search |
|
|
75
|
+
|
|
67
76
|
#### Project Detail View
|
|
68
77
|
|
|
69
78
|
| Key | Action |
|
package/dist/i18n/en.js
CHANGED
|
@@ -198,7 +198,7 @@ export const en = {
|
|
|
198
198
|
search: {
|
|
199
199
|
prefix: '/',
|
|
200
200
|
placeholder: 'Search tasks...',
|
|
201
|
-
help: '(Enter to select, Ctrl+j/k to navigate, Esc to cancel)',
|
|
201
|
+
help: '(Enter to select, ↑/↓ or Ctrl+j/k to navigate, Esc to cancel)',
|
|
202
202
|
noResults: 'No matching tasks',
|
|
203
203
|
resultsTitle: 'Search Results',
|
|
204
204
|
searchTasks: 'Search tasks',
|
package/dist/i18n/ja.js
CHANGED
|
@@ -198,7 +198,7 @@ export const ja = {
|
|
|
198
198
|
search: {
|
|
199
199
|
prefix: '/',
|
|
200
200
|
placeholder: 'タスクを検索...',
|
|
201
|
-
help: '(Enterで選択, Ctrl+j/kで移動, Escでキャンセル)',
|
|
201
|
+
help: '(Enterで選択, ↑/↓またはCtrl+j/kで移動, Escでキャンセル)',
|
|
202
202
|
noResults: '該当するタスクがありません',
|
|
203
203
|
resultsTitle: '検索結果',
|
|
204
204
|
searchTasks: 'タスク検索',
|
package/dist/ui/App.js
CHANGED
|
@@ -174,6 +174,18 @@ function AppContent({ onOpenSettings }) {
|
|
|
174
174
|
setSearchResults(results);
|
|
175
175
|
setSearchResultIndex(0);
|
|
176
176
|
}, [searchTasks]);
|
|
177
|
+
// Navigate to a task from search results
|
|
178
|
+
const navigateToTask = useCallback((task) => {
|
|
179
|
+
const targetTab = task.isProject ? 'projects' : task.status;
|
|
180
|
+
const tabIndex = TABS.indexOf(targetTab);
|
|
181
|
+
const tabTasks = tasks[targetTab];
|
|
182
|
+
const taskIndex = tabTasks.findIndex(t => t.id === task.id);
|
|
183
|
+
if (tabIndex >= 0 && taskIndex >= 0) {
|
|
184
|
+
setCurrentListIndex(tabIndex);
|
|
185
|
+
setSelectedTaskIndex(taskIndex);
|
|
186
|
+
setMode('normal');
|
|
187
|
+
}
|
|
188
|
+
}, [tasks]);
|
|
177
189
|
const addTask = useCallback(async (title, parentId) => {
|
|
178
190
|
if (!title.trim())
|
|
179
191
|
return;
|
|
@@ -224,9 +236,7 @@ function AppContent({ onOpenSettings }) {
|
|
|
224
236
|
if (mode === 'search') {
|
|
225
237
|
if (searchResults.length > 0) {
|
|
226
238
|
const task = searchResults[searchResultIndex];
|
|
227
|
-
|
|
228
|
-
loadTaskComments(task.id);
|
|
229
|
-
setMode('task-detail');
|
|
239
|
+
navigateToTask(task);
|
|
230
240
|
}
|
|
231
241
|
else {
|
|
232
242
|
setMode('normal');
|
|
@@ -345,12 +355,12 @@ function AppContent({ onOpenSettings }) {
|
|
|
345
355
|
setMode('normal');
|
|
346
356
|
return;
|
|
347
357
|
}
|
|
348
|
-
// Navigate search results with Ctrl+j/k or Ctrl+n/p
|
|
349
|
-
if (key.ctrl && (input === 'j' || input === 'n')) {
|
|
358
|
+
// Navigate search results with arrow keys, Ctrl+j/k, or Ctrl+n/p
|
|
359
|
+
if (key.downArrow || (key.ctrl && (input === 'j' || input === 'n'))) {
|
|
350
360
|
setSearchResultIndex((prev) => prev < searchResults.length - 1 ? prev + 1 : 0);
|
|
351
361
|
return;
|
|
352
362
|
}
|
|
353
|
-
if (key.ctrl && (input === 'k' || input === 'p')) {
|
|
363
|
+
if (key.upArrow || (key.ctrl && (input === 'k' || input === 'p'))) {
|
|
354
364
|
setSearchResultIndex((prev) => prev > 0 ? prev - 1 : Math.max(0, searchResults.length - 1));
|
|
355
365
|
return;
|
|
356
366
|
}
|
|
@@ -140,6 +140,30 @@ export function KanbanBoard({ onSwitchToGtd, onOpenSettings }) {
|
|
|
140
140
|
setSearchResults(results);
|
|
141
141
|
setSearchResultIndex(0);
|
|
142
142
|
}, [searchTasks]);
|
|
143
|
+
// Navigate to a task from search results
|
|
144
|
+
const navigateToTask = useCallback((task) => {
|
|
145
|
+
// Determine which column the task belongs to based on status
|
|
146
|
+
let targetColumn;
|
|
147
|
+
if (task.status === 'inbox' || task.status === 'someday') {
|
|
148
|
+
targetColumn = 'todo';
|
|
149
|
+
}
|
|
150
|
+
else if (task.status === 'next' || task.status === 'waiting') {
|
|
151
|
+
targetColumn = 'doing';
|
|
152
|
+
}
|
|
153
|
+
else {
|
|
154
|
+
targetColumn = 'done';
|
|
155
|
+
}
|
|
156
|
+
const columnIndex = COLUMNS.indexOf(targetColumn);
|
|
157
|
+
const taskIndex = tasks[targetColumn].findIndex(t => t.id === task.id);
|
|
158
|
+
if (columnIndex >= 0 && taskIndex >= 0) {
|
|
159
|
+
setCurrentColumnIndex(columnIndex);
|
|
160
|
+
setSelectedTaskIndices(prev => ({
|
|
161
|
+
...prev,
|
|
162
|
+
[targetColumn]: taskIndex,
|
|
163
|
+
}));
|
|
164
|
+
setMode('normal');
|
|
165
|
+
}
|
|
166
|
+
}, [tasks]);
|
|
143
167
|
const addTask = useCallback(async (title) => {
|
|
144
168
|
if (!title.trim())
|
|
145
169
|
return;
|
|
@@ -169,9 +193,7 @@ export function KanbanBoard({ onSwitchToGtd, onOpenSettings }) {
|
|
|
169
193
|
if (mode === 'search') {
|
|
170
194
|
if (searchResults.length > 0) {
|
|
171
195
|
const task = searchResults[searchResultIndex];
|
|
172
|
-
|
|
173
|
-
loadTaskComments(task.id);
|
|
174
|
-
setMode('task-detail');
|
|
196
|
+
navigateToTask(task);
|
|
175
197
|
}
|
|
176
198
|
else {
|
|
177
199
|
setMode('normal');
|
|
@@ -257,12 +279,12 @@ export function KanbanBoard({ onSwitchToGtd, onOpenSettings }) {
|
|
|
257
279
|
setMode('normal');
|
|
258
280
|
return;
|
|
259
281
|
}
|
|
260
|
-
// Navigate search results with Ctrl+j/k or Ctrl+n/p
|
|
261
|
-
if (key.ctrl && (input === 'j' || input === 'n')) {
|
|
282
|
+
// Navigate search results with arrow keys, Ctrl+j/k, or Ctrl+n/p
|
|
283
|
+
if (key.downArrow || (key.ctrl && (input === 'j' || input === 'n'))) {
|
|
262
284
|
setSearchResultIndex((prev) => prev < searchResults.length - 1 ? prev + 1 : 0);
|
|
263
285
|
return;
|
|
264
286
|
}
|
|
265
|
-
if (key.ctrl && (input === 'k' || input === 'p')) {
|
|
287
|
+
if (key.upArrow || (key.ctrl && (input === 'k' || input === 'p'))) {
|
|
266
288
|
setSearchResultIndex((prev) => prev > 0 ? prev - 1 : Math.max(0, searchResults.length - 1));
|
|
267
289
|
return;
|
|
268
290
|
}
|
|
@@ -12,7 +12,7 @@ export function SearchResults({ results, selectedIndex, query }) {
|
|
|
12
12
|
return (_jsxs(Box, { flexDirection: "column", borderStyle: theme.borders.list, borderColor: theme.colors.borderActive, paddingX: 1, paddingY: 1, minHeight: 5, children: [_jsx(Box, { marginBottom: 1, children: _jsxs(Text, { color: theme.colors.secondary, bold: true, children: ["[", search.resultsTitle, "] (", results.length, ")"] }) }), results.length === 0 ? (_jsx(Text, { color: theme.colors.textMuted, italic: true, children: search.noResults })) : (results.slice(0, 10).map((task, index) => {
|
|
13
13
|
const isSelected = index === selectedIndex;
|
|
14
14
|
const shortId = task.id.slice(0, 8);
|
|
15
|
-
const
|
|
16
|
-
return (_jsx(Box, { children: _jsxs(Text, { color: isSelected ? theme.colors.textSelected : theme.colors.text, bold: isSelected, children: [isSelected ? theme.style.selectedPrefix : theme.style.unselectedPrefix, "[", shortId, "] ", task.title, _jsxs(Text, { color: theme.colors.textMuted, children: [" (",
|
|
15
|
+
const displayLabel = task.isProject ? i18n.tui.keyBar.project : i18n.status[task.status];
|
|
16
|
+
return (_jsx(Box, { children: _jsxs(Text, { color: isSelected ? theme.colors.textSelected : theme.colors.text, bold: isSelected, children: [isSelected ? theme.style.selectedPrefix : theme.style.unselectedPrefix, "[", shortId, "] ", task.title, _jsxs(Text, { color: theme.colors.textMuted, children: [" (", displayLabel, ")"] }), task.waitingFor && (_jsxs(Text, { color: theme.colors.statusWaiting, children: [" - ", task.waitingFor] }))] }) }, task.id));
|
|
17
17
|
})), results.length > 10 && (_jsxs(Text, { color: theme.colors.textMuted, italic: true, children: ["... and ", results.length - 10, " more"] }))] }));
|
|
18
18
|
}
|