floq 0.3.1 → 0.5.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 CHANGED
@@ -7,9 +7,10 @@ MS-DOSスタイルのテーマを備えたターミナルベースのGTD(Getti
7
7
  ## 特徴
8
8
 
9
9
  - **TUIインターフェース**: Ink(CLI用React)で構築されたインタラクティブなターミナルUI
10
- - **GTDワークフロー**: Inbox、Next Actions、Waiting For、Someday/Maybe、Done
10
+ - **GTDワークフロー**: Inbox、Next Actions、Waiting For、Someday/Maybe、Done(過去7日間表示)
11
11
  - **カンバンモード**: 3カラムのカンバンボード表示(TODO、Doing、Done)
12
12
  - **プロジェクト**: タスクをプロジェクトに整理(進捗バー表示付き)
13
+ - **コンテキスト**: タスクにコンテキスト(@work、@homeなど)を設定してフィルタリング。タスク追加時は現在のフィルターを自動継承
13
14
  - **タスク検索**: `/` キーで全タスクを素早く検索
14
15
  - **コメント**: タスクにメモやコメントを追加
15
16
  - **クラウド同期**: [Turso](https://turso.tech/)のembedded replicasによるオプションの同期機能
@@ -57,6 +58,8 @@ floq
57
58
  | `w` | Waiting Forに移動(担当者入力) |
58
59
  | `p` | プロジェクトに変換 |
59
60
  | `P` | プロジェクトに紐付け |
61
+ | `c` | コンテキスト設定 |
62
+ | `@` | コンテキストでフィルター |
60
63
  | `Enter` | タスク詳細を開く / プロジェクトを開く |
61
64
  | `Esc/b` | 戻る |
62
65
  | `/` | タスク検索 |
@@ -106,6 +109,8 @@ floq
106
109
  | `d` | 完了にする |
107
110
  | `m` | タスクを右に移動(→) |
108
111
  | `Backspace` | タスクを左に移動(←) |
112
+ | `c` | コンテキスト設定 |
113
+ | `@` | コンテキストでフィルター |
109
114
  | `Enter` | タスク詳細を開く |
110
115
  | `/` | タスク検索 |
111
116
  | `r` | 更新 |
@@ -142,6 +147,7 @@ floq setup
142
147
  # タスク追加
143
148
  floq add "タスクのタイトル"
144
149
  floq add "タスクのタイトル" -p "プロジェクト名"
150
+ floq add "タスクのタイトル" -c work # コンテキスト付き
145
151
 
146
152
  # タスク一覧
147
153
  floq list # 未完了タスク全て
@@ -168,6 +174,11 @@ floq project complete <id>
168
174
  # コメント
169
175
  floq comment <id> "コメント内容" # コメント追加
170
176
  floq comment <id> # コメント一覧
177
+
178
+ # コンテキスト
179
+ floq context list # コンテキスト一覧
180
+ floq context add <name> # コンテキスト追加
181
+ floq context remove <name> # コンテキスト削除
171
182
  ```
172
183
 
173
184
  ## 設定
package/README.md CHANGED
@@ -7,9 +7,10 @@ A terminal-based GTD (Getting Things Done) task manager with MS-DOS style themes
7
7
  ## Features
8
8
 
9
9
  - **TUI Interface**: Interactive terminal UI built with Ink (React for CLI)
10
- - **GTD Workflow**: Inbox, Next Actions, Waiting For, Someday/Maybe, Done
10
+ - **GTD Workflow**: Inbox, Next Actions, Waiting For, Someday/Maybe, Done (shows last 7 days)
11
11
  - **Kanban Mode**: 3-column kanban board view (TODO, Doing, Done)
12
12
  - **Projects**: Organize tasks into projects with progress tracking
13
+ - **Contexts**: Tag tasks with contexts (@work, @home, etc.) and filter by context. New tasks inherit the active context filter
13
14
  - **Task Search**: Quick search across all tasks with `/`
14
15
  - **Comments**: Add notes and comments to tasks
15
16
  - **Cloud Sync**: Optional sync with [Turso](https://turso.tech/) using embedded replicas
@@ -57,6 +58,8 @@ floq
57
58
  | `w` | Move to Waiting For (prompts for person) |
58
59
  | `p` | Convert to project |
59
60
  | `P` | Link to project |
61
+ | `c` | Set context |
62
+ | `@` | Filter by context |
60
63
  | `Enter` | Open task detail / Open project |
61
64
  | `Esc/b` | Back |
62
65
  | `/` | Search tasks |
@@ -106,6 +109,8 @@ floq
106
109
  | `d` | Mark as done |
107
110
  | `m` | Move task right (→) |
108
111
  | `Backspace` | Move task left (←) |
112
+ | `c` | Set context |
113
+ | `@` | Filter by context |
109
114
  | `Enter` | Open task detail |
110
115
  | `/` | Search tasks |
111
116
  | `r` | Refresh |
@@ -142,6 +147,7 @@ floq setup
142
147
  # Add task
143
148
  floq add "Task title"
144
149
  floq add "Task title" -p "Project name"
150
+ floq add "Task title" -c work # With context
145
151
 
146
152
  # List tasks
147
153
  floq list # All non-done tasks
@@ -168,6 +174,11 @@ floq project complete <id>
168
174
  # Comments
169
175
  floq comment <id> "Comment text" # Add comment
170
176
  floq comment <id> # List comments
177
+
178
+ # Contexts
179
+ floq context list # List available contexts
180
+ floq context add <name> # Add new context
181
+ floq context remove <name> # Remove context
171
182
  ```
172
183
 
173
184
  ## Configuration
package/dist/cli.js CHANGED
@@ -9,6 +9,7 @@ import { markDone } from './commands/done.js';
9
9
  import { addProject, listProjectsCommand, showProject, completeProject, } from './commands/project.js';
10
10
  import { showConfig, setLanguage, setDbPath, resetDbPath, setTheme, selectTheme, setViewModeCommand, selectMode, setTurso, disableTurso, syncCommand, resetDatabase } from './commands/config.js';
11
11
  import { addComment, listComments } from './commands/comment.js';
12
+ import { listContexts, addContextCommand, removeContextCommand } from './commands/context.js';
12
13
  import { runSetupWizard } from './commands/setup.js';
13
14
  import { VERSION } from './version.js';
14
15
  const program = new Command();
@@ -27,6 +28,7 @@ program
27
28
  .description('Add a new task to Inbox')
28
29
  .option('-p, --project <name>', 'Add to a specific project')
29
30
  .option('-d, --description <text>', 'Add a description')
31
+ .option('-c, --context <context>', 'Set context (e.g., work, home)')
30
32
  .action(async (title, options) => {
31
33
  await addTask(title, options);
32
34
  });
@@ -183,6 +185,28 @@ program
183
185
  await listComments(taskId);
184
186
  }
185
187
  });
188
+ // Context commands
189
+ const contextCmd = program
190
+ .command('context')
191
+ .description('Context management commands');
192
+ contextCmd
193
+ .command('list')
194
+ .description('List available contexts')
195
+ .action(async () => {
196
+ await listContexts();
197
+ });
198
+ contextCmd
199
+ .command('add <name>')
200
+ .description('Add a new context')
201
+ .action(async (name) => {
202
+ await addContextCommand(name);
203
+ });
204
+ contextCmd
205
+ .command('remove <name>')
206
+ .description('Remove a context')
207
+ .action(async (name) => {
208
+ await removeContextCommand(name);
209
+ });
186
210
  // Setup wizard command
187
211
  program
188
212
  .command('setup')
@@ -1,6 +1,7 @@
1
1
  interface AddOptions {
2
2
  project?: string;
3
3
  description?: string;
4
+ context?: string;
4
5
  }
5
6
  export declare function addTask(title: string, options: AddOptions): Promise<void>;
6
7
  export {};
@@ -18,12 +18,14 @@ export async function addTask(title, options) {
18
18
  }
19
19
  parentId = projects[0].id;
20
20
  }
21
+ const context = options.context?.toLowerCase().replace(/^@/, '');
21
22
  const task = {
22
23
  id: uuidv4(),
23
24
  title,
24
25
  description: options.description,
25
26
  status: 'inbox',
26
27
  parentId,
28
+ context: context || null,
27
29
  createdAt: now,
28
30
  updatedAt: now,
29
31
  };
@@ -0,0 +1,3 @@
1
+ export declare function listContexts(): Promise<void>;
2
+ export declare function addContextCommand(name: string): Promise<void>;
3
+ export declare function removeContextCommand(name: string): Promise<void>;
@@ -0,0 +1,36 @@
1
+ import { getContexts, addContext, removeContext } from '../config.js';
2
+ import { t, fmt } from '../i18n/index.js';
3
+ export async function listContexts() {
4
+ const i18n = t();
5
+ const contexts = getContexts();
6
+ if (contexts.length === 0) {
7
+ console.log(i18n.commands.context.noContexts);
8
+ return;
9
+ }
10
+ console.log(i18n.commands.context.list);
11
+ for (const context of contexts) {
12
+ console.log(` @${context}`);
13
+ }
14
+ }
15
+ export async function addContextCommand(name) {
16
+ const i18n = t();
17
+ const normalized = name.toLowerCase().replace(/^@/, '');
18
+ if (addContext(normalized)) {
19
+ console.log(fmt(i18n.commands.context.added, { context: normalized }));
20
+ }
21
+ else {
22
+ console.error(fmt(i18n.commands.context.alreadyExists, { context: normalized }));
23
+ process.exit(1);
24
+ }
25
+ }
26
+ export async function removeContextCommand(name) {
27
+ const i18n = t();
28
+ const normalized = name.toLowerCase().replace(/^@/, '');
29
+ if (removeContext(normalized)) {
30
+ console.log(fmt(i18n.commands.context.removed, { context: normalized }));
31
+ }
32
+ else {
33
+ console.error(fmt(i18n.commands.context.notFound, { context: normalized }));
34
+ process.exit(1);
35
+ }
36
+ }
@@ -1,4 +1,4 @@
1
- import { eq } from 'drizzle-orm';
1
+ import { eq, and, gte } from 'drizzle-orm';
2
2
  import { getDb, schema } from '../db/index.js';
3
3
  import { t, fmt } from '../i18n/index.js';
4
4
  export async function listTasks(status) {
@@ -11,10 +11,22 @@ export async function listTasks(status) {
11
11
  console.error(fmt(i18n.commands.list.validStatuses, { statuses: validStatuses.join(', ') }));
12
12
  process.exit(1);
13
13
  }
14
- const tasks = await db
15
- .select()
16
- .from(schema.tasks)
17
- .where(eq(schema.tasks.status, status));
14
+ // For done status, only show tasks from the last week by default
15
+ let tasks;
16
+ if (status === 'done') {
17
+ const oneWeekAgo = new Date();
18
+ oneWeekAgo.setDate(oneWeekAgo.getDate() - 7);
19
+ tasks = await db
20
+ .select()
21
+ .from(schema.tasks)
22
+ .where(and(eq(schema.tasks.status, 'done'), gte(schema.tasks.updatedAt, oneWeekAgo)));
23
+ }
24
+ else {
25
+ tasks = await db
26
+ .select()
27
+ .from(schema.tasks)
28
+ .where(eq(schema.tasks.status, status));
29
+ }
18
30
  console.log(`\n${i18n.status[status]} (${tasks.length})`);
19
31
  console.log('─'.repeat(40));
20
32
  if (tasks.length === 0) {
package/dist/config.d.ts CHANGED
@@ -12,6 +12,7 @@ export interface Config {
12
12
  theme: ThemeName;
13
13
  viewMode: ViewMode;
14
14
  turso?: TursoConfig;
15
+ contexts?: string[];
15
16
  }
16
17
  export declare function loadConfig(): Config;
17
18
  export declare function saveConfig(updates: Partial<Config>): void;
@@ -26,3 +27,6 @@ export declare function setThemeName(theme: ThemeName): void;
26
27
  export declare function getViewMode(): ViewMode;
27
28
  export declare function setViewMode(viewMode: ViewMode): void;
28
29
  export declare function isFirstRun(): boolean;
30
+ export declare function getContexts(): string[];
31
+ export declare function addContext(context: string): boolean;
32
+ export declare function removeContext(context: string): boolean;
package/dist/config.js CHANGED
@@ -28,10 +28,12 @@ function migrateDbFiles() {
28
28
  }
29
29
  // Run DB file migration on module load
30
30
  migrateDbFiles();
31
+ const DEFAULT_CONTEXTS = ['work', 'home'];
31
32
  const DEFAULT_CONFIG = {
32
33
  locale: 'en',
33
34
  theme: 'modern',
34
35
  viewMode: 'gtd',
36
+ contexts: DEFAULT_CONTEXTS,
35
37
  };
36
38
  let configCache = null;
37
39
  export function loadConfig() {
@@ -113,3 +115,26 @@ export function setViewMode(viewMode) {
113
115
  export function isFirstRun() {
114
116
  return !existsSync(CONFIG_FILE);
115
117
  }
118
+ export function getContexts() {
119
+ return loadConfig().contexts || DEFAULT_CONTEXTS;
120
+ }
121
+ export function addContext(context) {
122
+ const contexts = getContexts();
123
+ const normalized = context.toLowerCase().replace(/^@/, '');
124
+ if (contexts.includes(normalized)) {
125
+ return false;
126
+ }
127
+ saveConfig({ contexts: [...contexts, normalized] });
128
+ return true;
129
+ }
130
+ export function removeContext(context) {
131
+ const contexts = getContexts();
132
+ const normalized = context.toLowerCase().replace(/^@/, '');
133
+ const index = contexts.indexOf(normalized);
134
+ if (index === -1) {
135
+ return false;
136
+ }
137
+ const newContexts = contexts.filter(c => c !== normalized);
138
+ saveConfig({ contexts: newContexts });
139
+ return true;
140
+ }
package/dist/db/index.js CHANGED
@@ -23,6 +23,7 @@ async function initializeRemoteSchema(tursoUrl, authToken) {
23
23
  const tableInfoResult = await remoteClient.execute("PRAGMA table_info(tasks)");
24
24
  const tableInfo = tableInfoResult.rows;
25
25
  const tableExists = tableInfo.length > 0;
26
+ const hasContext = tableInfo.some(col => col.name === 'context');
26
27
  if (!tableExists) {
27
28
  // Fresh install: create new schema on remote
28
29
  await remoteClient.execute(`
@@ -34,6 +35,7 @@ async function initializeRemoteSchema(tursoUrl, authToken) {
34
35
  is_project INTEGER NOT NULL DEFAULT 0,
35
36
  parent_id TEXT,
36
37
  waiting_for TEXT,
38
+ context TEXT,
37
39
  due_date INTEGER,
38
40
  created_at INTEGER NOT NULL,
39
41
  updated_at INTEGER NOT NULL
@@ -42,6 +44,12 @@ async function initializeRemoteSchema(tursoUrl, authToken) {
42
44
  await remoteClient.execute("CREATE INDEX IF NOT EXISTS idx_tasks_status ON tasks(status)");
43
45
  await remoteClient.execute("CREATE INDEX IF NOT EXISTS idx_tasks_parent_id ON tasks(parent_id)");
44
46
  await remoteClient.execute("CREATE INDEX IF NOT EXISTS idx_tasks_is_project ON tasks(is_project)");
47
+ await remoteClient.execute("CREATE INDEX IF NOT EXISTS idx_tasks_context ON tasks(context)");
48
+ }
49
+ else if (!hasContext) {
50
+ // Migration: add context column
51
+ await remoteClient.execute("ALTER TABLE tasks ADD COLUMN context TEXT");
52
+ await remoteClient.execute("CREATE INDEX IF NOT EXISTS idx_tasks_context ON tasks(context)");
45
53
  }
46
54
  // Create comments table
47
55
  await remoteClient.execute(`
@@ -66,6 +74,7 @@ async function initializeLocalSchema() {
66
74
  const tableInfo = tableInfoResult.rows;
67
75
  const hasProjectId = tableInfo.some(col => col.name === 'project_id');
68
76
  const hasIsProject = tableInfo.some(col => col.name === 'is_project');
77
+ const hasContext = tableInfo.some(col => col.name === 'context');
69
78
  const tableExists = tableInfo.length > 0;
70
79
  if (tableExists && hasProjectId && !hasIsProject) {
71
80
  // Migration: old schema -> new schema
@@ -96,6 +105,7 @@ async function initializeLocalSchema() {
96
105
  is_project INTEGER NOT NULL DEFAULT 0,
97
106
  parent_id TEXT,
98
107
  waiting_for TEXT,
108
+ context TEXT,
99
109
  due_date INTEGER,
100
110
  created_at INTEGER NOT NULL,
101
111
  updated_at INTEGER NOT NULL
@@ -104,6 +114,12 @@ async function initializeLocalSchema() {
104
114
  await client.execute("CREATE INDEX IF NOT EXISTS idx_tasks_status ON tasks(status)");
105
115
  await client.execute("CREATE INDEX IF NOT EXISTS idx_tasks_parent_id ON tasks(parent_id)");
106
116
  await client.execute("CREATE INDEX IF NOT EXISTS idx_tasks_is_project ON tasks(is_project)");
117
+ await client.execute("CREATE INDEX IF NOT EXISTS idx_tasks_context ON tasks(context)");
118
+ }
119
+ // Migration: add context column if missing
120
+ if (tableExists && !hasContext) {
121
+ await client.execute("ALTER TABLE tasks ADD COLUMN context TEXT");
122
+ await client.execute("CREATE INDEX IF NOT EXISTS idx_tasks_context ON tasks(context)");
107
123
  }
108
124
  // Create comments table
109
125
  await client.execute(`
@@ -133,6 +133,25 @@ export declare const tasks: import("drizzle-orm/sqlite-core").SQLiteTableWithCol
133
133
  }, {}, {
134
134
  length: number | undefined;
135
135
  }>;
136
+ context: import("drizzle-orm/sqlite-core").SQLiteColumn<{
137
+ name: "context";
138
+ tableName: "tasks";
139
+ dataType: "string";
140
+ columnType: "SQLiteText";
141
+ data: string;
142
+ driverParam: string;
143
+ notNull: false;
144
+ hasDefault: false;
145
+ isPrimaryKey: false;
146
+ isAutoincrement: false;
147
+ hasRuntimeDefault: false;
148
+ enumValues: [string, ...string[]];
149
+ baseColumn: never;
150
+ identity: undefined;
151
+ generated: undefined;
152
+ }, {}, {
153
+ length: number | undefined;
154
+ }>;
136
155
  dueDate: import("drizzle-orm/sqlite-core").SQLiteColumn<{
137
156
  name: "due_date";
138
157
  tableName: "tasks";
package/dist/db/schema.js CHANGED
@@ -7,6 +7,7 @@ export const tasks = sqliteTable('tasks', {
7
7
  isProject: integer('is_project', { mode: 'boolean' }).notNull().default(false),
8
8
  parentId: text('parent_id'),
9
9
  waitingFor: text('waiting_for'),
10
+ context: text('context'),
10
11
  dueDate: integer('due_date', { mode: 'timestamp' }),
11
12
  createdAt: integer('created_at', { mode: 'timestamp' }).notNull(),
12
13
  updatedAt: integer('updated_at', { mode: 'timestamp' }).notNull(),
package/dist/i18n/en.d.ts CHANGED
@@ -63,6 +63,14 @@ export declare const en: {
63
63
  noComments: string;
64
64
  listHeader: string;
65
65
  };
66
+ context: {
67
+ list: string;
68
+ added: string;
69
+ removed: string;
70
+ alreadyExists: string;
71
+ notFound: string;
72
+ noContexts: string;
73
+ };
66
74
  };
67
75
  tui: {
68
76
  title: string;
@@ -129,6 +137,8 @@ export declare const en: {
129
137
  taskDetail: string;
130
138
  addComment: string;
131
139
  searchTasks: string;
140
+ filterByContext: string;
141
+ setContext: string;
132
142
  settings: string;
133
143
  changeTheme: string;
134
144
  changeViewMode: string;
@@ -199,6 +209,21 @@ export declare const en: {
199
209
  resultsTitle: string;
200
210
  searchTasks: string;
201
211
  };
212
+ context: {
213
+ label: string;
214
+ filter: string;
215
+ filterHelp: string;
216
+ all: string;
217
+ none: string;
218
+ setContext: string;
219
+ setContextHelp: string;
220
+ contextSet: string;
221
+ contextCleared: string;
222
+ filterActive: string;
223
+ addNew: string;
224
+ newContext: string;
225
+ newContextPlaceholder: string;
226
+ };
202
227
  info: {
203
228
  settings: string;
204
229
  database: string;
@@ -290,6 +315,8 @@ export type HelpTranslations = {
290
315
  taskDetail: string;
291
316
  addComment: string;
292
317
  searchTasks: string;
318
+ filterByContext: string;
319
+ setContext: string;
293
320
  settings: string;
294
321
  changeTheme: string;
295
322
  changeViewMode: string;
@@ -359,6 +386,21 @@ export type SearchTranslations = {
359
386
  resultsTitle: string;
360
387
  searchTasks: string;
361
388
  };
389
+ export type ContextTranslations = {
390
+ label: string;
391
+ filter: string;
392
+ filterHelp: string;
393
+ all: string;
394
+ none: string;
395
+ setContext: string;
396
+ setContextHelp: string;
397
+ contextSet: string;
398
+ contextCleared: string;
399
+ filterActive: string;
400
+ addNew: string;
401
+ newContext: string;
402
+ newContextPlaceholder: string;
403
+ };
362
404
  export type InfoTranslations = {
363
405
  settings: string;
364
406
  database: string;
@@ -404,6 +446,7 @@ export type TuiTranslations = {
404
446
  whatsNew: WhatsNewTranslations;
405
447
  kanbanHelp: KanbanHelpTranslations;
406
448
  search: SearchTranslations;
449
+ context: ContextTranslations;
407
450
  info: InfoTranslations;
408
451
  addComment: string;
409
452
  noComments: string;
@@ -485,6 +528,7 @@ export type Translations = {
485
528
  done: Record<string, string>;
486
529
  project: Record<string, string>;
487
530
  comment: Record<string, string>;
531
+ context: Record<string, string>;
488
532
  };
489
533
  tui: TuiTranslations;
490
534
  setup: SetupTranslations;
package/dist/i18n/en.js CHANGED
@@ -67,6 +67,14 @@ export const en = {
67
67
  noComments: 'No comments',
68
68
  listHeader: 'Comments for "{title}":',
69
69
  },
70
+ context: {
71
+ list: 'Available contexts:',
72
+ added: 'Added context: @{context}',
73
+ removed: 'Removed context: @{context}',
74
+ alreadyExists: 'Context @{context} already exists.',
75
+ notFound: 'Context @{context} not found.',
76
+ noContexts: 'No contexts configured.',
77
+ },
70
78
  },
71
79
  // TUI
72
80
  tui: {
@@ -138,6 +146,8 @@ export const en = {
138
146
  taskDetail: 'View task details',
139
147
  addComment: 'Add comment',
140
148
  searchTasks: 'Search tasks',
149
+ filterByContext: 'Filter by context',
150
+ setContext: 'Set context',
141
151
  settings: 'Settings',
142
152
  changeTheme: 'Change theme',
143
153
  changeViewMode: 'Change view mode',
@@ -212,6 +222,22 @@ export const en = {
212
222
  resultsTitle: 'Search Results',
213
223
  searchTasks: 'Search tasks',
214
224
  },
225
+ // Context
226
+ context: {
227
+ label: 'Context',
228
+ filter: 'Filter by context',
229
+ filterHelp: 'j/k: select, Enter: confirm, Esc: cancel',
230
+ all: 'All',
231
+ none: 'No context',
232
+ setContext: 'Set context',
233
+ setContextHelp: 'j/k: select, Enter: confirm, Esc: cancel',
234
+ contextSet: 'Set context @{context} for "{title}"',
235
+ contextCleared: 'Cleared context for "{title}"',
236
+ filterActive: '@{context}',
237
+ addNew: '+ New context',
238
+ newContext: 'New context: ',
239
+ newContextPlaceholder: 'Enter context name...',
240
+ },
215
241
  // Info tab
216
242
  info: {
217
243
  settings: 'Settings',
package/dist/i18n/ja.js CHANGED
@@ -67,6 +67,14 @@ export const ja = {
67
67
  noComments: 'コメントはありません',
68
68
  listHeader: '「{title}」のコメント:',
69
69
  },
70
+ context: {
71
+ list: '利用可能なコンテキスト:',
72
+ added: 'コンテキストを追加しました: @{context}',
73
+ removed: 'コンテキストを削除しました: @{context}',
74
+ alreadyExists: 'コンテキスト @{context} は既に存在します。',
75
+ notFound: 'コンテキスト @{context} が見つかりません。',
76
+ noContexts: 'コンテキストが設定されていません。',
77
+ },
70
78
  },
71
79
  // TUI
72
80
  tui: {
@@ -138,6 +146,8 @@ export const ja = {
138
146
  taskDetail: 'タスク詳細を表示',
139
147
  addComment: 'コメント追加',
140
148
  searchTasks: 'タスク検索',
149
+ filterByContext: 'コンテキストフィルター',
150
+ setContext: 'コンテキスト設定',
141
151
  settings: '設定',
142
152
  changeTheme: 'テーマ変更',
143
153
  changeViewMode: '表示モード変更',
@@ -212,6 +222,22 @@ export const ja = {
212
222
  resultsTitle: '検索結果',
213
223
  searchTasks: 'タスク検索',
214
224
  },
225
+ // Context
226
+ context: {
227
+ label: 'コンテキスト',
228
+ filter: 'コンテキストでフィルター',
229
+ filterHelp: 'j/k: 選択, Enter: 確定, Esc: キャンセル',
230
+ all: 'すべて',
231
+ none: 'コンテキストなし',
232
+ setContext: 'コンテキスト設定',
233
+ setContextHelp: 'j/k: 選択, Enter: 確定, Esc: キャンセル',
234
+ contextSet: '「{title}」にコンテキスト @{context} を設定しました',
235
+ contextCleared: '「{title}」のコンテキストをクリアしました',
236
+ filterActive: '@{context}',
237
+ addNew: '+ 新規コンテキスト',
238
+ newContext: '新規コンテキスト: ',
239
+ newContextPlaceholder: 'コンテキスト名を入力...',
240
+ },
215
241
  // Info tab
216
242
  info: {
217
243
  settings: '設定',