floq 0.4.0 → 0.6.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 +16 -3
- package/README.md +16 -3
- package/dist/cli.js +12 -1
- package/dist/commands/config.d.ts +2 -0
- package/dist/commands/config.js +51 -1
- package/dist/commands/list.js +17 -5
- package/dist/config.d.ts +3 -0
- package/dist/config.js +13 -0
- package/dist/i18n/en.d.ts +13 -0
- package/dist/i18n/en.js +7 -0
- package/dist/i18n/ja.js +7 -0
- package/dist/ui/App.js +39 -20
- package/dist/ui/SplashScreen.d.ts +2 -1
- package/dist/ui/SplashScreen.js +109 -10
- package/dist/ui/components/DQLayout.d.ts +36 -0
- package/dist/ui/components/DQLayout.js +53 -0
- package/dist/ui/components/DQTaskList.d.ts +53 -0
- package/dist/ui/components/DQTaskList.js +48 -0
- package/dist/ui/components/DQWindow.d.ts +19 -0
- package/dist/ui/components/DQWindow.js +33 -0
- package/dist/ui/components/GtdDQ.d.ts +7 -0
- package/dist/ui/components/GtdDQ.js +773 -0
- package/dist/ui/components/HelpModal.js +136 -102
- package/dist/ui/components/KanbanBoard.js +10 -6
- package/dist/ui/components/KanbanColumn.js +53 -1
- package/dist/ui/components/KanbanDQ.d.ts +7 -0
- package/dist/ui/components/KanbanDQ.js +470 -0
- package/dist/ui/components/SearchResults.d.ts +2 -1
- package/dist/ui/components/SearchResults.js +22 -2
- package/dist/ui/components/TitledBox.d.ts +11 -0
- package/dist/ui/components/TitledBox.js +66 -0
- package/dist/ui/theme/themes.d.ts +1 -0
- package/dist/ui/theme/themes.js +43 -1
- package/dist/ui/theme/types.d.ts +3 -1
- package/package.json +1 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { useState, useMemo } from 'react';
|
|
3
3
|
import { Box, Text, useInput } from 'ink';
|
|
4
4
|
import { t } from '../../i18n/index.js';
|
|
@@ -6,32 +6,135 @@ import { useTheme } from '../theme/index.js';
|
|
|
6
6
|
import { parseChangelog } from '../../changelog.js';
|
|
7
7
|
import { loadConfig, isTursoEnabled, getTursoConfig, getDbPath } from '../../config.js';
|
|
8
8
|
import { CONFIG_FILE, DATA_DIR } from '../../paths.js';
|
|
9
|
-
const VISIBLE_LINES =
|
|
9
|
+
const VISIBLE_LINES = 14;
|
|
10
10
|
export function HelpModal({ onClose, isKanban = false }) {
|
|
11
11
|
const [activeTab, setActiveTab] = useState('keybindings');
|
|
12
12
|
const [scrollOffset, setScrollOffset] = useState(0);
|
|
13
13
|
const i18n = t();
|
|
14
14
|
const theme = useTheme();
|
|
15
15
|
const help = i18n.tui.help;
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
const formatTitle = (title) => theme.style.headerUppercase ? title.toUpperCase() : title;
|
|
17
|
+
// Build keybindings content
|
|
18
|
+
const keybindingsContent = useMemo(() => {
|
|
19
|
+
if (isKanban) {
|
|
20
|
+
const kHelp = i18n.tui.kanbanHelp;
|
|
21
|
+
return [
|
|
22
|
+
{ type: 'header', value: kHelp.navigation },
|
|
23
|
+
{ type: 'key', key: 'h/l ←/→', value: kHelp.columnSwitch },
|
|
24
|
+
{ type: 'key', key: '1-3', value: kHelp.columnDirect },
|
|
25
|
+
{ type: 'key', key: 'j/k ↑/↓', value: kHelp.taskSelect },
|
|
26
|
+
{ type: 'header', value: kHelp.actions },
|
|
27
|
+
{ type: 'key', key: 'a', value: kHelp.addTask },
|
|
28
|
+
{ type: 'key', key: 'd', value: kHelp.completeTask },
|
|
29
|
+
{ type: 'key', key: 'm', value: kHelp.moveRight },
|
|
30
|
+
{ type: 'key', key: 'BS', value: kHelp.moveLeft },
|
|
31
|
+
{ type: 'key', key: 'u', value: 'Undo' },
|
|
32
|
+
{ type: 'key', key: 'Ctrl+r', value: 'Redo' },
|
|
33
|
+
{ type: 'header', value: kHelp.settings },
|
|
34
|
+
{ type: 'key', key: 'T', value: kHelp.changeTheme },
|
|
35
|
+
{ type: 'key', key: 'V', value: kHelp.changeViewMode },
|
|
36
|
+
{ type: 'key', key: 'L', value: kHelp.changeLanguage },
|
|
37
|
+
{ type: 'header', value: kHelp.other },
|
|
38
|
+
{ type: 'key', key: '/', value: kHelp.searchTasks },
|
|
39
|
+
{ type: 'key', key: '?', value: kHelp.showHelp },
|
|
40
|
+
{ type: 'key', key: 'q', value: kHelp.quit },
|
|
41
|
+
];
|
|
42
|
+
}
|
|
43
|
+
return [
|
|
44
|
+
{ type: 'header', value: help.navigation },
|
|
45
|
+
{ type: 'key', key: '1-6', value: help.tabSwitch },
|
|
46
|
+
{ type: 'key', key: 'h/l ←/→', value: help.prevNextTab },
|
|
47
|
+
{ type: 'key', key: 'j/k ↑/↓', value: help.taskSelect },
|
|
48
|
+
{ type: 'header', value: help.actions },
|
|
49
|
+
{ type: 'key', key: 'a', value: help.addTask },
|
|
50
|
+
{ type: 'key', key: 'd', value: help.completeTask },
|
|
51
|
+
{ type: 'key', key: 'n', value: help.moveToNext },
|
|
52
|
+
{ type: 'key', key: 's', value: help.moveToSomeday },
|
|
53
|
+
{ type: 'key', key: 'w', value: help.moveToWaiting },
|
|
54
|
+
{ type: 'key', key: 'i', value: help.moveToInbox },
|
|
55
|
+
{ type: 'key', key: 'r', value: help.refresh },
|
|
56
|
+
{ type: 'key', key: 'u', value: help.undo },
|
|
57
|
+
{ type: 'key', key: 'Ctrl+r', value: help.redo },
|
|
58
|
+
{ type: 'header', value: help.projects },
|
|
59
|
+
{ type: 'key', key: 'p', value: help.makeProject },
|
|
60
|
+
{ type: 'key', key: 'P', value: help.linkToProject },
|
|
61
|
+
{ type: 'key', key: 'Enter', value: help.openProject },
|
|
62
|
+
{ type: 'key', key: 'Esc/b', value: help.backFromProject },
|
|
63
|
+
{ type: 'header', value: help.settings },
|
|
64
|
+
{ type: 'key', key: 'T', value: help.changeTheme },
|
|
65
|
+
{ type: 'key', key: 'V', value: help.changeViewMode },
|
|
66
|
+
{ type: 'key', key: 'L', value: help.changeLanguage },
|
|
67
|
+
{ type: 'header', value: help.other },
|
|
68
|
+
{ type: 'key', key: '/', value: help.searchTasks },
|
|
69
|
+
{ type: 'key', key: '?', value: help.showHelp },
|
|
70
|
+
{ type: 'key', key: 'q', value: help.quit },
|
|
71
|
+
];
|
|
72
|
+
}, [isKanban, help, i18n.tui.kanbanHelp]);
|
|
73
|
+
// Build info content
|
|
74
|
+
const infoContent = useMemo(() => {
|
|
75
|
+
const info = i18n.tui.info;
|
|
76
|
+
const config = loadConfig();
|
|
77
|
+
const tursoEnabled = isTursoEnabled();
|
|
78
|
+
const tursoConfig = tursoEnabled ? getTursoConfig() : undefined;
|
|
79
|
+
const dbPath = getDbPath();
|
|
80
|
+
const tursoUrl = tursoConfig ? (() => {
|
|
81
|
+
try {
|
|
82
|
+
return new URL(tursoConfig.url).host;
|
|
83
|
+
}
|
|
84
|
+
catch {
|
|
85
|
+
return tursoConfig.url;
|
|
86
|
+
}
|
|
87
|
+
})() : '';
|
|
88
|
+
const lines = [
|
|
89
|
+
{ type: 'header', value: info.settings },
|
|
90
|
+
{ type: 'key', key: info.theme, value: config.theme },
|
|
91
|
+
{ type: 'key', key: info.language, value: config.locale },
|
|
92
|
+
{ type: 'key', key: info.viewMode, value: config.viewMode },
|
|
93
|
+
{ type: 'header', value: info.database },
|
|
94
|
+
{ type: 'key', key: info.dbType, value: tursoEnabled ? info.turso : info.local },
|
|
95
|
+
{ type: 'key', key: info.dbPath, value: dbPath },
|
|
96
|
+
];
|
|
97
|
+
if (tursoEnabled && tursoUrl) {
|
|
98
|
+
lines.push({ type: 'key', key: info.tursoUrl, value: tursoUrl });
|
|
99
|
+
}
|
|
100
|
+
lines.push({ type: 'header', value: info.paths }, { type: 'key', key: info.configFile, value: CONFIG_FILE }, { type: 'key', key: info.dataDir, value: DATA_DIR });
|
|
101
|
+
return lines;
|
|
102
|
+
}, [i18n.tui.info]);
|
|
103
|
+
// Build changelog content
|
|
104
|
+
const changelogContent = useMemo(() => {
|
|
18
105
|
const changelog = parseChangelog();
|
|
106
|
+
const whatsNew = i18n.tui.whatsNew;
|
|
19
107
|
const items = [];
|
|
108
|
+
const getSectionLabel = (type) => {
|
|
109
|
+
const labels = {
|
|
110
|
+
Added: whatsNew.added,
|
|
111
|
+
Changed: whatsNew.changed,
|
|
112
|
+
Deprecated: whatsNew.deprecated,
|
|
113
|
+
Removed: whatsNew.removed,
|
|
114
|
+
Fixed: whatsNew.fixed,
|
|
115
|
+
Security: whatsNew.security,
|
|
116
|
+
};
|
|
117
|
+
return labels[type] || type;
|
|
118
|
+
};
|
|
20
119
|
for (const entry of changelog.entries.slice(0, 5)) {
|
|
21
|
-
items.push({ type: 'version',
|
|
120
|
+
items.push({ type: 'version', value: entry.version, date: entry.date });
|
|
22
121
|
for (const section of entry.sections) {
|
|
23
|
-
items.push({ type: 'section',
|
|
122
|
+
items.push({ type: 'section', value: getSectionLabel(section.type) });
|
|
24
123
|
for (const item of section.items) {
|
|
25
|
-
items.push({ type: 'item',
|
|
124
|
+
items.push({ type: 'item', value: item });
|
|
26
125
|
}
|
|
27
126
|
}
|
|
28
127
|
}
|
|
29
128
|
return items;
|
|
30
|
-
}, []);
|
|
31
|
-
|
|
129
|
+
}, [i18n.tui.whatsNew]);
|
|
130
|
+
// Get current content and max scroll
|
|
131
|
+
const currentContent = activeTab === 'keybindings' ? keybindingsContent
|
|
132
|
+
: activeTab === 'info' ? infoContent
|
|
133
|
+
: changelogContent;
|
|
134
|
+
const maxScroll = Math.max(0, currentContent.length - VISIBLE_LINES);
|
|
32
135
|
const tabs = ['keybindings', 'info', 'whatsNew'];
|
|
33
136
|
useInput((input, key) => {
|
|
34
|
-
// Tab key detection
|
|
137
|
+
// Tab key detection
|
|
35
138
|
if (key.tab || input === '\t') {
|
|
36
139
|
setActiveTab(prev => {
|
|
37
140
|
const currentIndex = tabs.indexOf(prev);
|
|
@@ -56,108 +159,39 @@ export function HelpModal({ onClose, isKanban = false }) {
|
|
|
56
159
|
setScrollOffset(0);
|
|
57
160
|
return;
|
|
58
161
|
}
|
|
59
|
-
//
|
|
60
|
-
if (input === '
|
|
61
|
-
|
|
62
|
-
const currentIndex = tabs.indexOf(prev);
|
|
63
|
-
return tabs[(currentIndex - 1 + tabs.length) % tabs.length];
|
|
64
|
-
});
|
|
65
|
-
setScrollOffset(0);
|
|
162
|
+
// Scroll with j/k or arrows
|
|
163
|
+
if (input === 'j' || key.downArrow) {
|
|
164
|
+
setScrollOffset(prev => Math.min(prev + 1, maxScroll));
|
|
66
165
|
return;
|
|
67
166
|
}
|
|
68
|
-
if (input === '
|
|
69
|
-
|
|
70
|
-
const currentIndex = tabs.indexOf(prev);
|
|
71
|
-
return tabs[(currentIndex + 1) % tabs.length];
|
|
72
|
-
});
|
|
73
|
-
setScrollOffset(0);
|
|
167
|
+
if (input === 'k' || key.upArrow) {
|
|
168
|
+
setScrollOffset(prev => Math.max(prev - 1, 0));
|
|
74
169
|
return;
|
|
75
170
|
}
|
|
76
|
-
// Scroll in What's New tab
|
|
77
|
-
if (activeTab === 'whatsNew') {
|
|
78
|
-
if (input === 'j' || key.downArrow) {
|
|
79
|
-
setScrollOffset(prev => Math.min(prev + 1, maxScroll));
|
|
80
|
-
return;
|
|
81
|
-
}
|
|
82
|
-
if (input === 'k' || key.upArrow) {
|
|
83
|
-
setScrollOffset(prev => Math.max(prev - 1, 0));
|
|
84
|
-
return;
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
171
|
// Close modal
|
|
88
172
|
if (key.escape || key.return || input === 'q' || input === ' ') {
|
|
89
173
|
onClose();
|
|
90
174
|
return;
|
|
91
175
|
}
|
|
92
176
|
});
|
|
93
|
-
const
|
|
94
|
-
return (_jsxs(Box, { flexDirection: "column", borderStyle: theme.borders.modal, borderColor: theme.colors.borderActive, paddingX: 2, paddingY: 1, children: [_jsx(Box, { justifyContent: "center", marginBottom: 1, children: _jsxs(Box, { children: [_jsxs(Text, { bold: activeTab === 'keybindings', color: activeTab === 'keybindings' ? theme.colors.secondary : theme.colors.textMuted, inverse: activeTab === 'keybindings', children: [' ', formatTitle(help.keybindingsTab), ' '] }), _jsx(Text, { color: theme.colors.textMuted, children: " \u2502 " }), _jsxs(Text, { bold: activeTab === 'info', color: activeTab === 'info' ? theme.colors.secondary : theme.colors.textMuted, inverse: activeTab === 'info', children: [' ', formatTitle(help.infoTab), ' '] }), _jsx(Text, { color: theme.colors.textMuted, children: " \u2502 " }), _jsxs(Text, { bold: activeTab === 'whatsNew', color: activeTab === 'whatsNew' ? theme.colors.secondary : theme.colors.textMuted, inverse: activeTab === 'whatsNew', children: [' ', formatTitle(help.whatsNewTab), ' '] })] }) }), activeTab === 'keybindings' ? (isKanban ? (_jsx(KanbanKeybindingsContent, {})) : (_jsx(GTDKeybindingsContent, {}))) : activeTab === 'info' ? (_jsx(InfoContent, {})) : (_jsx(WhatsNewContent, { items: changelogItems, scrollOffset: scrollOffset, visibleLines: VISIBLE_LINES, maxScroll: maxScroll })), _jsx(Box, { justifyContent: "center", marginTop: 1, children: _jsx(Text, { color: theme.colors.textMuted, children: activeTab === 'whatsNew' && maxScroll > 0
|
|
95
|
-
? `j/k: scroll | ${help.tabHint} | ${help.closeHint}`
|
|
96
|
-
: `${help.tabHint} | ${help.closeHint}` }) })] }));
|
|
97
|
-
}
|
|
98
|
-
function GTDKeybindingsContent() {
|
|
99
|
-
const i18n = t();
|
|
100
|
-
const help = i18n.tui.help;
|
|
101
|
-
const theme = useTheme();
|
|
102
|
-
const formatTitle = (title) => theme.style.headerUppercase ? title.toUpperCase() : title;
|
|
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] })] })] })] }));
|
|
104
|
-
}
|
|
105
|
-
function KanbanKeybindingsContent() {
|
|
106
|
-
const i18n = t();
|
|
107
|
-
const help = i18n.tui.kanbanHelp;
|
|
108
|
-
const theme = useTheme();
|
|
109
|
-
const formatTitle = (title) => theme.style.headerUppercase ? title.toUpperCase() : title;
|
|
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] })] })] })] }));
|
|
111
|
-
}
|
|
112
|
-
function InfoContent() {
|
|
113
|
-
const i18n = t();
|
|
114
|
-
const info = i18n.tui.info;
|
|
115
|
-
const theme = useTheme();
|
|
116
|
-
const formatTitle = (title) => theme.style.headerUppercase ? title.toUpperCase() : title;
|
|
117
|
-
const config = loadConfig();
|
|
118
|
-
const tursoEnabled = isTursoEnabled();
|
|
119
|
-
const tursoConfig = tursoEnabled ? getTursoConfig() : undefined;
|
|
120
|
-
const dbPath = getDbPath();
|
|
121
|
-
// Get Turso host for display
|
|
122
|
-
const tursoUrl = tursoConfig ? (() => {
|
|
123
|
-
try {
|
|
124
|
-
return new URL(tursoConfig.url).host;
|
|
125
|
-
}
|
|
126
|
-
catch {
|
|
127
|
-
return tursoConfig.url;
|
|
128
|
-
}
|
|
129
|
-
})() : '';
|
|
130
|
-
return (_jsxs(_Fragment, { children: [_jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [_jsx(Text, { bold: true, color: theme.colors.accent, children: formatTitle(info.settings) }), _jsxs(Box, { paddingLeft: 2, flexDirection: "column", children: [_jsxs(Text, { color: theme.colors.text, children: [_jsxs(Text, { color: theme.colors.textHighlight, children: [info.theme, ":"] }), " ", config.theme] }), _jsxs(Text, { color: theme.colors.text, children: [_jsxs(Text, { color: theme.colors.textHighlight, children: [info.language, ":"] }), " ", config.locale] }), _jsxs(Text, { color: theme.colors.text, children: [_jsxs(Text, { color: theme.colors.textHighlight, children: [info.viewMode, ":"] }), " ", config.viewMode] })] })] }), _jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [_jsx(Text, { bold: true, color: theme.colors.accent, children: formatTitle(info.database) }), _jsxs(Box, { paddingLeft: 2, flexDirection: "column", children: [_jsxs(Text, { color: theme.colors.text, children: [_jsxs(Text, { color: theme.colors.textHighlight, children: [info.dbType, ":"] }), " ", tursoEnabled ? info.turso : info.local] }), _jsxs(Text, { color: theme.colors.text, children: [_jsxs(Text, { color: theme.colors.textHighlight, children: [info.dbPath, ":"] }), " ", dbPath] }), tursoEnabled && tursoUrl && (_jsxs(Text, { color: theme.colors.text, children: [_jsxs(Text, { color: theme.colors.textHighlight, children: [info.tursoUrl, ":"] }), " ", tursoUrl] }))] })] }), _jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [_jsx(Text, { bold: true, color: theme.colors.accent, children: formatTitle(info.paths) }), _jsxs(Box, { paddingLeft: 2, flexDirection: "column", children: [_jsxs(Text, { color: theme.colors.text, children: [_jsxs(Text, { color: theme.colors.textHighlight, children: [info.configFile, ":"] }), " ", CONFIG_FILE] }), _jsxs(Text, { color: theme.colors.text, children: [_jsxs(Text, { color: theme.colors.textHighlight, children: [info.dataDir, ":"] }), " ", DATA_DIR] })] })] })] }));
|
|
131
|
-
}
|
|
132
|
-
function WhatsNewContent({ items, scrollOffset, visibleLines, maxScroll }) {
|
|
133
|
-
const i18n = t();
|
|
134
|
-
const whatsNew = i18n.tui.whatsNew;
|
|
135
|
-
const theme = useTheme();
|
|
136
|
-
const formatTitle = (title) => theme.style.headerUppercase ? title.toUpperCase() : title;
|
|
137
|
-
const getSectionLabel = (type) => {
|
|
138
|
-
const labels = {
|
|
139
|
-
Added: whatsNew.added,
|
|
140
|
-
Changed: whatsNew.changed,
|
|
141
|
-
Deprecated: whatsNew.deprecated,
|
|
142
|
-
Removed: whatsNew.removed,
|
|
143
|
-
Fixed: whatsNew.fixed,
|
|
144
|
-
Security: whatsNew.security,
|
|
145
|
-
};
|
|
146
|
-
return labels[type] || type;
|
|
147
|
-
};
|
|
148
|
-
if (items.length === 0) {
|
|
149
|
-
return (_jsx(Box, { justifyContent: "center", paddingY: 2, children: _jsx(Text, { color: theme.colors.textMuted, children: whatsNew.noChanges }) }));
|
|
150
|
-
}
|
|
151
|
-
const visibleItems = items.slice(scrollOffset, scrollOffset + visibleLines);
|
|
177
|
+
const visibleContent = currentContent.slice(scrollOffset, scrollOffset + VISIBLE_LINES);
|
|
152
178
|
const showScrollUp = scrollOffset > 0;
|
|
153
179
|
const showScrollDown = scrollOffset < maxScroll;
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
return (_jsxs(Text, { color: theme.colors.
|
|
162
|
-
|
|
180
|
+
const renderLine = (line, index) => {
|
|
181
|
+
switch (line.type) {
|
|
182
|
+
case 'header':
|
|
183
|
+
return (_jsx(Text, { bold: true, color: theme.colors.accent, children: formatTitle(line.value) }, index));
|
|
184
|
+
case 'key':
|
|
185
|
+
return (_jsxs(Text, { color: theme.colors.text, children: [' ', _jsx(Text, { color: theme.colors.textHighlight, children: (line.key || '').padEnd(10) }), " ", line.value] }, index));
|
|
186
|
+
case 'version':
|
|
187
|
+
return (_jsxs(Text, { bold: true, color: theme.colors.accent, children: ["v", line.value, " ", line.date && _jsxs(Text, { color: theme.colors.textMuted, children: ["(", line.date, ")"] })] }, index));
|
|
188
|
+
case 'section':
|
|
189
|
+
return (_jsxs(Text, { color: theme.colors.secondary, children: [' ', formatTitle(line.value), ":"] }, index));
|
|
190
|
+
case 'item':
|
|
191
|
+
return (_jsxs(Text, { color: theme.colors.text, children: [' ', "\u2022 ", line.value] }, index));
|
|
192
|
+
default:
|
|
193
|
+
return (_jsx(Text, { color: theme.colors.text, children: line.value }, index));
|
|
194
|
+
}
|
|
195
|
+
};
|
|
196
|
+
return (_jsxs(Box, { flexDirection: "column", borderStyle: theme.borders.modal, borderColor: theme.colors.borderActive, paddingX: 2, paddingY: 1, children: [_jsx(Box, { justifyContent: "center", marginBottom: 1, children: _jsxs(Box, { children: [_jsxs(Text, { bold: activeTab === 'keybindings', color: activeTab === 'keybindings' ? theme.colors.secondary : theme.colors.textMuted, inverse: activeTab === 'keybindings', children: [' ', formatTitle(help.keybindingsTab), ' '] }), _jsx(Text, { color: theme.colors.textMuted, children: " \u2502 " }), _jsxs(Text, { bold: activeTab === 'info', color: activeTab === 'info' ? theme.colors.secondary : theme.colors.textMuted, inverse: activeTab === 'info', children: [' ', formatTitle(help.infoTab), ' '] }), _jsx(Text, { color: theme.colors.textMuted, children: " \u2502 " }), _jsxs(Text, { bold: activeTab === 'whatsNew', color: activeTab === 'whatsNew' ? theme.colors.secondary : theme.colors.textMuted, inverse: activeTab === 'whatsNew', children: [' ', formatTitle(help.whatsNewTab), ' '] })] }) }), _jsxs(Box, { flexDirection: "column", height: VISIBLE_LINES + 2, children: [showScrollUp && (_jsx(Text, { color: theme.colors.textMuted, children: " \u25B2 scroll up (k)" })), !showScrollUp && _jsx(Text, { children: " " }), visibleContent.map((line, index) => renderLine(line, index)), showScrollDown && (_jsx(Text, { color: theme.colors.textMuted, children: " \u25BC scroll down (j)" })), !showScrollDown && _jsx(Text, { children: " " })] }), _jsx(Box, { justifyContent: "center", marginTop: 1, children: _jsxs(Text, { color: theme.colors.textMuted, children: [maxScroll > 0 ? `j/k: scroll | ` : '', help.tabHint, " | ", help.closeHint] }) })] }));
|
|
163
197
|
}
|
|
@@ -2,7 +2,7 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
|
|
|
2
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
|
-
import { eq, and, inArray } from 'drizzle-orm';
|
|
5
|
+
import { eq, and, inArray, gte } from 'drizzle-orm';
|
|
6
6
|
import { v4 as uuidv4 } from 'uuid';
|
|
7
7
|
import { KanbanColumn } from './KanbanColumn.js';
|
|
8
8
|
import { HelpModal } from './HelpModal.js';
|
|
@@ -72,11 +72,13 @@ export function KanbanBoard({ onSwitchToGtd, onOpenSettings }) {
|
|
|
72
72
|
.select()
|
|
73
73
|
.from(schema.tasks)
|
|
74
74
|
.where(and(inArray(schema.tasks.status, ['next', 'waiting']), eq(schema.tasks.isProject, false)));
|
|
75
|
-
// Done: done (non-project tasks)
|
|
75
|
+
// Done: done (non-project tasks) - only show last week
|
|
76
|
+
const oneWeekAgo = new Date();
|
|
77
|
+
oneWeekAgo.setDate(oneWeekAgo.getDate() - 7);
|
|
76
78
|
let doneTasks = await db
|
|
77
79
|
.select()
|
|
78
80
|
.from(schema.tasks)
|
|
79
|
-
.where(and(eq(schema.tasks.status, 'done'), eq(schema.tasks.isProject, false)));
|
|
81
|
+
.where(and(eq(schema.tasks.status, 'done'), eq(schema.tasks.isProject, false), gte(schema.tasks.updatedAt, oneWeekAgo)));
|
|
80
82
|
// Load projects for linking
|
|
81
83
|
const projectTasks = await db
|
|
82
84
|
.select()
|
|
@@ -189,7 +191,7 @@ export function KanbanBoard({ onSwitchToGtd, onOpenSettings }) {
|
|
|
189
191
|
setMode('normal');
|
|
190
192
|
}
|
|
191
193
|
}, [tasks]);
|
|
192
|
-
const addTask = useCallback(async (title) => {
|
|
194
|
+
const addTask = useCallback(async (title, context) => {
|
|
193
195
|
if (!title.trim())
|
|
194
196
|
return;
|
|
195
197
|
const now = new Date();
|
|
@@ -199,6 +201,7 @@ export function KanbanBoard({ onSwitchToGtd, onOpenSettings }) {
|
|
|
199
201
|
id: taskId,
|
|
200
202
|
title: title.trim(),
|
|
201
203
|
status: 'inbox', // New tasks go to inbox (which maps to TODO)
|
|
204
|
+
context: context || null,
|
|
202
205
|
createdAt: now,
|
|
203
206
|
updatedAt: now,
|
|
204
207
|
},
|
|
@@ -249,7 +252,8 @@ export function KanbanBoard({ onSwitchToGtd, onOpenSettings }) {
|
|
|
249
252
|
return;
|
|
250
253
|
}
|
|
251
254
|
if (value.trim()) {
|
|
252
|
-
|
|
255
|
+
// Pass contextFilter when adding a task, so it inherits the current filter context
|
|
256
|
+
await addTask(value, contextFilter && contextFilter !== '' ? contextFilter : null);
|
|
253
257
|
}
|
|
254
258
|
setInputValue('');
|
|
255
259
|
setMode('normal');
|
|
@@ -711,7 +715,7 @@ export function KanbanBoard({ onSwitchToGtd, onOpenSettings }) {
|
|
|
711
715
|
: (tursoEnabled ? ' [DB]TURSO' : ' [DB]local') }), contextFilter !== null && (_jsxs(Text, { color: theme.colors.accent, children: [' ', "@", contextFilter === '' ? (i18n.tui.context?.none || 'none') : contextFilter] }))] }), _jsx(Text, { color: theme.colors.textMuted, children: i18n.tui.helpHint })] }), (mode === 'task-detail' || mode === 'add-comment' || mode === 'select-project') && 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(Box, { marginTop: 1, children: [_jsxs(Text, { color: theme.colors.secondary, bold: true, children: [i18n.tui.taskDetailStatus, ": "] }), _jsxs(Text, { color: theme.colors.accent, children: [i18n.status[selectedTask.status], selectedTask.waitingFor && ` (${selectedTask.waitingFor})`] })] }), _jsxs(Box, { children: [_jsxs(Text, { color: theme.colors.secondary, bold: true, children: [i18n.tui.context?.label || 'Context', ": "] }), _jsx(Text, { color: theme.colors.accent, children: selectedTask.context ? `@${selectedTask.context}` : (i18n.tui.context?.none || 'No context') })] }), selectedTask.dueDate && (_jsxs(Text, { color: theme.colors.textMuted, children: ["Due: ", selectedTask.dueDate.toLocaleDateString()] }))] }), _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) => {
|
|
712
716
|
const isSelected = index === selectedCommentIndex && mode === 'task-detail';
|
|
713
717
|
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));
|
|
714
|
-
})) }), 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 === 'select-project' && (_jsxs(Box, { flexDirection: "column", marginTop: 1, children: [_jsxs(Text, { color: theme.colors.secondary, bold: true, children: [i18n.tui.selectProject || 'Select project for', ": ", selectedTask.title] }), _jsx(Box, { flexDirection: "column", marginTop: 1, borderStyle: theme.borders.list, borderColor: theme.colors.borderActive, paddingX: 1, children: 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(_Fragment, { children: searchQuery && (_jsx(SearchResults, { results: searchResults, selectedIndex: searchResultIndex, query: searchQuery })) })) : mode === 'context-filter' ? (_jsxs(Box, { flexDirection: "column", marginTop: 1, children: [_jsx(Text, { color: theme.colors.secondary, bold: true, children: i18n.tui.context?.filter || 'Filter by context' }), _jsx(Box, { flexDirection: "column", marginTop: 1, borderStyle: theme.borders.list, borderColor: theme.colors.borderActive, paddingX: 1, children: ['all', 'none', ...availableContexts].map((ctx, index) => {
|
|
718
|
+
})) }), 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 === 'select-project' && (_jsxs(Box, { flexDirection: "column", marginTop: 1, children: [_jsxs(Text, { color: theme.colors.secondary, bold: true, children: [i18n.tui.selectProject || 'Select project for', ": ", selectedTask.title] }), _jsx(Box, { flexDirection: "column", marginTop: 1, borderStyle: theme.borders.list, borderColor: theme.colors.borderActive, paddingX: 1, children: 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(_Fragment, { children: searchQuery && (_jsx(SearchResults, { results: searchResults, selectedIndex: searchResultIndex, query: searchQuery, viewMode: "kanban" })) })) : mode === 'context-filter' ? (_jsxs(Box, { flexDirection: "column", marginTop: 1, children: [_jsx(Text, { color: theme.colors.secondary, bold: true, children: i18n.tui.context?.filter || 'Filter by context' }), _jsx(Box, { flexDirection: "column", marginTop: 1, borderStyle: theme.borders.list, borderColor: theme.colors.borderActive, paddingX: 1, children: ['all', 'none', ...availableContexts].map((ctx, index) => {
|
|
715
719
|
const label = ctx === 'all'
|
|
716
720
|
? (i18n.tui.context?.all || 'All')
|
|
717
721
|
: ctx === 'none'
|
|
@@ -1,8 +1,60 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { Box, Text } from 'ink';
|
|
3
3
|
import { useTheme } from '../theme/index.js';
|
|
4
|
+
// Round border characters (DQ style)
|
|
5
|
+
const BORDER = {
|
|
6
|
+
topLeft: '╭',
|
|
7
|
+
topRight: '╮',
|
|
8
|
+
bottomLeft: '╰',
|
|
9
|
+
bottomRight: '╯',
|
|
10
|
+
horizontal: '─',
|
|
11
|
+
vertical: '│',
|
|
12
|
+
};
|
|
13
|
+
const SHADOW = '░';
|
|
14
|
+
// Calculate display width of string (full-width chars = 2, half-width = 1)
|
|
15
|
+
function getDisplayWidth(str) {
|
|
16
|
+
let width = 0;
|
|
17
|
+
for (const char of str) {
|
|
18
|
+
const code = char.charCodeAt(0);
|
|
19
|
+
if ((code >= 0x1100 && code <= 0x115F) ||
|
|
20
|
+
(code >= 0x2E80 && code <= 0x9FFF) ||
|
|
21
|
+
(code >= 0xAC00 && code <= 0xD7AF) ||
|
|
22
|
+
(code >= 0xF900 && code <= 0xFAFF) ||
|
|
23
|
+
(code >= 0xFE10 && code <= 0xFE1F) ||
|
|
24
|
+
(code >= 0xFE30 && code <= 0xFE6F) ||
|
|
25
|
+
(code >= 0xFF00 && code <= 0xFF60) ||
|
|
26
|
+
(code >= 0xFFE0 && code <= 0xFFE6) ||
|
|
27
|
+
(code >= 0x20000 && code <= 0x2FFFF)) {
|
|
28
|
+
width += 2;
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
width += 1;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return width;
|
|
35
|
+
}
|
|
4
36
|
export function KanbanColumn({ title, tasks, isActive, selectedTaskIndex, columnIndex, }) {
|
|
5
37
|
const theme = useTheme();
|
|
38
|
+
const isLastColumn = columnIndex === 2;
|
|
39
|
+
const showShadow = theme.uiStyle === 'titled-box' && isLastColumn;
|
|
40
|
+
// Use TitledBox style for dragon-quest theme
|
|
41
|
+
if (theme.uiStyle === 'titled-box') {
|
|
42
|
+
const color = isActive ? theme.colors.borderActive : theme.colors.border;
|
|
43
|
+
const shadowColor = theme.colors.muted;
|
|
44
|
+
const titleText = `${title} (${tasks.length})`;
|
|
45
|
+
const titleLength = getDisplayWidth(titleText);
|
|
46
|
+
// Fixed width for each column (will be stretched by flexGrow)
|
|
47
|
+
const innerWidth = 24;
|
|
48
|
+
const leftDashes = 2;
|
|
49
|
+
const titlePadding = 2;
|
|
50
|
+
const rightDashes = Math.max(2, innerWidth - leftDashes - titlePadding - titleLength);
|
|
51
|
+
return (_jsxs(Box, { flexDirection: "column", flexGrow: 1, flexBasis: 0, marginRight: columnIndex < 2 ? 1 : 0, children: [_jsxs(Box, { children: [_jsx(Text, { color: color, children: BORDER.topLeft }), _jsxs(Text, { color: color, children: [BORDER.horizontal.repeat(leftDashes), " "] }), _jsx(Text, { color: isActive ? theme.colors.accent : theme.colors.textMuted, bold: isActive, children: titleText }), _jsxs(Text, { color: color, children: [" ", BORDER.horizontal.repeat(rightDashes)] }), _jsx(Text, { color: color, children: BORDER.topRight }), showShadow && _jsx(Text, { children: " " })] }), _jsxs(Box, { flexDirection: "column", minHeight: 8, children: [tasks.length === 0 ? (_jsxs(Box, { children: [_jsx(Text, { color: color, children: BORDER.vertical }), _jsx(Box, { paddingX: 1, flexGrow: 1, children: _jsx(Text, { color: theme.colors.textMuted, italic: true, children: "-" }) }), _jsx(Text, { color: color, children: BORDER.vertical }), showShadow && _jsx(Text, { color: shadowColor, children: SHADOW })] })) : (tasks.map((task, index) => {
|
|
52
|
+
const isSelected = isActive && index === selectedTaskIndex;
|
|
53
|
+
const shortId = task.id.slice(0, 6);
|
|
54
|
+
return (_jsxs(Box, { children: [_jsx(Text, { color: color, children: BORDER.vertical }), _jsx(Box, { paddingX: 1, flexGrow: 1, children: _jsxs(Text, { color: isSelected ? theme.colors.textSelected : theme.colors.text, bold: isSelected, children: [isSelected ? theme.style.selectedPrefix : theme.style.unselectedPrefix, "[", shortId, "] ", task.title] }) }), _jsx(Text, { color: color, children: BORDER.vertical }), showShadow && _jsx(Text, { color: shadowColor, children: SHADOW })] }, task.id));
|
|
55
|
+
})), Array.from({ length: Math.max(0, 8 - Math.max(1, tasks.length)) }).map((_, i) => (_jsxs(Box, { children: [_jsx(Text, { color: color, children: BORDER.vertical }), _jsx(Box, { paddingX: 1, flexGrow: 1, children: _jsx(Text, { children: " " }) }), _jsx(Text, { color: color, children: BORDER.vertical }), showShadow && _jsx(Text, { color: shadowColor, children: SHADOW })] }, `empty-${i}`)))] }), _jsxs(Box, { children: [_jsx(Text, { color: color, children: BORDER.bottomLeft }), _jsx(Text, { color: color, children: BORDER.horizontal.repeat(innerWidth) }), _jsx(Text, { color: color, children: BORDER.bottomRight }), showShadow && _jsx(Text, { color: shadowColor, children: SHADOW })] }), showShadow && (_jsx(Box, { children: _jsxs(Text, { color: shadowColor, children: [" ", SHADOW.repeat(innerWidth + 2)] }) }))] }));
|
|
56
|
+
}
|
|
57
|
+
// Default style
|
|
6
58
|
return (_jsxs(Box, { flexDirection: "column", flexGrow: 1, flexBasis: 0, borderStyle: theme.borders.list, borderColor: isActive ? theme.colors.borderActive : theme.colors.border, marginRight: columnIndex < 2 ? 1 : 0, children: [_jsx(Box, { paddingX: 1, justifyContent: "center", borderStyle: undefined, children: _jsxs(Text, { bold: true, color: isActive ? theme.colors.primary : theme.colors.textMuted, inverse: isActive && theme.style.tabActiveInverse, children: [title, " (", tasks.length, ")"] }) }), _jsx(Box, { flexDirection: "column", paddingX: 1, paddingY: 1, minHeight: 8, children: tasks.length === 0 ? (_jsx(Text, { color: theme.colors.textMuted, italic: true, children: "-" })) : (tasks.map((task, index) => {
|
|
7
59
|
const isSelected = isActive && index === selectedTaskIndex;
|
|
8
60
|
const shortId = task.id.slice(0, 6);
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
type SettingsMode = 'none' | 'theme-select' | 'mode-select' | 'lang-select';
|
|
3
|
+
interface KanbanDQProps {
|
|
4
|
+
onOpenSettings?: (mode: SettingsMode) => void;
|
|
5
|
+
}
|
|
6
|
+
export declare function KanbanDQ({ onOpenSettings }: KanbanDQProps): React.ReactElement;
|
|
7
|
+
export {};
|