@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.
Files changed (247) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/README.md +11 -3
  3. package/assets/forum-images/ac-dark/01.png +0 -0
  4. package/assets/forum-images/ac-dark/02.png +0 -0
  5. package/assets/forum-images/ac-dark/03.png +0 -0
  6. package/assets/forum-images/ac-dark/04.png +0 -0
  7. package/assets/forum-images/ac-dark/05.png +0 -0
  8. package/assets/forum-images/ac-dark/06.png +0 -0
  9. package/assets/forum-images/ac-dark/07.png +0 -0
  10. package/assets/forum-images/ac-dark/08.png +0 -0
  11. package/assets/forum-images/ac-dark/09.png +0 -0
  12. package/assets/forum-images/ac-dark/10.png +0 -0
  13. package/assets/forum-images/ac-dark/1001.png +0 -0
  14. package/assets/forum-images/ac-dark/1002.png +0 -0
  15. package/assets/forum-images/ac-dark/1003.png +0 -0
  16. package/assets/forum-images/ac-dark/1004.png +0 -0
  17. package/assets/forum-images/ac-dark/1005.png +0 -0
  18. package/assets/forum-images/ac-dark/1006.png +0 -0
  19. package/assets/forum-images/ac-dark/1007.png +0 -0
  20. package/assets/forum-images/ac-dark/1008.png +0 -0
  21. package/assets/forum-images/ac-dark/1009.png +0 -0
  22. package/assets/forum-images/ac-dark/1010.png +0 -0
  23. package/assets/forum-images/ac-dark/1011.png +0 -0
  24. package/assets/forum-images/ac-dark/1012.png +0 -0
  25. package/assets/forum-images/ac-dark/1013.png +0 -0
  26. package/assets/forum-images/ac-dark/1014.png +0 -0
  27. package/assets/forum-images/ac-dark/1015.png +0 -0
  28. package/assets/forum-images/ac-dark/1016.png +0 -0
  29. package/assets/forum-images/ac-dark/1017.png +0 -0
  30. package/assets/forum-images/ac-dark/1018.png +0 -0
  31. package/assets/forum-images/ac-dark/1019.png +0 -0
  32. package/assets/forum-images/ac-dark/1020.png +0 -0
  33. package/assets/forum-images/ac-dark/1021.png +0 -0
  34. package/assets/forum-images/ac-dark/1022.png +0 -0
  35. package/assets/forum-images/ac-dark/1023.png +0 -0
  36. package/assets/forum-images/ac-dark/1024.png +0 -0
  37. package/assets/forum-images/ac-dark/1025.png +0 -0
  38. package/assets/forum-images/ac-dark/1026.png +0 -0
  39. package/assets/forum-images/ac-dark/1027.png +0 -0
  40. package/assets/forum-images/ac-dark/1028.png +0 -0
  41. package/assets/forum-images/ac-dark/1029.png +0 -0
  42. package/assets/forum-images/ac-dark/1030.png +0 -0
  43. package/assets/forum-images/ac-dark/1031.png +0 -0
  44. package/assets/forum-images/ac-dark/1032.png +0 -0
  45. package/assets/forum-images/ac-dark/1033.png +0 -0
  46. package/assets/forum-images/ac-dark/1034.png +0 -0
  47. package/assets/forum-images/ac-dark/1035.png +0 -0
  48. package/assets/forum-images/ac-dark/1036.png +0 -0
  49. package/assets/forum-images/ac-dark/1037.png +0 -0
  50. package/assets/forum-images/ac-dark/1038.png +0 -0
  51. package/assets/forum-images/ac-dark/1039.png +0 -0
  52. package/assets/forum-images/ac-dark/1040.png +0 -0
  53. package/assets/forum-images/ac-dark/11.png +0 -0
  54. package/assets/forum-images/ac-dark/12.png +0 -0
  55. package/assets/forum-images/ac-dark/13.png +0 -0
  56. package/assets/forum-images/ac-dark/14.png +0 -0
  57. package/assets/forum-images/ac-dark/15.png +0 -0
  58. package/assets/forum-images/ac-dark/16.png +0 -0
  59. package/assets/forum-images/ac-dark/17.png +0 -0
  60. package/assets/forum-images/ac-dark/18.png +0 -0
  61. package/assets/forum-images/ac-dark/19.png +0 -0
  62. package/assets/forum-images/ac-dark/20.png +0 -0
  63. package/assets/forum-images/ac-dark/2001.png +0 -0
  64. package/assets/forum-images/ac-dark/2002.png +0 -0
  65. package/assets/forum-images/ac-dark/2003.png +0 -0
  66. package/assets/forum-images/ac-dark/2004.png +0 -0
  67. package/assets/forum-images/ac-dark/2005.png +0 -0
  68. package/assets/forum-images/ac-dark/2006.png +0 -0
  69. package/assets/forum-images/ac-dark/2007.png +0 -0
  70. package/assets/forum-images/ac-dark/2008.png +0 -0
  71. package/assets/forum-images/ac-dark/2009.png +0 -0
  72. package/assets/forum-images/ac-dark/2010.png +0 -0
  73. package/assets/forum-images/ac-dark/2011.png +0 -0
  74. package/assets/forum-images/ac-dark/2012.png +0 -0
  75. package/assets/forum-images/ac-dark/2013.png +0 -0
  76. package/assets/forum-images/ac-dark/2014.png +0 -0
  77. package/assets/forum-images/ac-dark/2015.png +0 -0
  78. package/assets/forum-images/ac-dark/2016.png +0 -0
  79. package/assets/forum-images/ac-dark/2017.png +0 -0
  80. package/assets/forum-images/ac-dark/2018.png +0 -0
  81. package/assets/forum-images/ac-dark/2019.png +0 -0
  82. package/assets/forum-images/ac-dark/2020.png +0 -0
  83. package/assets/forum-images/ac-dark/2021.png +0 -0
  84. package/assets/forum-images/ac-dark/2022.png +0 -0
  85. package/assets/forum-images/ac-dark/2023.png +0 -0
  86. package/assets/forum-images/ac-dark/2024.png +0 -0
  87. package/assets/forum-images/ac-dark/2025.png +0 -0
  88. package/assets/forum-images/ac-dark/2026.png +0 -0
  89. package/assets/forum-images/ac-dark/2027.png +0 -0
  90. package/assets/forum-images/ac-dark/2028.png +0 -0
  91. package/assets/forum-images/ac-dark/2029.png +0 -0
  92. package/assets/forum-images/ac-dark/2030.png +0 -0
  93. package/assets/forum-images/ac-dark/2031.png +0 -0
  94. package/assets/forum-images/ac-dark/2032.png +0 -0
  95. package/assets/forum-images/ac-dark/2033.png +0 -0
  96. package/assets/forum-images/ac-dark/2034.png +0 -0
  97. package/assets/forum-images/ac-dark/2035.png +0 -0
  98. package/assets/forum-images/ac-dark/2036.png +0 -0
  99. package/assets/forum-images/ac-dark/2037.png +0 -0
  100. package/assets/forum-images/ac-dark/2038.png +0 -0
  101. package/assets/forum-images/ac-dark/2039.png +0 -0
  102. package/assets/forum-images/ac-dark/2040.png +0 -0
  103. package/assets/forum-images/ac-dark/2041.png +0 -0
  104. package/assets/forum-images/ac-dark/2042.png +0 -0
  105. package/assets/forum-images/ac-dark/2043.png +0 -0
  106. package/assets/forum-images/ac-dark/2044.png +0 -0
  107. package/assets/forum-images/ac-dark/2045.png +0 -0
  108. package/assets/forum-images/ac-dark/2046.png +0 -0
  109. package/assets/forum-images/ac-dark/2047.png +0 -0
  110. package/assets/forum-images/ac-dark/2048.png +0 -0
  111. package/assets/forum-images/ac-dark/2049.png +0 -0
  112. package/assets/forum-images/ac-dark/2050.png +0 -0
  113. package/assets/forum-images/ac-dark/2051.png +0 -0
  114. package/assets/forum-images/ac-dark/2052.png +0 -0
  115. package/assets/forum-images/ac-dark/2053.png +0 -0
  116. package/assets/forum-images/ac-dark/2054.png +0 -0
  117. package/assets/forum-images/ac-dark/2055.png +0 -0
  118. package/assets/forum-images/ac-dark/21.png +0 -0
  119. package/assets/forum-images/ac-dark/22.png +0 -0
  120. package/assets/forum-images/ac-dark/23.png +0 -0
  121. package/assets/forum-images/ac-dark/24.png +0 -0
  122. package/assets/forum-images/ac-dark/25.png +0 -0
  123. package/assets/forum-images/ac-dark/26.png +0 -0
  124. package/assets/forum-images/ac-dark/27.png +0 -0
  125. package/assets/forum-images/ac-dark/28.png +0 -0
  126. package/assets/forum-images/ac-dark/29.png +0 -0
  127. package/assets/forum-images/ac-dark/30.png +0 -0
  128. package/assets/forum-images/ac-dark/31.png +0 -0
  129. package/assets/forum-images/ac-dark/32.png +0 -0
  130. package/assets/forum-images/ac-dark/33.png +0 -0
  131. package/assets/forum-images/ac-dark/34.png +0 -0
  132. package/assets/forum-images/ac-dark/35.png +0 -0
  133. package/assets/forum-images/ac-dark/36.png +0 -0
  134. package/assets/forum-images/ac-dark/37.png +0 -0
  135. package/assets/forum-images/ac-dark/38.png +0 -0
  136. package/assets/forum-images/ac-dark/39.png +0 -0
  137. package/assets/forum-images/ac-dark/40.png +0 -0
  138. package/assets/forum-images/ac-dark/41.png +0 -0
  139. package/assets/forum-images/ac-dark/42.png +0 -0
  140. package/assets/forum-images/ac-dark/43.png +0 -0
  141. package/assets/forum-images/ac-dark/44.png +0 -0
  142. package/assets/forum-images/ac-dark/45.png +0 -0
  143. package/assets/forum-images/ac-dark/46.png +0 -0
  144. package/assets/forum-images/ac-dark/47.png +0 -0
  145. package/assets/forum-images/ac-dark/48.png +0 -0
  146. package/assets/forum-images/ac-dark/49.png +0 -0
  147. package/assets/forum-images/ac-dark/50.png +0 -0
  148. package/assets/forum-images/ac-dark/51.png +0 -0
  149. package/assets/forum-images/ac-dark/52.png +0 -0
  150. package/assets/forum-images/ac-dark/53.png +0 -0
  151. package/assets/forum-images/ac-dark/54.png +0 -0
  152. package/dist/api/client.d.ts +2 -1
  153. package/dist/api/client.d.ts.map +1 -1
  154. package/dist/api/client.js +19 -2
  155. package/dist/api/client.js.map +1 -1
  156. package/dist/api/endpoints.d.ts +1 -0
  157. package/dist/api/endpoints.d.ts.map +1 -1
  158. package/dist/api/endpoints.js +1 -0
  159. package/dist/api/endpoints.js.map +1 -1
  160. package/dist/config.d.ts +2 -0
  161. package/dist/config.d.ts.map +1 -1
  162. package/dist/config.js +25 -4
  163. package/dist/config.js.map +1 -1
  164. package/dist/tui/app-data.d.ts +4 -1
  165. package/dist/tui/app-data.d.ts.map +1 -1
  166. package/dist/tui/app-data.js +107 -0
  167. package/dist/tui/app-data.js.map +1 -1
  168. package/dist/tui/app-runtime/content.d.ts +9 -0
  169. package/dist/tui/app-runtime/content.d.ts.map +1 -0
  170. package/dist/tui/app-runtime/content.js +275 -0
  171. package/dist/tui/app-runtime/content.js.map +1 -0
  172. package/dist/tui/app-runtime/context.d.ts +24 -0
  173. package/dist/tui/app-runtime/context.d.ts.map +1 -0
  174. package/dist/tui/app-runtime/context.js +2 -0
  175. package/dist/tui/app-runtime/context.js.map +1 -0
  176. package/dist/tui/app-runtime/image-viewer.d.ts +5 -0
  177. package/dist/tui/app-runtime/image-viewer.d.ts.map +1 -0
  178. package/dist/tui/app-runtime/image-viewer.js +112 -0
  179. package/dist/tui/app-runtime/image-viewer.js.map +1 -0
  180. package/dist/tui/app-runtime/interactions.d.ts +6 -0
  181. package/dist/tui/app-runtime/interactions.d.ts.map +1 -0
  182. package/dist/tui/app-runtime/interactions.js +181 -0
  183. package/dist/tui/app-runtime/interactions.js.map +1 -0
  184. package/dist/tui/app-runtime/keyboard.d.ts +3 -0
  185. package/dist/tui/app-runtime/keyboard.d.ts.map +1 -0
  186. package/dist/tui/app-runtime/keyboard.js +284 -0
  187. package/dist/tui/app-runtime/keyboard.js.map +1 -0
  188. package/dist/tui/app-runtime/modals.d.ts +17 -0
  189. package/dist/tui/app-runtime/modals.d.ts.map +1 -0
  190. package/dist/tui/app-runtime/modals.js +343 -0
  191. package/dist/tui/app-runtime/modals.js.map +1 -0
  192. package/dist/tui/app-runtime/mouse.d.ts +5 -0
  193. package/dist/tui/app-runtime/mouse.d.ts.map +1 -0
  194. package/dist/tui/app-runtime/mouse.js +68 -0
  195. package/dist/tui/app-runtime/mouse.js.map +1 -0
  196. package/dist/tui/app-runtime/state.d.ts +6 -0
  197. package/dist/tui/app-runtime/state.d.ts.map +1 -0
  198. package/dist/tui/app-runtime/state.js +41 -0
  199. package/dist/tui/app-runtime/state.js.map +1 -0
  200. package/dist/tui/app-runtime/topic.d.ts +6 -0
  201. package/dist/tui/app-runtime/topic.d.ts.map +1 -0
  202. package/dist/tui/app-runtime/topic.js +184 -0
  203. package/dist/tui/app-runtime/topic.js.map +1 -0
  204. package/dist/tui/app-runtime.d.ts +2 -27
  205. package/dist/tui/app-runtime.d.ts.map +1 -1
  206. package/dist/tui/app-runtime.js +2 -960
  207. package/dist/tui/app-runtime.js.map +1 -1
  208. package/dist/tui/app.d.ts.map +1 -1
  209. package/dist/tui/app.js +5 -2
  210. package/dist/tui/app.js.map +1 -1
  211. package/dist/tui/cached-client.d.ts +2 -0
  212. package/dist/tui/cached-client.d.ts.map +1 -1
  213. package/dist/tui/cached-client.js +6 -0
  214. package/dist/tui/cached-client.js.map +1 -1
  215. package/dist/tui/emotion-catalog.d.ts +23 -0
  216. package/dist/tui/emotion-catalog.d.ts.map +1 -0
  217. package/dist/tui/emotion-catalog.js +150 -0
  218. package/dist/tui/emotion-catalog.js.map +1 -0
  219. package/dist/tui/emotion-preview.js +1 -1
  220. package/dist/tui/emotion-preview.js.map +1 -1
  221. package/dist/tui/image-preview.d.ts.map +1 -1
  222. package/dist/tui/image-preview.js +2 -1
  223. package/dist/tui/image-preview.js.map +1 -1
  224. package/dist/tui/keymap.d.ts +1 -1
  225. package/dist/tui/keymap.d.ts.map +1 -1
  226. package/dist/tui/keymap.js +5 -1
  227. package/dist/tui/keymap.js.map +1 -1
  228. package/dist/tui/renderer.d.ts.map +1 -1
  229. package/dist/tui/renderer.js +268 -4
  230. package/dist/tui/renderer.js.map +1 -1
  231. package/dist/tui/terminal.d.ts +3 -0
  232. package/dist/tui/terminal.d.ts.map +1 -1
  233. package/dist/tui/terminal.js +37 -0
  234. package/dist/tui/terminal.js.map +1 -1
  235. package/dist/tui/theme.d.ts +1 -0
  236. package/dist/tui/theme.d.ts.map +1 -1
  237. package/dist/tui/theme.js +1 -0
  238. package/dist/tui/theme.js.map +1 -1
  239. package/dist/tui/tui-model.d.ts +24 -2
  240. package/dist/tui/tui-model.d.ts.map +1 -1
  241. package/dist/tui/tui-model.js +12 -0
  242. package/dist/tui/tui-model.js.map +1 -1
  243. package/dist/tui/ubb-renderer.js +1 -1
  244. package/dist/tui/ubb-renderer.js.map +1 -1
  245. package/dist/version.d.ts +1 -1
  246. package/dist/version.js +1 -1
  247. 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,2 @@
1
+ export {};
2
+ //# sourceMappingURL=context.js.map
@@ -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