cc98-cli 0.4.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (82) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/dist/cli/commands/update.d.ts.map +1 -1
  3. package/dist/cli/commands/update.js +49 -3
  4. package/dist/cli/commands/update.js.map +1 -1
  5. package/dist/storage/settings-store.d.ts +12 -0
  6. package/dist/storage/settings-store.d.ts.map +1 -0
  7. package/dist/storage/settings-store.js +46 -0
  8. package/dist/storage/settings-store.js.map +1 -0
  9. package/dist/tui/ansi.d.ts.map +1 -1
  10. package/dist/tui/ansi.js +5 -1
  11. package/dist/tui/ansi.js.map +1 -1
  12. package/dist/tui/app.js +1 -1
  13. package/dist/tui/app.js.map +1 -1
  14. package/dist/tui/components/content.d.ts +2 -0
  15. package/dist/tui/components/content.d.ts.map +1 -1
  16. package/dist/tui/components/content.js +47 -9
  17. package/dist/tui/components/content.js.map +1 -1
  18. package/dist/tui/components/status.d.ts +3 -0
  19. package/dist/tui/components/status.d.ts.map +1 -1
  20. package/dist/tui/components/status.js +21 -8
  21. package/dist/tui/components/status.js.map +1 -1
  22. package/dist/tui/components/utils.d.ts.map +1 -1
  23. package/dist/tui/components/utils.js +33 -12
  24. package/dist/tui/components/utils.js.map +1 -1
  25. package/dist/tui/controller.d.ts +36 -1
  26. package/dist/tui/controller.d.ts.map +1 -1
  27. package/dist/tui/controller.js +802 -124
  28. package/dist/tui/controller.js.map +1 -1
  29. package/dist/tui/emoji-art.d.ts +11 -0
  30. package/dist/tui/emoji-art.d.ts.map +1 -0
  31. package/dist/tui/emoji-art.js +371 -0
  32. package/dist/tui/emoji-art.js.map +1 -0
  33. package/dist/tui/emoji-renderer.d.ts +16 -0
  34. package/dist/tui/emoji-renderer.d.ts.map +1 -0
  35. package/dist/tui/emoji-renderer.js +110 -0
  36. package/dist/tui/emoji-renderer.js.map +1 -0
  37. package/dist/tui/image-renderer.d.ts +46 -0
  38. package/dist/tui/image-renderer.d.ts.map +1 -0
  39. package/dist/tui/image-renderer.js +259 -0
  40. package/dist/tui/image-renderer.js.map +1 -0
  41. package/dist/tui/keybindings.d.ts +24 -0
  42. package/dist/tui/keybindings.d.ts.map +1 -0
  43. package/dist/tui/keybindings.js +207 -0
  44. package/dist/tui/keybindings.js.map +1 -0
  45. package/dist/tui/navigation.d.ts.map +1 -1
  46. package/dist/tui/navigation.js +4 -0
  47. package/dist/tui/navigation.js.map +1 -1
  48. package/dist/tui/renderer.d.ts.map +1 -1
  49. package/dist/tui/renderer.js +181 -11
  50. package/dist/tui/renderer.js.map +1 -1
  51. package/dist/tui/state/store.d.ts.map +1 -1
  52. package/dist/tui/state/store.js +13 -2
  53. package/dist/tui/state/store.js.map +1 -1
  54. package/dist/tui/state/types.d.ts +24 -0
  55. package/dist/tui/state/types.d.ts.map +1 -1
  56. package/dist/tui/terminal-capabilities.d.ts +24 -0
  57. package/dist/tui/terminal-capabilities.d.ts.map +1 -0
  58. package/dist/tui/terminal-capabilities.js +55 -0
  59. package/dist/tui/terminal-capabilities.js.map +1 -0
  60. package/dist/tui/terminal.js +1 -1
  61. package/dist/tui/terminal.js.map +1 -1
  62. package/dist/tui/topic-reader.d.ts +9 -1
  63. package/dist/tui/topic-reader.d.ts.map +1 -1
  64. package/dist/tui/topic-reader.js +30 -14
  65. package/dist/tui/topic-reader.js.map +1 -1
  66. package/dist/tui/ubb-renderer.d.ts +5 -1
  67. package/dist/tui/ubb-renderer.d.ts.map +1 -1
  68. package/dist/tui/ubb-renderer.js +71 -25
  69. package/dist/tui/ubb-renderer.js.map +1 -1
  70. package/dist/update.d.ts +4 -1
  71. package/dist/update.d.ts.map +1 -1
  72. package/dist/update.js +71 -11
  73. package/dist/update.js.map +1 -1
  74. package/dist/version.d.ts +2 -2
  75. package/dist/version.d.ts.map +1 -1
  76. package/dist/version.js +10 -2
  77. package/dist/version.js.map +1 -1
  78. package/package.json +2 -1
  79. package/dist/tui/components/layout.d.ts +0 -3
  80. package/dist/tui/components/layout.d.ts.map +0 -1
  81. package/dist/tui/components/layout.js +0 -453
  82. package/dist/tui/components/layout.js.map +0 -1
package/dist/update.d.ts CHANGED
@@ -12,6 +12,9 @@ export interface UpdateCheckResult {
12
12
  updateAvailable: boolean;
13
13
  message: string;
14
14
  }
15
+ export type InstallMethod = "npm" | "bun" | "source" | "unknown";
16
+ export declare function detectInstallMethod(): Promise<InstallMethod>;
17
+ export declare function performUpdate(method: InstallMethod): Promise<string>;
15
18
  export declare function checkForUpdate(): Promise<UpdateCheckResult>;
16
- export declare function formatUpdateResult(result: UpdateCheckResult): string;
19
+ export declare function formatUpdateResult(result: UpdateCheckResult, installMethod?: InstallMethod): string;
17
20
  //# sourceMappingURL=update.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"update.d.ts","sourceRoot":"","sources":["../src/update.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,iBAAiB;IAChC,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,eAAe,EAAE,OAAO,CAAC;IACzB,OAAO,EAAE,MAAM,CAAC;CACjB;AAYD,wBAAsB,cAAc,IAAI,OAAO,CAAC,iBAAiB,CAAC,CA6CjE;AAED,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,iBAAiB,GAAG,MAAM,CAoBpE"}
1
+ {"version":3,"file":"update.d.ts","sourceRoot":"","sources":["../src/update.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,iBAAiB;IAChC,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,eAAe,EAAE,OAAO,CAAC;IACzB,OAAO,EAAE,MAAM,CAAC;CACjB;AAYD,MAAM,MAAM,aAAa,GAAG,KAAK,GAAG,KAAK,GAAG,QAAQ,GAAG,SAAS,CAAC;AAEjE,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,aAAa,CAAC,CAgClE;AAED,wBAAsB,aAAa,CAAC,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,MAAM,CAAC,CAgB1E;AAcD,wBAAsB,cAAc,IAAI,OAAO,CAAC,iBAAiB,CAAC,CA6CjE;AAED,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,iBAAiB,EAAE,aAAa,CAAC,EAAE,aAAa,GAAG,MAAM,CAenG"}
package/dist/update.js CHANGED
@@ -1,5 +1,70 @@
1
+ import { execFile } from "node:child_process";
2
+ import { readFile } from "node:fs/promises";
3
+ import { join } from "node:path";
1
4
  import { appName, appVersion, repositoryName, repositoryOwner, repositoryUrl } from "./version.js";
2
5
  const latestReleaseApiUrl = `https://api.github.com/repos/${repositoryOwner}/${repositoryName}/releases/latest`;
6
+ export async function detectInstallMethod() {
7
+ // 检查是否是 npm 全局安装
8
+ try {
9
+ const npmGlobalDir = await execCommand("npm", ["root", "-g"]);
10
+ const currentFile = new URL(import.meta.url).pathname;
11
+ if (currentFile.includes(npmGlobalDir.trim())) {
12
+ return "npm";
13
+ }
14
+ }
15
+ catch {
16
+ // ignore
17
+ }
18
+ // 检查是否是 bun 全局安装
19
+ try {
20
+ const bunGlobalDir = await execCommand("bun", ["pm", "ls", "-g"]);
21
+ if (bunGlobalDir.includes(appName)) {
22
+ return "bun";
23
+ }
24
+ }
25
+ catch {
26
+ // ignore
27
+ }
28
+ // 检查 package.json 是否存在(源码安装)
29
+ try {
30
+ const currentDir = new URL("../..", import.meta.url).pathname;
31
+ await readFile(join(currentDir, "package.json"), "utf-8");
32
+ return "source";
33
+ }
34
+ catch {
35
+ // ignore
36
+ }
37
+ return "unknown";
38
+ }
39
+ export async function performUpdate(method) {
40
+ switch (method) {
41
+ case "npm":
42
+ return execCommand("npm", ["install", "-g", `${appName}`]);
43
+ case "bun":
44
+ return execCommand("bun", ["install", "-g", `${appName}`]);
45
+ case "source": {
46
+ const currentDir = new URL("../..", import.meta.url).pathname;
47
+ await execCommand("git", ["pull"], currentDir);
48
+ await execCommand("npm", ["install"], currentDir);
49
+ await execCommand("npm", ["run", "build"], currentDir);
50
+ return "源码更新完成";
51
+ }
52
+ default:
53
+ throw new Error("无法检测安装方式,请手动更新。");
54
+ }
55
+ }
56
+ function execCommand(command, args, cwd) {
57
+ return new Promise((resolve, reject) => {
58
+ execFile(command, args, { cwd }, (error, stdout, stderr) => {
59
+ if (error) {
60
+ reject(new Error(stderr || error.message));
61
+ }
62
+ else {
63
+ resolve(stdout);
64
+ }
65
+ });
66
+ });
67
+ }
3
68
  export async function checkForUpdate() {
4
69
  const response = await fetch(latestReleaseApiUrl, {
5
70
  headers: {
@@ -41,21 +106,16 @@ export async function checkForUpdate() {
41
106
  : `当前已是最新版本 v${appVersion}。`
42
107
  };
43
108
  }
44
- export function formatUpdateResult(result) {
45
- const lines = [
46
- result.message
47
- ];
109
+ export function formatUpdateResult(result, installMethod) {
110
+ const lines = [result.message];
48
111
  if (result.latest) {
49
112
  lines.push(`最新版本:${result.latest.tagName}`);
50
113
  lines.push(`发布页面:${result.latest.url}`);
51
114
  if (result.updateAvailable) {
52
- lines.push("更新方式:npm install -g cc98-cli");
53
- }
54
- const body = result.latest.body.trim();
55
- if (body) {
56
- lines.push("");
57
- lines.push("更新内容:");
58
- lines.push(body);
115
+ if (installMethod && installMethod !== "unknown") {
116
+ lines.push("");
117
+ lines.push(`检测到安装方式:${installMethod}`);
118
+ }
59
119
  }
60
120
  }
61
121
  return lines.join("\n");
@@ -1 +1 @@
1
- {"version":3,"file":"update.js","sourceRoot":"","sources":["../src/update.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"update.js","sourceRoot":"","sources":["../src/update.ts"],"names":[],"mappings":"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"}
package/dist/version.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- export declare const appName = "cc98-cli";
2
- export declare const appVersion = "0.3.0";
1
+ export declare const appName: string;
2
+ export declare const appVersion: string;
3
3
  export declare const repositoryOwner = "Lucent-Snow";
4
4
  export declare const repositoryName = "CC98-CLI";
5
5
  export declare const repositoryUrl = "https://github.com/Lucent-Snow/CC98-CLI";
@@ -1 +1 @@
1
- {"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,OAAO,aAAa,CAAC;AAClC,eAAO,MAAM,UAAU,UAAU,CAAC;AAClC,eAAO,MAAM,eAAe,gBAAgB,CAAC;AAC7C,eAAO,MAAM,cAAc,aAAa,CAAC;AACzC,eAAO,MAAM,aAAa,4CAA4D,CAAC"}
1
+ {"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAWA,eAAO,MAAM,OAAO,EAAE,MAAyB,CAAC;AAChD,eAAO,MAAM,UAAU,EAAE,MAA4B,CAAC;AACtD,eAAO,MAAM,eAAe,gBAAgB,CAAC;AAC7C,eAAO,MAAM,cAAc,aAAa,CAAC;AACzC,eAAO,MAAM,aAAa,4CAA4D,CAAC"}
package/dist/version.js CHANGED
@@ -1,5 +1,13 @@
1
- export const appName = "cc98-cli";
2
- export const appVersion = "0.3.0";
1
+ import { createRequire } from "module";
2
+ import { fileURLToPath } from "url";
3
+ import { dirname, join } from "path";
4
+ const __filename = fileURLToPath(import.meta.url);
5
+ const __dirname = dirname(__filename);
6
+ // 从 package.json 读取版本,避免两处维护
7
+ const require = createRequire(import.meta.url);
8
+ const packageJson = require(join(__dirname, "../package.json"));
9
+ export const appName = packageJson.name;
10
+ export const appVersion = packageJson.version;
3
11
  export const repositoryOwner = "Lucent-Snow";
4
12
  export const repositoryName = "CC98-CLI";
5
13
  export const repositoryUrl = `https://github.com/${repositoryOwner}/${repositoryName}`;
@@ -1 +1 @@
1
- {"version":3,"file":"version.js","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,OAAO,GAAG,UAAU,CAAC;AAClC,MAAM,CAAC,MAAM,UAAU,GAAG,OAAO,CAAC;AAClC,MAAM,CAAC,MAAM,eAAe,GAAG,aAAa,CAAC;AAC7C,MAAM,CAAC,MAAM,cAAc,GAAG,UAAU,CAAC;AACzC,MAAM,CAAC,MAAM,aAAa,GAAG,sBAAsB,eAAe,IAAI,cAAc,EAAE,CAAC"}
1
+ {"version":3,"file":"version.js","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,QAAQ,CAAC;AACvC,OAAO,EAAE,aAAa,EAAE,MAAM,KAAK,CAAC;AACpC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAErC,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAClD,MAAM,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;AAEtC,6BAA6B;AAC7B,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC/C,MAAM,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,SAAS,EAAE,iBAAiB,CAAC,CAAC,CAAC;AAEhE,MAAM,CAAC,MAAM,OAAO,GAAW,WAAW,CAAC,IAAI,CAAC;AAChD,MAAM,CAAC,MAAM,UAAU,GAAW,WAAW,CAAC,OAAO,CAAC;AACtD,MAAM,CAAC,MAAM,eAAe,GAAG,aAAa,CAAC;AAC7C,MAAM,CAAC,MAAM,cAAc,GAAG,UAAU,CAAC;AACzC,MAAM,CAAC,MAAM,aAAa,GAAG,sBAAsB,eAAe,IAAI,cAAc,EAAE,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cc98-cli",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "description": "A native TypeScript CLI and TUI client for CC98.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -14,6 +14,7 @@
14
14
  "scripts": {
15
15
  "build": "tsc",
16
16
  "dev": "node --enable-source-maps dist/main.js",
17
+ "generate:emoji": "python3 scripts/generate-emoji-art.py",
17
18
  "check": "tsc --noEmit",
18
19
  "prepublishOnly": "npm run check && npm run build"
19
20
  },
@@ -1,3 +0,0 @@
1
- import type { TuiState } from "../state/types.js";
2
- export declare function drawThreeColumnLayout(state: TuiState, width: number, height: number, sidebarWidth: number, rightWidth: number): string[];
3
- //# sourceMappingURL=layout.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"layout.d.ts","sourceRoot":"","sources":["../../../src/tui/components/layout.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAoBlD,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,QAAQ,EACf,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EACd,YAAY,EAAE,MAAM,EACpB,UAAU,EAAE,MAAM,GACjB,MAAM,EAAE,CAqHV"}
@@ -1,453 +0,0 @@
1
- // 布局组件 - 使用正确的 Unicode 框绘制
2
- import { ansi, bg, fg } from "../ansi.js";
3
- import { fit, cellWidth } from "./utils.js";
4
- import { BOX_ROUNDED } from "../borders.js";
5
- import { navItems } from "../navigation.js";
6
- // 颜色常量
7
- const cc98Blue = fg(0, 130, 202);
8
- const cc98BlueSoft = fg(94, 180, 232);
9
- const cc98BlueBg = bg(0, 104, 176);
10
- const white = fg(245, 250, 255);
11
- const muted = fg(139, 152, 166);
12
- const line = fg(52, 84, 112);
13
- const danger = fg(245, 101, 101);
14
- const ok = fg(91, 207, 140);
15
- // 使用圆角框样式
16
- const style = BOX_ROUNDED;
17
- // 绘制完整的三栏布局
18
- export function drawThreeColumnLayout(state, width, height, sidebarWidth, rightWidth) {
19
- const lines = [];
20
- const mainWidth = width - sidebarWidth - rightWidth - 2;
21
- const overviewHeight = 1;
22
- const bodyHeight = height - 4 - overviewHeight;
23
- // 1. 顶部标题栏
24
- lines.push(drawHeader(state, width));
25
- // 2. 顶部连接线
26
- if (rightWidth > 0) {
27
- lines.push(line +
28
- style.topLeft +
29
- style.horizontal.repeat(sidebarWidth - 2) +
30
- style.teeDown +
31
- style.horizontal.repeat(mainWidth - 2) +
32
- style.teeDown +
33
- style.horizontal.repeat(rightWidth - 2) +
34
- style.topRight +
35
- ansi.reset);
36
- }
37
- else {
38
- lines.push(line +
39
- style.topLeft +
40
- style.horizontal.repeat(sidebarWidth - 2) +
41
- style.teeDown +
42
- style.horizontal.repeat(mainWidth - 2) +
43
- style.topRight +
44
- ansi.reset);
45
- }
46
- // 3. 概览区
47
- lines.push(...drawOverview(state, width, overviewHeight));
48
- // 4. 分隔线
49
- if (rightWidth > 0) {
50
- lines.push(line +
51
- style.teeRight +
52
- style.horizontal.repeat(sidebarWidth - 2) +
53
- style.cross +
54
- style.horizontal.repeat(mainWidth - 2) +
55
- style.cross +
56
- style.horizontal.repeat(rightWidth - 2) +
57
- style.teeLeft +
58
- ansi.reset);
59
- }
60
- else {
61
- lines.push(line +
62
- style.teeRight +
63
- style.horizontal.repeat(sidebarWidth - 2) +
64
- style.cross +
65
- style.horizontal.repeat(mainWidth - 2) +
66
- style.teeLeft +
67
- ansi.reset);
68
- }
69
- // 5. 主内容区
70
- const sidebarLines = drawSidebar(state, sidebarWidth, bodyHeight);
71
- const mainLines = drawMainContent(state, mainWidth, bodyHeight);
72
- const rightLines = rightWidth > 0 ? drawRightPanel(state, rightWidth, bodyHeight) : [];
73
- for (let row = 0; row < bodyHeight; row++) {
74
- const parts = [
75
- line + style.vertical + ansi.reset,
76
- fit(sidebarLines[row] ?? "", sidebarWidth - 2),
77
- line + style.vertical + ansi.reset,
78
- fit(mainLines[row] ?? "", mainWidth - 2),
79
- ];
80
- if (rightWidth > 0) {
81
- parts.push(line + style.vertical + ansi.reset, fit(rightLines[row] ?? "", rightWidth - 2), line + style.vertical + ansi.reset);
82
- }
83
- else {
84
- parts.push(line + style.vertical + ansi.reset);
85
- }
86
- lines.push(parts.join(""));
87
- }
88
- // 6. 底部连接线
89
- if (rightWidth > 0) {
90
- lines.push(line +
91
- style.bottomLeft +
92
- style.horizontal.repeat(sidebarWidth - 2) +
93
- style.teeUp +
94
- style.horizontal.repeat(mainWidth - 2) +
95
- style.teeUp +
96
- style.horizontal.repeat(rightWidth - 2) +
97
- style.bottomRight +
98
- ansi.reset);
99
- }
100
- else {
101
- lines.push(line +
102
- style.bottomLeft +
103
- style.horizontal.repeat(sidebarWidth - 2) +
104
- style.teeUp +
105
- style.horizontal.repeat(mainWidth - 2) +
106
- style.bottomRight +
107
- ansi.reset);
108
- }
109
- // 7. 状态栏
110
- lines.push(drawStatusBar(state, width));
111
- return lines.slice(0, height);
112
- }
113
- // 绘制顶部标题栏
114
- function drawHeader(state, width) {
115
- const account = state.account ? `@${state.account}` : "未登录";
116
- const title = ` CC98 ${state.viewTitle} `;
117
- const padding = Math.max(1, width - cellWidth(title) - cellWidth(account));
118
- return `${cc98BlueBg}${white}${ansi.bold}${fit(`${title}${" ".repeat(padding)}${account}`, width)}${ansi.reset}`;
119
- }
120
- // 绘制概览区
121
- function drawOverview(state, width, height) {
122
- const rows = [];
123
- const summary = state.overview.length > 0
124
- ? state.overview.map((entry) => `${entry.title} ${entry.detail ?? "-"}`).join(" ")
125
- : "全站概览会在读取十大时更新";
126
- rows.push(fit(`${cc98BlueSoft} ${summary}`, width));
127
- return rows.slice(0, height);
128
- }
129
- // 绘制左侧导航
130
- function drawSidebar(state, width, height) {
131
- const rows = [];
132
- const navItems = [
133
- { id: "hot", label: "十大", hint: "热门话题" },
134
- { id: "favorite", label: "收藏", hint: "版面帖子" },
135
- { id: "new", label: "最新", hint: "新帖流" },
136
- { id: "boards", label: "版面", hint: "所有分区" },
137
- { id: "following", label: "关注", hint: "用户动态" },
138
- { id: "messages", label: "消息", hint: "未读与私信" },
139
- { id: "notices", label: "通知", hint: "系统与回复" },
140
- { id: "me", label: "我的", hint: "当前账号" },
141
- { id: "settings", label: "设置", hint: "账号与配置" }
142
- ];
143
- for (let index = 0; index < height; index++) {
144
- const nav = navItems[index];
145
- if (!nav) {
146
- rows.push(" ".repeat(width));
147
- continue;
148
- }
149
- const active = index === state.navIndex;
150
- const focused = state.focus === "nav";
151
- const label = ` ${nav.label}`;
152
- const hint = width > 14 ? ` ${nav.hint}` : "";
153
- const text = fit(`${label}${hint}`, width);
154
- if (active && focused) {
155
- rows.push(`${bg(0, 130, 202)}${white}${text}${ansi.reset}`);
156
- }
157
- else if (active) {
158
- rows.push(`${bg(5, 46, 74)}${cc98BlueSoft}${text}${ansi.reset}`);
159
- }
160
- else {
161
- rows.push(`${cc98Blue}${label}${ansi.reset}${muted}${fit(hint, Math.max(0, width - cellWidth(label)))}${ansi.reset}`);
162
- }
163
- }
164
- return rows;
165
- }
166
- // 绘制主内容区
167
- function drawMainContent(state, width, height) {
168
- if (state.mode === "topic") {
169
- return drawTopicContent(state, width, height);
170
- }
171
- if (state.loading) {
172
- return drawLoadingContent(state, width, height);
173
- }
174
- if (state.error) {
175
- return drawErrorContent(state, width, height);
176
- }
177
- return drawListContent(state, width, height);
178
- }
179
- // 绘制加载中内容
180
- function drawLoadingContent(state, width, height) {
181
- const rows = [];
182
- rows.push(`${cc98Blue}${ansi.bold} ${state.viewTitle}${ansi.reset}`);
183
- rows.push(fit(`${muted} 正在加载...${ansi.reset}`, width));
184
- rows.push(`${line}${"─".repeat(Math.max(0, width - 1))}${ansi.reset}`);
185
- rows.push(`${muted} ${"· ".repeat(Math.max(1, Math.floor((width - 2) / 2))).slice(0, width - 1)}${ansi.reset}`);
186
- while (rows.length < height) {
187
- rows.push(" ".repeat(width));
188
- }
189
- return rows.slice(0, height);
190
- }
191
- // 绘制错误内容
192
- function drawErrorContent(state, width, height) {
193
- const rows = [];
194
- rows.push(`${cc98Blue}${ansi.bold} ${state.viewTitle}${ansi.reset}`);
195
- rows.push(`${line}${"─".repeat(Math.max(0, width - 1))}${ansi.reset}`);
196
- rows.push(`${danger} 请求失败${ansi.reset}`);
197
- rows.push(fit(` ${state.error}`, width));
198
- while (rows.length < height) {
199
- rows.push(" ".repeat(width));
200
- }
201
- return rows.slice(0, height);
202
- }
203
- // 绘制列表内容
204
- function drawListContent(state, width, height) {
205
- const rows = [];
206
- rows.push(`${cc98Blue}${ansi.bold} ${state.viewTitle}${ansi.reset}`);
207
- rows.push(`${line}${"─".repeat(Math.max(0, width - 1))}${ansi.reset}`);
208
- const visibleCapacity = Math.max(1, Math.floor(Math.max(1, height - 3) / 3));
209
- if (state.itemIndex < state.scroll) {
210
- state.scroll = state.itemIndex;
211
- }
212
- else if (state.itemIndex >= state.scroll + visibleCapacity) {
213
- state.scroll = state.itemIndex - visibleCapacity + 1;
214
- }
215
- const visible = state.items.slice(state.scroll);
216
- visible.forEach((itemValue, offset) => {
217
- if (rows.length >= height) {
218
- return;
219
- }
220
- const index = state.scroll + offset;
221
- const active = index === state.itemIndex && (state.focus === "content" || state.mode === "settings");
222
- const prefix = active ? `${ok}●${ansi.reset}` : `${muted}•${ansi.reset}`;
223
- const title = fit(` ${itemValue.title}`, Math.max(10, width - 2));
224
- rows.push(active ? `${bg(5, 46, 74)}${prefix}${title}${ansi.reset}` : fit(`${prefix}${title}`, width));
225
- if (itemValue.meta && rows.length < height) {
226
- rows.push(fit(` ${muted}${itemValue.meta}${ansi.reset}`, width));
227
- }
228
- });
229
- if (visible.length === 0) {
230
- rows.push(`${muted} 暂无数据${ansi.reset}`);
231
- }
232
- while (rows.length < height) {
233
- rows.push(" ".repeat(width));
234
- }
235
- return rows.slice(0, height);
236
- }
237
- // 绘制帖子内容
238
- function drawTopicContent(state, width, height) {
239
- const rows = [];
240
- if (state.loading && (!state.topic || state.topic.lines.length === 0)) {
241
- rows.push(`${cc98Blue} 正在打开帖子...${ansi.reset}`);
242
- rows.push("");
243
- rows.push(`${muted} 只加载第一页,不预取未读楼层。${ansi.reset}`);
244
- while (rows.length < height) {
245
- rows.push(" ".repeat(width));
246
- }
247
- return rows.slice(0, height);
248
- }
249
- if (state.error) {
250
- rows.push(`${danger} 读取帖子失败${ansi.reset}`);
251
- rows.push(fit(` ${state.error}`, width));
252
- rows.push("");
253
- rows.push(`${muted} h/Esc 返回列表${ansi.reset}`);
254
- while (rows.length < height) {
255
- rows.push(" ".repeat(width));
256
- }
257
- return rows.slice(0, height);
258
- }
259
- const topic = state.topic;
260
- if (!topic) {
261
- return Array(height).fill(" ".repeat(width));
262
- }
263
- rows.push(`${cc98Blue}${ansi.bold} ${topic.title}${ansi.reset}`);
264
- rows.push(fit(`${muted} ${topic.meta}${ansi.reset}`, width));
265
- rows.push(`${line}${"─".repeat(Math.max(0, width - 1))}${ansi.reset}`);
266
- const viewport = Math.max(0, height - rows.length - 1);
267
- const maxScroll = Math.max(0, topic.lines.length - viewport);
268
- state.scroll = Math.min(state.scroll, maxScroll);
269
- const body = topic.lines.slice(state.scroll, state.scroll + viewport);
270
- for (const bodyLine of body) {
271
- if (bodyLine.startsWith("[image ")) {
272
- rows.push(fit(`${cc98BlueSoft}${bodyLine}${ansi.reset}`, width));
273
- }
274
- else if (bodyLine.startsWith("│ ")) {
275
- rows.push(fit(`${muted}${bodyLine}${ansi.reset}`, width));
276
- }
277
- else if (/^#\d+ /.test(bodyLine)) {
278
- rows.push(fit(`${ok}${bodyLine}${ansi.reset}`, width));
279
- }
280
- else {
281
- rows.push(fit(` ${bodyLine}`, width));
282
- }
283
- }
284
- const pageInfo = topic.hasMore
285
- ? `已载入 ${topic.loaded} 楼,n 下一页`
286
- : `已载入 ${topic.loaded} 楼,已到底`;
287
- rows.push(fit(`${muted}${pageInfo}${state.loadingMore ? " · 加载中" : ""}${ansi.reset}`, width));
288
- while (rows.length < height) {
289
- rows.push(" ".repeat(width));
290
- }
291
- return rows.slice(0, height);
292
- }
293
- // 绘制右侧面板
294
- function drawRightPanel(state, width, height) {
295
- if (state.mode === "topic" && state.topic) {
296
- return drawTopicRight(state.topic, state.scroll, width, height);
297
- }
298
- if (state.focus === "nav") {
299
- return drawNavRight(state, width, height);
300
- }
301
- return drawItemRight(state, width, height);
302
- }
303
- // 绘制导航右侧面板
304
- function drawNavRight(state, width, height) {
305
- const rows = [];
306
- const nav = navItems[state.navIndex];
307
- rows.push(`${cc98Blue}${ansi.bold} ${nav?.label ?? ""}${ansi.reset}`);
308
- rows.push(`${muted} ${nav?.hint ?? ""}${ansi.reset}`);
309
- rows.push(`${line}${"─".repeat(Math.max(0, width - 1))}${ansi.reset}`);
310
- for (const stat of state.stats) {
311
- if (rows.length >= height)
312
- break;
313
- rows.push(`${muted} ${stat.title}${ansi.reset}`);
314
- if (stat.detail) {
315
- rows.push(`${cc98BlueSoft} ${stat.detail}${ansi.reset}`);
316
- }
317
- }
318
- // 删除快捷键提示,只保留统计信息
319
- while (rows.length < height) {
320
- rows.push(" ".repeat(width));
321
- }
322
- return rows.slice(0, height);
323
- }
324
- // 绘制列表项右侧面板
325
- function drawItemRight(state, width, height) {
326
- const rows = [];
327
- const selected = state.items[state.itemIndex];
328
- if (!selected) {
329
- return Array(height).fill(" ".repeat(width));
330
- }
331
- rows.push(`${cc98Blue}${ansi.bold} ${selected.title}${ansi.reset}`);
332
- rows.push(`${line}${"─".repeat(Math.max(0, width - 1))}${ansi.reset}`);
333
- if (selected.meta) {
334
- rows.push(`${muted} ${selected.meta}${ansi.reset}`);
335
- }
336
- if (selected.detail) {
337
- rows.push(`${cc98BlueSoft} ${selected.detail}${ansi.reset}`);
338
- }
339
- if (selected.topicId !== undefined) {
340
- rows.push(`${muted} 主题 #${selected.topicId}${ansi.reset}`);
341
- }
342
- if (selected.boardId !== undefined) {
343
- rows.push(`${muted} 版面 #${selected.boardId}${ansi.reset}`);
344
- }
345
- if (selected.userId !== undefined) {
346
- rows.push(`${muted} 用户 #${selected.userId}${ansi.reset}`);
347
- }
348
- if (selected.sortTime) {
349
- const date = new Date(selected.sortTime);
350
- const timeStr = date.toLocaleString('zh-CN', { month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit' });
351
- rows.push(`${muted} 时间: ${timeStr}${ansi.reset}`);
352
- }
353
- while (rows.length < height) {
354
- rows.push(" ".repeat(width));
355
- }
356
- return rows.slice(0, height);
357
- }
358
- // 绘制帖子右侧面板
359
- function drawTopicRight(topic, scroll, width, height) {
360
- const rows = [];
361
- const currentPost = topic.posts.find((p) => scroll >= p.lineStart && scroll <= p.lineEnd);
362
- rows.push(`${cc98Blue}${ansi.bold} 帖子信息${ansi.reset}`);
363
- rows.push(`${line}${"─".repeat(Math.max(0, width - 1))}${ansi.reset}`);
364
- if (currentPost) {
365
- rows.push(`${muted} 楼层: #${currentPost.floor ?? "?"}${ansi.reset}`);
366
- rows.push(`${muted} 作者: ${currentPost.author}${ansi.reset}`);
367
- rows.push(`${muted} 时间: ${currentPost.time}${ansi.reset}`);
368
- if (currentPost.likeCount > 0) {
369
- rows.push(`${ok} 赞: ${currentPost.likeCount}${ansi.reset}`);
370
- }
371
- if (currentPost.dislikeCount > 0) {
372
- rows.push(`${danger} 踩: ${currentPost.dislikeCount}${ansi.reset}`);
373
- }
374
- if (currentPost.rating) {
375
- rows.push(`${muted} 评分: ${currentPost.rating}${ansi.reset}`);
376
- }
377
- if (currentPost.imageCount > 0) {
378
- rows.push(`${muted} 图片: ${currentPost.imageCount}${ansi.reset}`);
379
- }
380
- if (currentPost.linkCount > 0) {
381
- rows.push(`${muted} 链接: ${currentPost.linkCount}${ansi.reset}`);
382
- }
383
- }
384
- rows.push(`${line}${"─".repeat(Math.max(0, width - 1))}${ansi.reset}`);
385
- rows.push(`${muted} 当前: ${scroll + 1}/${topic.lines.length}${ansi.reset}`);
386
- rows.push(`${muted} 已加载: ${topic.loaded} 楼${ansi.reset}`);
387
- while (rows.length < height) {
388
- rows.push(" ".repeat(width));
389
- }
390
- return rows.slice(0, height);
391
- }
392
- // 绘制状态栏
393
- function drawStatusBar(state, width) {
394
- const left = getStatus(state);
395
- const right = getKeyHints(state);
396
- const padding = Math.max(1, width - cellWidth(left) - cellWidth(right) - 2);
397
- return fit(`${muted} ${left}${" ".repeat(padding)}${right} `, width);
398
- }
399
- // 获取状态文本
400
- function getStatus(state) {
401
- if (state.loading) {
402
- return "加载中...";
403
- }
404
- if (state.error) {
405
- return `错误: ${state.error}`;
406
- }
407
- if (state.inputMode) {
408
- return state.inputPrompt;
409
- }
410
- return state.status || getDefaultStatus(state);
411
- }
412
- // 获取默认状态文本
413
- function getDefaultStatus(state) {
414
- switch (state.mode) {
415
- case "topic":
416
- return "帖子阅读";
417
- case "settings":
418
- return "设置";
419
- default:
420
- if (state.currentBoard) {
421
- return `版面 #${state.currentBoard.boardId}`;
422
- }
423
- if (state.currentChat) {
424
- return "私信";
425
- }
426
- return state.focus === "nav" ? "导航" : "列表";
427
- }
428
- }
429
- // 获取快捷键提示
430
- function getKeyHints(state) {
431
- if (state.modal === "search") {
432
- return "Enter 搜索/打开 Tab 切换 / 关闭";
433
- }
434
- if (state.modal === "menu") {
435
- return "j/k 移动 Enter 执行 o 关闭";
436
- }
437
- if (state.modal === "user") {
438
- return "f 关注 m 私信 u 关闭";
439
- }
440
- if (state.mode === "topic") {
441
- return "j/k 滚动 n 下页 h 返回 s 收藏 l/d 赞踩 u 用户";
442
- }
443
- if (state.mode === "settings") {
444
- return "j/k 选择 Enter 执行 h 返回";
445
- }
446
- if (state.currentChat) {
447
- return "j/k 滚动 n 更多 h 返回 r 刷新";
448
- }
449
- return state.focus === "nav"
450
- ? "j/k 切换 Enter 进入 r 刷新 / 搜索 ? 帮助 q 退出"
451
- : "j/k 选择 Enter 打开 h 返回 r 刷新 / 搜索 ? 帮助 q 退出";
452
- }
453
- //# sourceMappingURL=layout.js.map