@walavave/cc98-cli 0.2.0 → 0.2.2
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/CHANGELOG.md +17 -0
- package/README.md +11 -3
- package/assets/forum-images/ac-dark/01.png +0 -0
- package/assets/forum-images/ac-dark/02.png +0 -0
- package/assets/forum-images/ac-dark/03.png +0 -0
- package/assets/forum-images/ac-dark/04.png +0 -0
- package/assets/forum-images/ac-dark/05.png +0 -0
- package/assets/forum-images/ac-dark/06.png +0 -0
- package/assets/forum-images/ac-dark/07.png +0 -0
- package/assets/forum-images/ac-dark/08.png +0 -0
- package/assets/forum-images/ac-dark/09.png +0 -0
- package/assets/forum-images/ac-dark/10.png +0 -0
- package/assets/forum-images/ac-dark/1001.png +0 -0
- package/assets/forum-images/ac-dark/1002.png +0 -0
- package/assets/forum-images/ac-dark/1003.png +0 -0
- package/assets/forum-images/ac-dark/1004.png +0 -0
- package/assets/forum-images/ac-dark/1005.png +0 -0
- package/assets/forum-images/ac-dark/1006.png +0 -0
- package/assets/forum-images/ac-dark/1007.png +0 -0
- package/assets/forum-images/ac-dark/1008.png +0 -0
- package/assets/forum-images/ac-dark/1009.png +0 -0
- package/assets/forum-images/ac-dark/1010.png +0 -0
- package/assets/forum-images/ac-dark/1011.png +0 -0
- package/assets/forum-images/ac-dark/1012.png +0 -0
- package/assets/forum-images/ac-dark/1013.png +0 -0
- package/assets/forum-images/ac-dark/1014.png +0 -0
- package/assets/forum-images/ac-dark/1015.png +0 -0
- package/assets/forum-images/ac-dark/1016.png +0 -0
- package/assets/forum-images/ac-dark/1017.png +0 -0
- package/assets/forum-images/ac-dark/1018.png +0 -0
- package/assets/forum-images/ac-dark/1019.png +0 -0
- package/assets/forum-images/ac-dark/1020.png +0 -0
- package/assets/forum-images/ac-dark/1021.png +0 -0
- package/assets/forum-images/ac-dark/1022.png +0 -0
- package/assets/forum-images/ac-dark/1023.png +0 -0
- package/assets/forum-images/ac-dark/1024.png +0 -0
- package/assets/forum-images/ac-dark/1025.png +0 -0
- package/assets/forum-images/ac-dark/1026.png +0 -0
- package/assets/forum-images/ac-dark/1027.png +0 -0
- package/assets/forum-images/ac-dark/1028.png +0 -0
- package/assets/forum-images/ac-dark/1029.png +0 -0
- package/assets/forum-images/ac-dark/1030.png +0 -0
- package/assets/forum-images/ac-dark/1031.png +0 -0
- package/assets/forum-images/ac-dark/1032.png +0 -0
- package/assets/forum-images/ac-dark/1033.png +0 -0
- package/assets/forum-images/ac-dark/1034.png +0 -0
- package/assets/forum-images/ac-dark/1035.png +0 -0
- package/assets/forum-images/ac-dark/1036.png +0 -0
- package/assets/forum-images/ac-dark/1037.png +0 -0
- package/assets/forum-images/ac-dark/1038.png +0 -0
- package/assets/forum-images/ac-dark/1039.png +0 -0
- package/assets/forum-images/ac-dark/1040.png +0 -0
- package/assets/forum-images/ac-dark/11.png +0 -0
- package/assets/forum-images/ac-dark/12.png +0 -0
- package/assets/forum-images/ac-dark/13.png +0 -0
- package/assets/forum-images/ac-dark/14.png +0 -0
- package/assets/forum-images/ac-dark/15.png +0 -0
- package/assets/forum-images/ac-dark/16.png +0 -0
- package/assets/forum-images/ac-dark/17.png +0 -0
- package/assets/forum-images/ac-dark/18.png +0 -0
- package/assets/forum-images/ac-dark/19.png +0 -0
- package/assets/forum-images/ac-dark/20.png +0 -0
- package/assets/forum-images/ac-dark/2001.png +0 -0
- package/assets/forum-images/ac-dark/2002.png +0 -0
- package/assets/forum-images/ac-dark/2003.png +0 -0
- package/assets/forum-images/ac-dark/2004.png +0 -0
- package/assets/forum-images/ac-dark/2005.png +0 -0
- package/assets/forum-images/ac-dark/2006.png +0 -0
- package/assets/forum-images/ac-dark/2007.png +0 -0
- package/assets/forum-images/ac-dark/2008.png +0 -0
- package/assets/forum-images/ac-dark/2009.png +0 -0
- package/assets/forum-images/ac-dark/2010.png +0 -0
- package/assets/forum-images/ac-dark/2011.png +0 -0
- package/assets/forum-images/ac-dark/2012.png +0 -0
- package/assets/forum-images/ac-dark/2013.png +0 -0
- package/assets/forum-images/ac-dark/2014.png +0 -0
- package/assets/forum-images/ac-dark/2015.png +0 -0
- package/assets/forum-images/ac-dark/2016.png +0 -0
- package/assets/forum-images/ac-dark/2017.png +0 -0
- package/assets/forum-images/ac-dark/2018.png +0 -0
- package/assets/forum-images/ac-dark/2019.png +0 -0
- package/assets/forum-images/ac-dark/2020.png +0 -0
- package/assets/forum-images/ac-dark/2021.png +0 -0
- package/assets/forum-images/ac-dark/2022.png +0 -0
- package/assets/forum-images/ac-dark/2023.png +0 -0
- package/assets/forum-images/ac-dark/2024.png +0 -0
- package/assets/forum-images/ac-dark/2025.png +0 -0
- package/assets/forum-images/ac-dark/2026.png +0 -0
- package/assets/forum-images/ac-dark/2027.png +0 -0
- package/assets/forum-images/ac-dark/2028.png +0 -0
- package/assets/forum-images/ac-dark/2029.png +0 -0
- package/assets/forum-images/ac-dark/2030.png +0 -0
- package/assets/forum-images/ac-dark/2031.png +0 -0
- package/assets/forum-images/ac-dark/2032.png +0 -0
- package/assets/forum-images/ac-dark/2033.png +0 -0
- package/assets/forum-images/ac-dark/2034.png +0 -0
- package/assets/forum-images/ac-dark/2035.png +0 -0
- package/assets/forum-images/ac-dark/2036.png +0 -0
- package/assets/forum-images/ac-dark/2037.png +0 -0
- package/assets/forum-images/ac-dark/2038.png +0 -0
- package/assets/forum-images/ac-dark/2039.png +0 -0
- package/assets/forum-images/ac-dark/2040.png +0 -0
- package/assets/forum-images/ac-dark/2041.png +0 -0
- package/assets/forum-images/ac-dark/2042.png +0 -0
- package/assets/forum-images/ac-dark/2043.png +0 -0
- package/assets/forum-images/ac-dark/2044.png +0 -0
- package/assets/forum-images/ac-dark/2045.png +0 -0
- package/assets/forum-images/ac-dark/2046.png +0 -0
- package/assets/forum-images/ac-dark/2047.png +0 -0
- package/assets/forum-images/ac-dark/2048.png +0 -0
- package/assets/forum-images/ac-dark/2049.png +0 -0
- package/assets/forum-images/ac-dark/2050.png +0 -0
- package/assets/forum-images/ac-dark/2051.png +0 -0
- package/assets/forum-images/ac-dark/2052.png +0 -0
- package/assets/forum-images/ac-dark/2053.png +0 -0
- package/assets/forum-images/ac-dark/2054.png +0 -0
- package/assets/forum-images/ac-dark/2055.png +0 -0
- package/assets/forum-images/ac-dark/21.png +0 -0
- package/assets/forum-images/ac-dark/22.png +0 -0
- package/assets/forum-images/ac-dark/23.png +0 -0
- package/assets/forum-images/ac-dark/24.png +0 -0
- package/assets/forum-images/ac-dark/25.png +0 -0
- package/assets/forum-images/ac-dark/26.png +0 -0
- package/assets/forum-images/ac-dark/27.png +0 -0
- package/assets/forum-images/ac-dark/28.png +0 -0
- package/assets/forum-images/ac-dark/29.png +0 -0
- package/assets/forum-images/ac-dark/30.png +0 -0
- package/assets/forum-images/ac-dark/31.png +0 -0
- package/assets/forum-images/ac-dark/32.png +0 -0
- package/assets/forum-images/ac-dark/33.png +0 -0
- package/assets/forum-images/ac-dark/34.png +0 -0
- package/assets/forum-images/ac-dark/35.png +0 -0
- package/assets/forum-images/ac-dark/36.png +0 -0
- package/assets/forum-images/ac-dark/37.png +0 -0
- package/assets/forum-images/ac-dark/38.png +0 -0
- package/assets/forum-images/ac-dark/39.png +0 -0
- package/assets/forum-images/ac-dark/40.png +0 -0
- package/assets/forum-images/ac-dark/41.png +0 -0
- package/assets/forum-images/ac-dark/42.png +0 -0
- package/assets/forum-images/ac-dark/43.png +0 -0
- package/assets/forum-images/ac-dark/44.png +0 -0
- package/assets/forum-images/ac-dark/45.png +0 -0
- package/assets/forum-images/ac-dark/46.png +0 -0
- package/assets/forum-images/ac-dark/47.png +0 -0
- package/assets/forum-images/ac-dark/48.png +0 -0
- package/assets/forum-images/ac-dark/49.png +0 -0
- package/assets/forum-images/ac-dark/50.png +0 -0
- package/assets/forum-images/ac-dark/51.png +0 -0
- package/assets/forum-images/ac-dark/52.png +0 -0
- package/assets/forum-images/ac-dark/53.png +0 -0
- package/assets/forum-images/ac-dark/54.png +0 -0
- package/dist/api/client.d.ts +2 -1
- package/dist/api/client.d.ts.map +1 -1
- package/dist/api/client.js +19 -2
- package/dist/api/client.js.map +1 -1
- package/dist/api/endpoints.d.ts +1 -0
- package/dist/api/endpoints.d.ts.map +1 -1
- package/dist/api/endpoints.js +1 -0
- package/dist/api/endpoints.js.map +1 -1
- package/dist/config.d.ts +2 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +25 -4
- package/dist/config.js.map +1 -1
- package/dist/tui/app-data.d.ts +4 -1
- package/dist/tui/app-data.d.ts.map +1 -1
- package/dist/tui/app-data.js +107 -0
- package/dist/tui/app-data.js.map +1 -1
- package/dist/tui/app-runtime/content.d.ts +9 -0
- package/dist/tui/app-runtime/content.d.ts.map +1 -0
- package/dist/tui/app-runtime/content.js +275 -0
- package/dist/tui/app-runtime/content.js.map +1 -0
- package/dist/tui/app-runtime/context.d.ts +24 -0
- package/dist/tui/app-runtime/context.d.ts.map +1 -0
- package/dist/tui/app-runtime/context.js +2 -0
- package/dist/tui/app-runtime/context.js.map +1 -0
- package/dist/tui/app-runtime/image-viewer.d.ts +5 -0
- package/dist/tui/app-runtime/image-viewer.d.ts.map +1 -0
- package/dist/tui/app-runtime/image-viewer.js +112 -0
- package/dist/tui/app-runtime/image-viewer.js.map +1 -0
- package/dist/tui/app-runtime/interactions.d.ts +6 -0
- package/dist/tui/app-runtime/interactions.d.ts.map +1 -0
- package/dist/tui/app-runtime/interactions.js +181 -0
- package/dist/tui/app-runtime/interactions.js.map +1 -0
- package/dist/tui/app-runtime/keyboard.d.ts +3 -0
- package/dist/tui/app-runtime/keyboard.d.ts.map +1 -0
- package/dist/tui/app-runtime/keyboard.js +284 -0
- package/dist/tui/app-runtime/keyboard.js.map +1 -0
- package/dist/tui/app-runtime/modals.d.ts +17 -0
- package/dist/tui/app-runtime/modals.d.ts.map +1 -0
- package/dist/tui/app-runtime/modals.js +343 -0
- package/dist/tui/app-runtime/modals.js.map +1 -0
- package/dist/tui/app-runtime/mouse.d.ts +5 -0
- package/dist/tui/app-runtime/mouse.d.ts.map +1 -0
- package/dist/tui/app-runtime/mouse.js +68 -0
- package/dist/tui/app-runtime/mouse.js.map +1 -0
- package/dist/tui/app-runtime/state.d.ts +6 -0
- package/dist/tui/app-runtime/state.d.ts.map +1 -0
- package/dist/tui/app-runtime/state.js +41 -0
- package/dist/tui/app-runtime/state.js.map +1 -0
- package/dist/tui/app-runtime/topic.d.ts +6 -0
- package/dist/tui/app-runtime/topic.d.ts.map +1 -0
- package/dist/tui/app-runtime/topic.js +184 -0
- package/dist/tui/app-runtime/topic.js.map +1 -0
- package/dist/tui/app-runtime.d.ts +2 -27
- package/dist/tui/app-runtime.d.ts.map +1 -1
- package/dist/tui/app-runtime.js +2 -960
- package/dist/tui/app-runtime.js.map +1 -1
- package/dist/tui/app.d.ts.map +1 -1
- package/dist/tui/app.js +5 -2
- package/dist/tui/app.js.map +1 -1
- package/dist/tui/cached-client.d.ts +2 -0
- package/dist/tui/cached-client.d.ts.map +1 -1
- package/dist/tui/cached-client.js +6 -0
- package/dist/tui/cached-client.js.map +1 -1
- package/dist/tui/emotion-catalog.d.ts +23 -0
- package/dist/tui/emotion-catalog.d.ts.map +1 -0
- package/dist/tui/emotion-catalog.js +150 -0
- package/dist/tui/emotion-catalog.js.map +1 -0
- package/dist/tui/emotion-preview.js +1 -1
- package/dist/tui/emotion-preview.js.map +1 -1
- package/dist/tui/image-preview.d.ts.map +1 -1
- package/dist/tui/image-preview.js +2 -1
- package/dist/tui/image-preview.js.map +1 -1
- package/dist/tui/keymap.d.ts +1 -1
- package/dist/tui/keymap.d.ts.map +1 -1
- package/dist/tui/keymap.js +5 -1
- package/dist/tui/keymap.js.map +1 -1
- package/dist/tui/renderer.d.ts.map +1 -1
- package/dist/tui/renderer.js +268 -4
- package/dist/tui/renderer.js.map +1 -1
- package/dist/tui/terminal.d.ts +3 -0
- package/dist/tui/terminal.d.ts.map +1 -1
- package/dist/tui/terminal.js +37 -0
- package/dist/tui/terminal.js.map +1 -1
- package/dist/tui/theme.d.ts +1 -0
- package/dist/tui/theme.d.ts.map +1 -1
- package/dist/tui/theme.js +1 -0
- package/dist/tui/theme.js.map +1 -1
- package/dist/tui/tui-model.d.ts +24 -2
- package/dist/tui/tui-model.d.ts.map +1 -1
- package/dist/tui/tui-model.js +12 -0
- package/dist/tui/tui-model.js.map +1 -1
- package/dist/tui/ubb-renderer.js +1 -1
- package/dist/tui/ubb-renderer.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
import { executeSearch, loadNextChatPage, loadNextSearchPage, openBoard, openChat, openTopic } from "../app-data.js";
|
|
2
|
+
import { isPrintableInput } from "../account-modal.js";
|
|
3
|
+
import { getStatus, navItems, settingsItems } from "../tui-model.js";
|
|
4
|
+
import { checkUpdate, openAccountOrLoginModal, requestCacheCleanup, requestLogout } from "./modals.js";
|
|
5
|
+
import { enterContentMode, leaveContentMode } from "./state.js";
|
|
6
|
+
export async function focusSearchInput(context) {
|
|
7
|
+
const { state, render, load, abortCurrent } = context;
|
|
8
|
+
const searchNavIndex = navItems.findIndex((item) => item.id === "search");
|
|
9
|
+
if (searchNavIndex < 0) {
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
if (state.navIndex === searchNavIndex && state.currentSearch) {
|
|
13
|
+
abortCurrent();
|
|
14
|
+
state.mode = "list";
|
|
15
|
+
state.focus = "content";
|
|
16
|
+
state.loading = false;
|
|
17
|
+
state.loadingMore = false;
|
|
18
|
+
state.error = undefined;
|
|
19
|
+
state.topic = undefined;
|
|
20
|
+
state.imageViewer = undefined;
|
|
21
|
+
state.currentSearch.focus = "input";
|
|
22
|
+
state.viewTitle = state.currentSearch.title;
|
|
23
|
+
state.status = getStatus(state);
|
|
24
|
+
render();
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
abortCurrent();
|
|
28
|
+
state.navIndex = searchNavIndex;
|
|
29
|
+
await load();
|
|
30
|
+
if (navItems[state.navIndex]?.id !== "search" || !state.currentSearch) {
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
state.mode = "list";
|
|
34
|
+
state.focus = "content";
|
|
35
|
+
state.currentSearch.focus = "input";
|
|
36
|
+
state.status = getStatus(state);
|
|
37
|
+
render();
|
|
38
|
+
}
|
|
39
|
+
export function handleSettingsMode(context, key) {
|
|
40
|
+
const { state, render, load } = context;
|
|
41
|
+
if (key === "j" || key === "\x1b[B") {
|
|
42
|
+
state.itemIndex = Math.min(settingsItems.length - 1, state.itemIndex + 1);
|
|
43
|
+
render();
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
if (key === "k" || key === "\x1b[A") {
|
|
47
|
+
state.itemIndex = Math.max(0, state.itemIndex - 1);
|
|
48
|
+
render();
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
if (key === "h" || key === "\x1b[D") {
|
|
52
|
+
leaveContentMode(state);
|
|
53
|
+
render();
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
if (key !== "l" && key !== "\x1b[C" && key !== "\r") {
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
const selected = settingsItems[state.itemIndex];
|
|
60
|
+
if (selected?.meta === "help") {
|
|
61
|
+
state.modal = "help";
|
|
62
|
+
render();
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
if (selected?.meta === "cache") {
|
|
66
|
+
requestCacheCleanup(context);
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
if (selected?.meta === "logout") {
|
|
70
|
+
requestLogout(context);
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
if (selected?.meta === "account") {
|
|
74
|
+
openAccountOrLoginModal(context);
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
if (selected?.meta === "update") {
|
|
78
|
+
checkUpdate(context);
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
void load(true);
|
|
82
|
+
}
|
|
83
|
+
export function handleNavFocus(context, key) {
|
|
84
|
+
const { state, render, load } = context;
|
|
85
|
+
if (key === "j" || key === "\x1b[B") {
|
|
86
|
+
state.navIndex = Math.min(navItems.length - 1, state.navIndex + 1);
|
|
87
|
+
void load();
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
if (key === "k" || key === "\x1b[A") {
|
|
91
|
+
state.navIndex = Math.max(0, state.navIndex - 1);
|
|
92
|
+
void load();
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
if (key === "l" || key === "\x1b[C" || key === "\r") {
|
|
96
|
+
if (!state.loading && (state.items.length > 0 || state.currentSearch)) {
|
|
97
|
+
enterContentMode(state, key === "\r");
|
|
98
|
+
render();
|
|
99
|
+
}
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
if (key === "r") {
|
|
103
|
+
void load(true);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
export function handleContentFocus(context, key) {
|
|
107
|
+
const { state, render, client, nextSignal, abortCurrent, load } = context;
|
|
108
|
+
if (state.currentSearch) {
|
|
109
|
+
handleSearchContentFocus(context, key);
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
if (key === "j" || key === "\x1b[B") {
|
|
113
|
+
state.itemIndex = Math.min(Math.max(0, state.items.length - 1), state.itemIndex + 1);
|
|
114
|
+
render();
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
if (key === "k" || key === "\x1b[A") {
|
|
118
|
+
state.itemIndex = Math.max(0, state.itemIndex - 1);
|
|
119
|
+
render();
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
if (key === "h" || key === "\x1b[D" || key === "\x1b") {
|
|
123
|
+
abortCurrent();
|
|
124
|
+
leaveContentMode(state);
|
|
125
|
+
render();
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
if (key === "l" || key === "\x1b[C" || key === "\r") {
|
|
129
|
+
if (openSelectedItem(context)) {
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
state.status = "当前条目不可进入";
|
|
133
|
+
render();
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
if ((key === "n" || key === " ") && state.currentChat) {
|
|
137
|
+
void loadNextChatPage(client, state, render, nextSignal());
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
if (key === "r") {
|
|
141
|
+
if (state.currentBoard) {
|
|
142
|
+
void openBoard(client, state, state.currentBoard.boardId, state.currentBoard.title, render, true, nextSignal(), false);
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
if (state.currentChat) {
|
|
146
|
+
void openChat(client, state, state.currentChat.userId, state.currentChat.title, render, true, nextSignal(), false);
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
void load(true);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
export function handleSearchContentFocus(context, key) {
|
|
153
|
+
const { state, render, client, nextSignal, abortCurrent, load } = context;
|
|
154
|
+
const search = state.currentSearch;
|
|
155
|
+
if (!search) {
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
if (key === "h" || key === "\x1b[D" || key === "\x1b") {
|
|
159
|
+
abortCurrent();
|
|
160
|
+
leaveContentMode(state);
|
|
161
|
+
render();
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
if (search.focus === "input") {
|
|
165
|
+
if (key === "\x7f") {
|
|
166
|
+
search.draft = search.draft.slice(0, -1);
|
|
167
|
+
render();
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
if (key === "\r") {
|
|
171
|
+
void executeSearch(client, state, render, false, nextSignal());
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
if ((key === "j" || key === "\x1b[B" || key === "\t") && state.items.length > 0) {
|
|
175
|
+
search.focus = "results";
|
|
176
|
+
render();
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
if (key === "r" && search.query) {
|
|
180
|
+
search.draft = search.query;
|
|
181
|
+
void executeSearch(client, state, render, true, nextSignal());
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
if (isPrintableInput(key)) {
|
|
185
|
+
search.draft = `${search.draft}${key}`;
|
|
186
|
+
render();
|
|
187
|
+
}
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
if (key === "i" || key === "/" || key === "\t") {
|
|
191
|
+
search.focus = "input";
|
|
192
|
+
render();
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
if (key === "j" || key === "\x1b[B") {
|
|
196
|
+
const wasAtEnd = isAtSearchEnd(state);
|
|
197
|
+
state.itemIndex = Math.min(Math.max(0, state.items.length - 1), state.itemIndex + 1);
|
|
198
|
+
render();
|
|
199
|
+
if (wasAtEnd && search.hasMore && !state.loadingMore && !state.loading) {
|
|
200
|
+
void loadNextSearchPage(client, state, render, nextSignal());
|
|
201
|
+
}
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
if (key === "k" || key === "\x1b[A") {
|
|
205
|
+
if (state.itemIndex === 0) {
|
|
206
|
+
search.focus = "input";
|
|
207
|
+
}
|
|
208
|
+
else {
|
|
209
|
+
state.itemIndex = Math.max(0, state.itemIndex - 1);
|
|
210
|
+
}
|
|
211
|
+
render();
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
if (key === "l" || key === "\x1b[C" || key === "\r") {
|
|
215
|
+
if (openSelectedItem(context)) {
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
state.status = "当前条目不可进入";
|
|
219
|
+
render();
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
if (key === "n" || key === " ") {
|
|
223
|
+
void loadNextSearchPage(client, state, render, nextSignal());
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
if (key === "r") {
|
|
227
|
+
if (search.query) {
|
|
228
|
+
search.draft = search.query;
|
|
229
|
+
void executeSearch(client, state, render, true, nextSignal());
|
|
230
|
+
return;
|
|
231
|
+
}
|
|
232
|
+
void load(true);
|
|
233
|
+
return;
|
|
234
|
+
}
|
|
235
|
+
if (isPrintableInput(key)) {
|
|
236
|
+
search.focus = "input";
|
|
237
|
+
search.draft = `${search.draft}${key}`;
|
|
238
|
+
render();
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
export function isAtSearchEnd(state) {
|
|
242
|
+
return Boolean(state.currentSearch &&
|
|
243
|
+
state.currentSearch.focus === "results" &&
|
|
244
|
+
state.items.length > 0 &&
|
|
245
|
+
state.itemIndex >= state.items.length - 1);
|
|
246
|
+
}
|
|
247
|
+
export function getContentListScroll(state, visibleCapacity) {
|
|
248
|
+
const maxScroll = Math.max(0, state.items.length - visibleCapacity);
|
|
249
|
+
const current = Math.min(Math.max(0, state.scroll), maxScroll);
|
|
250
|
+
if (state.itemIndex < current) {
|
|
251
|
+
return state.itemIndex;
|
|
252
|
+
}
|
|
253
|
+
if (state.itemIndex >= current + visibleCapacity) {
|
|
254
|
+
return Math.min(maxScroll, state.itemIndex - visibleCapacity + 1);
|
|
255
|
+
}
|
|
256
|
+
return current;
|
|
257
|
+
}
|
|
258
|
+
function openSelectedItem(context) {
|
|
259
|
+
const { state, render, client, config, nextSignal } = context;
|
|
260
|
+
const selected = state.items[state.itemIndex];
|
|
261
|
+
if (selected?.topicId !== undefined) {
|
|
262
|
+
void openTopic(client, state, selected.topicId, render, config, false, nextSignal());
|
|
263
|
+
return true;
|
|
264
|
+
}
|
|
265
|
+
if (selected?.boardId !== undefined) {
|
|
266
|
+
void openBoard(client, state, selected.boardId, selected.title, render, false, nextSignal());
|
|
267
|
+
return true;
|
|
268
|
+
}
|
|
269
|
+
if (selected?.chatUserId !== undefined) {
|
|
270
|
+
void openChat(client, state, selected.chatUserId, selected.title, render, false, nextSignal());
|
|
271
|
+
return true;
|
|
272
|
+
}
|
|
273
|
+
return false;
|
|
274
|
+
}
|
|
275
|
+
//# sourceMappingURL=content.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"content.js","sourceRoot":"","sources":["../../../src/tui/app-runtime/content.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { TuiConfig } from "../../config.js";
|
|
2
|
+
import type { Cc98Client } from "../../api/client.js";
|
|
3
|
+
import type { TokenStore } from "../../storage/token-store.js";
|
|
4
|
+
import type { CachedCc98Client } from "../cached-client.js";
|
|
5
|
+
import type { TuiKeymap } from "../keymap.js";
|
|
6
|
+
import type { TuiState } from "../tui-model.js";
|
|
7
|
+
export interface RuntimeContext {
|
|
8
|
+
client: CachedCc98Client;
|
|
9
|
+
rawClient: Cc98Client;
|
|
10
|
+
tokenStore: TokenStore;
|
|
11
|
+
config: TuiConfig;
|
|
12
|
+
keymap: TuiKeymap;
|
|
13
|
+
state: TuiState;
|
|
14
|
+
getSize: () => {
|
|
15
|
+
columns: number;
|
|
16
|
+
rows: number;
|
|
17
|
+
};
|
|
18
|
+
render: () => void;
|
|
19
|
+
load: (force?: boolean) => Promise<void>;
|
|
20
|
+
nextSignal: () => AbortSignal;
|
|
21
|
+
abortCurrent: () => void;
|
|
22
|
+
close: () => void;
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=context.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../../src/tui/app-runtime/context.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACtD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAC;AAC/D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAEhD,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,gBAAgB,CAAC;IACzB,SAAS,EAAE,UAAU,CAAC;IACtB,UAAU,EAAE,UAAU,CAAC;IACvB,MAAM,EAAE,SAAS,CAAC;IAClB,MAAM,EAAE,SAAS,CAAC;IAClB,KAAK,EAAE,QAAQ,CAAC;IAChB,OAAO,EAAE,MAAM;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IACjD,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,IAAI,EAAE,CAAC,KAAK,CAAC,EAAE,OAAO,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACzC,UAAU,EAAE,MAAM,WAAW,CAAC;IAC9B,YAAY,EAAE,MAAM,IAAI,CAAC;IACzB,KAAK,EAAE,MAAM,IAAI,CAAC;CACnB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context.js","sourceRoot":"","sources":["../../../src/tui/app-runtime/context.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { RuntimeContext } from "./context.js";
|
|
2
|
+
export declare function handleImageModal(context: RuntimeContext, key: string): void;
|
|
3
|
+
export declare function openTopicImageViewer(context: RuntimeContext): Promise<void>;
|
|
4
|
+
export declare function stepTopicImageViewer(context: RuntimeContext, delta: number): Promise<void>;
|
|
5
|
+
//# sourceMappingURL=image-viewer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"image-viewer.d.ts","sourceRoot":"","sources":["../../../src/tui/app-runtime/image-viewer.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAEnD,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,cAAc,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI,CAoB3E;AAED,wBAAsB,oBAAoB,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAmCjF;AAED,wBAAsB,oBAAoB,CAAC,OAAO,EAAE,cAAc,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAiBhG"}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { isEmotionAssetPath } from "../emotion-preview.js";
|
|
2
|
+
import { loadModalImagePreview, supportsImagePreview } from "../image-preview.js";
|
|
3
|
+
import { currentTopicLine, currentTopicPost, getStatus } from "../tui-model.js";
|
|
4
|
+
export function handleImageModal(context, key) {
|
|
5
|
+
const { state, render } = context;
|
|
6
|
+
if (!state.imageViewer) {
|
|
7
|
+
state.modal = null;
|
|
8
|
+
render();
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
if (key === " " || key === "\x1b" || key === "h" || key === "\r") {
|
|
12
|
+
state.modal = null;
|
|
13
|
+
state.status = getStatus(state);
|
|
14
|
+
render();
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
if (key === "\x1b[C" || key === "l") {
|
|
18
|
+
void stepTopicImageViewer(context, 1);
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
if (key === "\x1b[D" || key === "k") {
|
|
22
|
+
void stepTopicImageViewer(context, -1);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
export async function openTopicImageViewer(context) {
|
|
26
|
+
const { state, render } = context;
|
|
27
|
+
const topic = state.topic;
|
|
28
|
+
if (!topic) {
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
if (!supportsImagePreview()) {
|
|
32
|
+
state.status = "当前终端不支持图片大图预览";
|
|
33
|
+
render();
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
const images = topic.posts
|
|
37
|
+
.flatMap((post) => post.images)
|
|
38
|
+
.filter((url) => !isEmotionAssetPath(url));
|
|
39
|
+
if (images.length === 0) {
|
|
40
|
+
state.status = "当前帖子没有可预览的大图";
|
|
41
|
+
render();
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
const currentLine = currentTopicLine(topic, state.scroll);
|
|
45
|
+
const currentPost = currentTopicPost(topic, state.scroll);
|
|
46
|
+
const targetUrl = !isEmotionAssetPath(currentLine?.imageUrl ?? "")
|
|
47
|
+
? currentLine?.imageUrl
|
|
48
|
+
: currentPost?.images.find((url) => !isEmotionAssetPath(url)) ?? images[0];
|
|
49
|
+
const index = Math.max(0, images.findIndex((url) => url === targetUrl));
|
|
50
|
+
state.imageViewer = {
|
|
51
|
+
images,
|
|
52
|
+
index,
|
|
53
|
+
loading: true
|
|
54
|
+
};
|
|
55
|
+
state.modal = "image";
|
|
56
|
+
render();
|
|
57
|
+
await refreshTopicImageViewer(context, index);
|
|
58
|
+
}
|
|
59
|
+
export async function stepTopicImageViewer(context, delta) {
|
|
60
|
+
const viewer = context.state.imageViewer;
|
|
61
|
+
if (!viewer || viewer.images.length === 0) {
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
const nextIndex = Math.min(viewer.images.length - 1, Math.max(0, viewer.index + delta));
|
|
65
|
+
if (nextIndex === viewer.index && viewer.token) {
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
viewer.index = nextIndex;
|
|
69
|
+
viewer.loading = true;
|
|
70
|
+
viewer.error = undefined;
|
|
71
|
+
viewer.token = undefined;
|
|
72
|
+
viewer.renderSize = undefined;
|
|
73
|
+
context.state.modal = "image";
|
|
74
|
+
context.render();
|
|
75
|
+
await refreshTopicImageViewer(context, nextIndex);
|
|
76
|
+
}
|
|
77
|
+
async function refreshTopicImageViewer(context, index) {
|
|
78
|
+
const { state, render } = context;
|
|
79
|
+
const viewer = state.imageViewer;
|
|
80
|
+
if (!viewer) {
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
const terminalSize = process.stdout.isTTY
|
|
84
|
+
? { columns: process.stdout.columns || 80, rows: process.stdout.rows || 24 }
|
|
85
|
+
: { columns: 80, rows: 24 };
|
|
86
|
+
const modalWidth = Math.max(24, Math.min(terminalSize.columns - 4, Math.floor(terminalSize.columns * 0.92)));
|
|
87
|
+
const modalHeight = Math.max(10, Math.min(terminalSize.rows - 2, Math.floor(terminalSize.rows * 0.9)));
|
|
88
|
+
const maxColumns = Math.max(1, modalWidth - 2);
|
|
89
|
+
const maxRows = Math.max(1, modalHeight - 2);
|
|
90
|
+
const url = viewer.images[index];
|
|
91
|
+
try {
|
|
92
|
+
const loadedImage = await loadModalImagePreview(url ?? "", maxColumns, maxRows);
|
|
93
|
+
if (!state.imageViewer || state.imageViewer.index !== index) {
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
state.imageViewer.loading = false;
|
|
97
|
+
state.imageViewer.token = loadedImage?.token;
|
|
98
|
+
state.imageViewer.renderSize = loadedImage?.size;
|
|
99
|
+
state.imageViewer.error = loadedImage ? undefined : "当前终端无法显示这张图片";
|
|
100
|
+
}
|
|
101
|
+
catch (error) {
|
|
102
|
+
if (!state.imageViewer || state.imageViewer.index !== index) {
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
state.imageViewer.loading = false;
|
|
106
|
+
state.imageViewer.token = undefined;
|
|
107
|
+
state.imageViewer.renderSize = undefined;
|
|
108
|
+
state.imageViewer.error = error instanceof Error ? error.message : "图片加载失败";
|
|
109
|
+
}
|
|
110
|
+
render();
|
|
111
|
+
}
|
|
112
|
+
//# sourceMappingURL=image-viewer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"image-viewer.js","sourceRoot":"","sources":["../../../src/tui/app-runtime/image-viewer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { MouseEvent } from "../terminal.js";
|
|
2
|
+
import type { RuntimeContext } from "./context.js";
|
|
3
|
+
export declare function handleTopicClick(context: RuntimeContext, event: MouseEvent, columns: number, rows: number): Promise<void>;
|
|
4
|
+
export declare function handleSidebarClick(context: RuntimeContext, event: MouseEvent, columns: number, rows: number): boolean;
|
|
5
|
+
export declare function handleContentClick(context: RuntimeContext, event: MouseEvent, columns: number, rows: number): boolean;
|
|
6
|
+
//# sourceMappingURL=interactions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interactions.d.ts","sourceRoot":"","sources":["../../../src/tui/app-runtime/interactions.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAInD,wBAAsB,gBAAgB,CACpC,OAAO,EAAE,cAAc,EACvB,KAAK,EAAE,UAAU,EACjB,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,IAAI,CAAC,CAqCf;AAED,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,cAAc,EACvB,KAAK,EAAE,UAAU,EACjB,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,GACX,OAAO,CA+BT;AAED,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,cAAc,EACvB,KAAK,EAAE,UAAU,EACjB,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,GACX,OAAO,CAyET"}
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
import { downloadUrlToDownloads } from "../downloads.js";
|
|
2
|
+
import { fill, length, pad, rect, split } from "../layout.js";
|
|
3
|
+
import { getSidebarWidth } from "../renderer.js";
|
|
4
|
+
import { getStatus, navItems, settingsItems } from "../tui-model.js";
|
|
5
|
+
import { getContentListScroll } from "./content.js";
|
|
6
|
+
import { enterContentMode, showNotification } from "./state.js";
|
|
7
|
+
export async function handleTopicClick(context, event, columns, rows) {
|
|
8
|
+
const { state, render } = context;
|
|
9
|
+
if (state.mode !== "topic" || !state.topic || state.loading || state.error) {
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
const mainArea = getMainAreaRect(columns, rows, context.config, state.sidebarWidth);
|
|
13
|
+
if (!withinRect(event.column, event.row, mainArea)) {
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
const bodyRow = event.row - (mainArea.y + 1);
|
|
17
|
+
const bodyLineIndex = bodyRow - 3;
|
|
18
|
+
if (bodyLineIndex < 0) {
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
const absoluteLine = state.scroll + bodyLineIndex;
|
|
22
|
+
const lineEntry = state.topic.posts
|
|
23
|
+
.flatMap((post) => post.lines)
|
|
24
|
+
.find((entry) => entry.line === absoluteLine);
|
|
25
|
+
const url = lineEntry?.linkUrl ?? lineEntry?.imageUrl;
|
|
26
|
+
if (!url) {
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
state.status = `正在下载 ${shortUrl(url)}...`;
|
|
30
|
+
render();
|
|
31
|
+
try {
|
|
32
|
+
const savedPath = await downloadUrlToDownloads(url);
|
|
33
|
+
showNotification(state, `已下载到 ${savedPath}`);
|
|
34
|
+
}
|
|
35
|
+
catch (error) {
|
|
36
|
+
state.status = error instanceof Error ? error.message : "下载失败";
|
|
37
|
+
}
|
|
38
|
+
finally {
|
|
39
|
+
render();
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
export function handleSidebarClick(context, event, columns, rows) {
|
|
43
|
+
const { state, render, load, abortCurrent } = context;
|
|
44
|
+
if (state.mode === "topic") {
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
const sidebarArea = getSidebarAreaRect(columns, rows, context.config, state.sidebarWidth);
|
|
48
|
+
if (sidebarArea.width <= 0 || !withinRect(event.column, event.row, sidebarArea)) {
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
const rowIndex = event.row - (sidebarArea.y + 1);
|
|
52
|
+
if (rowIndex < 0 || rowIndex >= navItems.length) {
|
|
53
|
+
return true;
|
|
54
|
+
}
|
|
55
|
+
const nextNavIndex = Math.max(0, Math.min(navItems.length - 1, rowIndex));
|
|
56
|
+
if (state.navIndex === nextNavIndex && state.focus === "nav" && state.mode !== "settings") {
|
|
57
|
+
return true;
|
|
58
|
+
}
|
|
59
|
+
abortCurrent();
|
|
60
|
+
state.navIndex = nextNavIndex;
|
|
61
|
+
state.focus = "nav";
|
|
62
|
+
if (state.mode === "settings") {
|
|
63
|
+
state.mode = "list";
|
|
64
|
+
}
|
|
65
|
+
state.status = getStatus(state);
|
|
66
|
+
render();
|
|
67
|
+
void load();
|
|
68
|
+
return true;
|
|
69
|
+
}
|
|
70
|
+
export function handleContentClick(context, event, columns, rows) {
|
|
71
|
+
const { state, render } = context;
|
|
72
|
+
if (state.mode === "topic" || state.loading || state.error) {
|
|
73
|
+
return false;
|
|
74
|
+
}
|
|
75
|
+
const mainArea = getMainAreaRect(columns, rows, context.config, state.sidebarWidth);
|
|
76
|
+
if (!withinRect(event.column, event.row, mainArea)) {
|
|
77
|
+
return false;
|
|
78
|
+
}
|
|
79
|
+
if (navItems[state.navIndex]?.id === "settings" && state.mode !== "settings") {
|
|
80
|
+
state.mode = "settings";
|
|
81
|
+
}
|
|
82
|
+
if (state.mode === "settings") {
|
|
83
|
+
const rowIndex = event.row - (mainArea.y + 1) - 2;
|
|
84
|
+
if (rowIndex < 0 || rowIndex >= settingsItems.length) {
|
|
85
|
+
return true;
|
|
86
|
+
}
|
|
87
|
+
state.itemIndex = rowIndex;
|
|
88
|
+
enterContentMode(state);
|
|
89
|
+
render();
|
|
90
|
+
return true;
|
|
91
|
+
}
|
|
92
|
+
if (state.currentSearch) {
|
|
93
|
+
const rowIndex = event.row - (mainArea.y + 1);
|
|
94
|
+
if (rowIndex === 1) {
|
|
95
|
+
state.currentSearch.focus = "input";
|
|
96
|
+
enterContentMode(state);
|
|
97
|
+
render();
|
|
98
|
+
return true;
|
|
99
|
+
}
|
|
100
|
+
if (rowIndex < 3) {
|
|
101
|
+
return true;
|
|
102
|
+
}
|
|
103
|
+
const itemHeight = 2;
|
|
104
|
+
const visibleCapacity = Math.max(1, Math.floor(Math.max(1, mainArea.height - 3) / itemHeight));
|
|
105
|
+
const scroll = getContentListScroll(state, visibleCapacity);
|
|
106
|
+
const itemOffset = Math.floor((rowIndex - 3) / itemHeight);
|
|
107
|
+
const itemIndex = scroll + itemOffset;
|
|
108
|
+
if (itemIndex < 0 || itemIndex >= state.items.length) {
|
|
109
|
+
return true;
|
|
110
|
+
}
|
|
111
|
+
state.itemIndex = itemIndex;
|
|
112
|
+
state.currentSearch.focus = "results";
|
|
113
|
+
enterContentMode(state);
|
|
114
|
+
render();
|
|
115
|
+
return true;
|
|
116
|
+
}
|
|
117
|
+
const rowIndex = event.row - (mainArea.y + 1) - 2;
|
|
118
|
+
if (rowIndex < 0) {
|
|
119
|
+
return true;
|
|
120
|
+
}
|
|
121
|
+
const itemHeight = 2;
|
|
122
|
+
if (rowIndex % itemHeight !== 0 && rowIndex % itemHeight !== 1) {
|
|
123
|
+
return true;
|
|
124
|
+
}
|
|
125
|
+
const visibleCapacity = Math.max(1, Math.floor(Math.max(1, mainArea.height - 2) / itemHeight));
|
|
126
|
+
const scroll = getContentListScroll(state, visibleCapacity);
|
|
127
|
+
const itemOffset = Math.floor(rowIndex / itemHeight);
|
|
128
|
+
const itemIndex = scroll + itemOffset;
|
|
129
|
+
if (itemIndex < 0 || itemIndex >= state.items.length) {
|
|
130
|
+
return true;
|
|
131
|
+
}
|
|
132
|
+
state.itemIndex = itemIndex;
|
|
133
|
+
enterContentMode(state);
|
|
134
|
+
render();
|
|
135
|
+
return true;
|
|
136
|
+
}
|
|
137
|
+
function getMainAreaRect(columns, rows, config, sidebarWidthOverride) {
|
|
138
|
+
const { mainArea } = getBodyColumnRects(columns, rows, config, sidebarWidthOverride);
|
|
139
|
+
return mainArea;
|
|
140
|
+
}
|
|
141
|
+
function getSidebarAreaRect(columns, rows, config, sidebarWidthOverride) {
|
|
142
|
+
const { sidebarArea } = getBodyColumnRects(columns, rows, config, sidebarWidthOverride);
|
|
143
|
+
return sidebarArea;
|
|
144
|
+
}
|
|
145
|
+
function getBodyColumnRects(columns, rows, config, sidebarWidthOverride) {
|
|
146
|
+
const width = Math.max(1, columns);
|
|
147
|
+
const height = Math.max(1, rows);
|
|
148
|
+
const outer = rect(width, Math.max(0, height - 1));
|
|
149
|
+
const root = pad(outer, 1);
|
|
150
|
+
const verticalLayout = config.hideTopChrome
|
|
151
|
+
? [fill()]
|
|
152
|
+
: [length(1), length(1), length(1), length(1), fill()];
|
|
153
|
+
const areas = split(root, "vertical", verticalLayout);
|
|
154
|
+
const bodyArea = config.hideTopChrome ? areas[0] : areas[4];
|
|
155
|
+
const sidebarWidth = getSidebarWidth(width, sidebarWidthOverride);
|
|
156
|
+
const bodyColumns = split(bodyArea, "horizontal", [
|
|
157
|
+
length(sidebarWidth),
|
|
158
|
+
length(sidebarWidth > 0 ? 1 : 0),
|
|
159
|
+
fill()
|
|
160
|
+
]);
|
|
161
|
+
return {
|
|
162
|
+
sidebarArea: bodyColumns[0],
|
|
163
|
+
mainArea: bodyColumns[2]
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
function withinRect(column, row, area) {
|
|
167
|
+
const x = column - 1;
|
|
168
|
+
const y = row - 1;
|
|
169
|
+
return x >= area.x && x < area.x + area.width && y >= area.y && y < area.y + area.height;
|
|
170
|
+
}
|
|
171
|
+
function shortUrl(value) {
|
|
172
|
+
try {
|
|
173
|
+
const url = new URL(value);
|
|
174
|
+
const fileName = url.pathname.split("/").filter(Boolean).at(-1) ?? url.host;
|
|
175
|
+
return `${url.host}/${fileName}`;
|
|
176
|
+
}
|
|
177
|
+
catch {
|
|
178
|
+
return value;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
//# sourceMappingURL=interactions.js.map
|