This commit is contained in:
Aotumuri
2025-04-02 21:15:04 +09:00
parent 06b9a30111
commit a121f47b2d
2 changed files with 193 additions and 98 deletions
+135 -63
View File
@@ -5,11 +5,25 @@ const quickChatPhrases: Record<
string,
Array<{ text: string; requiresPlayer: boolean }>
> = {
help: [{ text: "Please give me troops!", requiresPlayer: false }],
attack: [{ text: "Attack [P1]!", requiresPlayer: true }],
help: [
{ text: "Please give me troops!", requiresPlayer: false },
{ text: "Please give me golds!", requiresPlayer: false },
{ text: "Please don't attack me!", requiresPlayer: false },
],
attack: [
{ text: "Attack [P1]!", requiresPlayer: true },
{ text: "Launch a MIRV at [P1]!", requiresPlayer: true },
{ text: "Focus fire on [P1]!", requiresPlayer: true },
{ text: "Let's finish off [P1]!", requiresPlayer: true },
],
defend: [{ text: "Defend [P1]!", requiresPlayer: true }],
greet: [{ text: "Hello!", requiresPlayer: false }],
misc: [{ text: "Lets go!", requiresPlayer: false }],
misc: [
{ text: "Lets go!", requiresPlayer: false },
{ text: "Nice strategy!", requiresPlayer: false },
{ text: "This game is fun!", requiresPlayer: false },
{ text: "When will my PR finally get merged...?", requiresPlayer: false },
],
};
@customElement("chat-modal")
@@ -23,10 +37,30 @@ export class ChatModal extends LitElement {
return this;
}
private players: string[] = [
"Slovakia",
"Germany",
"Japan",
"Anon",
"Anon1",
"Anon2",
"Anon3",
"Anon4",
"Anon5",
"Anon6",
"Anon7",
"Anon8",
"Anon9",
"Anon10",
];
private playerSearchQuery: string = "";
private previewText: string | null = null;
private requiresPlayerSelection: boolean = false;
private players: string[] = ["Slovakia", "Germany", "Japan"];
private selectedCategory: string | null = null;
private selectedPhraseText: string | null = null;
private selectedPlayer: string | null = null;
private selectedPhraseTemplate: string | null = null;
quickChatPhrases: Record<
string,
@@ -52,65 +86,78 @@ export class ChatModal extends LitElement {
}
render() {
const sortedPlayers = [...this.players].sort((a, b) => a.localeCompare(b));
const filteredPlayers = sortedPlayers.filter((player) =>
player.toLowerCase().includes(this.playerSearchQuery),
);
const otherPlayers = sortedPlayers.filter(
(player) => !player.toLowerCase().includes(this.playerSearchQuery),
);
const displayPlayers = [...filteredPlayers, ...otherPlayers];
return html`
<o-modal title="Quick Chat">
<div class="chat-modal-content">
<!-- 入力中のチャットプレビュー -->
<div class="chat-preview">
<span>${this.previewText || "Select a phrase"}</span>
<div class="chat-columns">
<div class="chat-column">
<div class="column-title">Category</div>
${this.categories.map(
(category) => html`
<button
class="chat-option-button ${this.selectedCategory ===
category.id
? "selected"
: ""}"
@click=${() => this.selectCategory(category.id)}
>
${category.name}
</button>
`,
)}
</div>
<!-- カテゴリ選択 -->
<div class="chat-section">
<div class="chat-section-title">Categories</div>
<div class="chat-options">
${this.categories.map(
(category) => html`
<button
class="chat-option-button ${this.selectedCategory ===
category.id
? "selected"
: ""}"
@click=${() => this.selectCategory(category.id)}
>
${category.name}
</button>
`,
)}
</div>
</div>
<!-- 定型文選択 -->
${this.selectedCategory
? html`
<div class="chat-section">
<div class="chat-section-title">Phrases</div>
<div class="chat-options">
${this.getPhrasesForCategory(this.selectedCategory).map(
(phrase) => html`
<button
class="chat-option-button"
@click=${() => this.selectPhrase(phrase)}
>
${this.renderPhrasePreview(phrase)}
</button>
`,
)}
</div>
<div class="chat-column">
<div class="column-title">Phrase</div>
${this.getPhrasesForCategory(this.selectedCategory).map(
(phrase) => html`
<button
class="chat-option-button ${this.selectedPhraseText ===
phrase.text
? "selected"
: ""}"
@click=${() => this.selectPhrase(phrase)}
>
${this.renderPhrasePreview(phrase)}
</button>
`,
)}
</div>
`
: null}
<!-- プレイヤー選択(変数が必要な場合のみ表示) -->
${this.requiresPlayerSelection
${this.requiresPlayerSelection || this.selectedPlayer
? html`
<div class="chat-section">
<div class="chat-section-title">Select Player</div>
<div class="chat-options">
${this.players.map(
<div class="chat-column">
<div class="column-title">Player</div>
<input
class="player-search-input"
type="text"
placeholder="Search player..."
.value=${this.playerSearchQuery}
@input=${this.onPlayerSearchInput}
/>
<div class="player-scroll-area">
${this.getSortedFilteredPlayers().map(
(player) => html`
<button
class="chat-option-button"
class="chat-option-button ${this.selectedPlayer ===
player
? "selected"
: ""}"
@click=${() => this.selectPlayer(player)}
>
${player}
@@ -121,17 +168,19 @@ export class ChatModal extends LitElement {
</div>
`
: null}
</div>
<!-- 送信ボタン -->
<div class="chat-send">
<button
class="chat-send-button"
@click=${this.sendChatMessage}
?disabled=${!this.previewText}
>
Send
</button>
</div>
<div class="chat-preview">
${this.previewText || "Build your message..."}
</div>
<div class="chat-send">
<button
class="chat-send-button"
@click=${this.sendChatMessage}
?disabled=${!this.previewText}
>
Send
</button>
</div>
</o-modal>
`;
@@ -139,14 +188,19 @@ export class ChatModal extends LitElement {
private selectCategory(categoryId: string) {
this.selectedCategory = categoryId;
this.selectedPhraseText = null;
this.previewText = null;
this.requiresPlayerSelection = false;
this.selectedPlayer = null;
this.requestUpdate();
}
private selectPhrase(phrase: { text: string; requiresPlayer: boolean }) {
this.selectedPhraseTemplate = phrase.text;
this.selectedPhraseText = phrase.text;
this.previewText = phrase.text;
this.requiresPlayerSelection = phrase.requiresPlayer;
this.selectedPlayer = null;
this.requestUpdate();
}
@@ -156,7 +210,8 @@ export class ChatModal extends LitElement {
private selectPlayer(player: string) {
if (this.previewText) {
this.previewText = this.previewText.replace("[P1]", player);
this.previewText = this.selectedPhraseTemplate.replace("[P1]", player);
this.selectedPlayer = player;
this.requiresPlayerSelection = false;
this.requestUpdate();
}
@@ -167,7 +222,24 @@ export class ChatModal extends LitElement {
this.previewText = null;
this.selectedCategory = null;
this.requiresPlayerSelection = false;
this.close(); // モーダルを閉じる
this.close();
}
private onPlayerSearchInput(e: Event) {
const target = e.target as HTMLInputElement;
this.playerSearchQuery = target.value.toLowerCase();
this.requestUpdate();
}
private getSortedFilteredPlayers(): string[] {
const sorted = [...this.players].sort((a, b) => a.localeCompare(b));
const filtered = sorted.filter((p) =>
p.toLowerCase().includes(this.playerSearchQuery),
);
const others = sorted.filter(
(p) => !p.toLowerCase().includes(this.playerSearchQuery),
);
return [...filtered, ...others];
}
public open() {
+58 -35
View File
@@ -492,65 +492,88 @@ label.option-card:hover {
border: 1px solid rgba(255, 255, 255, 0.2);
}
.chat-modal-content {
/* .w. */
.chat-columns {
display: flex;
flex-direction: column;
gap: 12px;
gap: 16px;
padding: 12px;
overflow-x: auto;
}
.chat-preview {
background: #222;
padding: 10px;
border-radius: 6px;
.chat-column {
display: flex;
flex-direction: column;
gap: 8px;
min-width: 120px;
}
.column-title {
font-weight: bold;
text-align: center;
}
.chat-section {
display: flex;
flex-direction: column;
}
.chat-section-title {
font-size: 14px;
margin-bottom: 6px;
}
.chat-options {
display: flex;
flex-wrap: wrap;
gap: 6px;
margin-bottom: 4px;
}
.chat-option-button {
background: #444;
background: #333;
color: white;
border: none;
padding: 8px 12px;
border-radius: 4px;
padding: 6px 10px;
text-align: left;
cursor: pointer;
}
.chat-option-button.selected {
background: #66c;
background-color: #66c;
}
.chat-preview {
margin: 10px 12px;
padding: 10px;
background: #222;
color: white;
border-radius: 6px;
text-align: center;
}
.chat-send {
display: flex;
justify-content: space-between;
margin-top: 10px;
justify-content: flex-end;
padding: 0 12px 12px;
}
.chat-send-button {
background: #4caf50;
color: white;
padding: 8px 14px;
padding: 8px 16px;
border: none;
border-radius: 4px;
cursor: pointer;
}
.chat-cancel-button {
background: #aaa;
color: black;
padding: 8px 14px;
border-radius: 4px;
.chat-column {
display: flex;
flex-direction: column;
gap: 8px;
min-width: 140px;
}
.player-search-input {
padding: 6px 8px;
border-radius: 4px;
border: 1px solid #666;
font-size: 14px;
outline: none;
background-color: #fff;
color: #000;
}
.player-scroll-area {
max-height: 200px;
overflow-y: auto;
display: flex;
flex-direction: column;
gap: 6px;
padding-right: 4px;
}