最後活躍 4 weeks ago

nuno 已修改 4 weeks ago. 還原成這個修訂版本

1 file changed, 100 insertions

charSelect.ts(檔案已創建)

@@ -0,0 +1,100 @@
1 + import {
2 + ButtonBuilder,
3 + ButtonStyle,
4 + ActionRowBuilder,
5 + } from "discord.js";
6 + import { getCharacters, getCharacterByName } from "@systems/characters";
7 + import { getClassEmoji } from "@systems/emojis";
8 + import { format } from "@format";
9 + import { Character } from "@types";
10 + import fs from "fs";
11 + import path from "path";
12 +
13 + const CHARS_PATH = path.join(__dirname, "../../data/characters.json");
14 +
15 + export interface CharSelectOptions {
16 + customIdPrefix: string; // e.g. "switch_after_reclaim:flash"
17 + excludeCharName?: string; // exclude this char from the list
18 + appendToCustomId?: string; // appended after charName e.g. ":yes"
19 + pageSize?: number; // default 4
20 + page?: number; // default 0
21 + }
22 +
23 + /**
24 + * Builds paginated character selection button rows for a given user.
25 + * Includes own characters + shared characters.
26 + * Returns up to 2 rows: one for char buttons, one for pagination if needed.
27 + */
28 + export function buildCharSelectButtons(
29 + userKey: string,
30 + options: CharSelectOptions
31 + ): ActionRowBuilder<ButtonBuilder>[] {
32 + const {
33 + customIdPrefix,
34 + excludeCharName,
35 + appendToCustomId = "",
36 + pageSize = 4,
37 + page = 0,
38 + } = options;
39 +
40 + // Gather own + shared chars
41 + const ownChars = getCharacters(userKey);
42 +
43 + const sharedChars: Character[] = [];
44 + try {
45 + const chars = JSON.parse(fs.readFileSync(CHARS_PATH, "utf8"));
46 + for (const [ownerKey, data] of Object.entries(chars) as [string, any][]) {
47 + if (ownerKey === userKey) continue;
48 + for (const c of data.characters ?? []) {
49 + if (c.sharedWith?.includes(userKey)) sharedChars.push(c);
50 + }
51 + }
52 + } catch {}
53 +
54 + const allChars = [...ownChars, ...sharedChars]
55 + .filter((c) => c.name !== excludeCharName);
56 +
57 + const pageChars = allChars.slice(page * pageSize, (page + 1) * pageSize);
58 + const hasNext = allChars.length > (page + 1) * pageSize;
59 + const hasPrev = page > 0;
60 + const rows: ActionRowBuilder<ButtonBuilder>[] = [];
61 +
62 + // Char buttons
63 + if (pageChars.length > 0) {
64 + const btns = pageChars.map((c) => {
65 + const emojiStr = getClassEmoji(c.class);
66 + const emoji = format.emoji(emojiStr);
67 + const btn = new ButtonBuilder()
68 + .setCustomId(`${customIdPrefix}:${c.name}${appendToCustomId}`)
69 + .setStyle(ButtonStyle.Secondary)
70 + .setLabel(`${c.level} ${c.name}`);
71 + if (emoji) btn.setEmoji(emoji as any);
72 + return btn;
73 + });
74 + rows.push(new ActionRowBuilder<ButtonBuilder>().addComponents(...btns));
75 + }
76 +
77 + // Pagination row
78 + const navBtns: ButtonBuilder[] = [];
79 + if (hasPrev) {
80 + navBtns.push(
81 + new ButtonBuilder()
82 + .setCustomId(`${customIdPrefix}_page:${page - 1}`)
83 + .setLabel("← Prev")
84 + .setStyle(ButtonStyle.Primary)
85 + );
86 + }
87 + if (hasNext) {
88 + navBtns.push(
89 + new ButtonBuilder()
90 + .setCustomId(`${customIdPrefix}_page:${page + 1}`)
91 + .setLabel("Next →")
92 + .setStyle(ButtonStyle.Primary)
93 + );
94 + }
95 + if (navBtns.length > 0) {
96 + rows.push(new ActionRowBuilder<ButtonBuilder>().addComponents(...navBtns));
97 + }
98 +
99 + return rows;
100 + }
上一頁 下一頁