This commit is contained in:
Aotumuri
2025-04-02 20:27:46 +09:00
parent 0976f4da0a
commit 06b9a30111
4 changed files with 258 additions and 0 deletions
+180
View File
@@ -0,0 +1,180 @@
import { LitElement, html } from "lit";
import { customElement, query } from "lit/decorators.js";
const quickChatPhrases: Record<
string,
Array<{ text: string; requiresPlayer: boolean }>
> = {
help: [{ text: "Please give me troops!", requiresPlayer: false }],
attack: [{ text: "Attack [P1]!", requiresPlayer: true }],
defend: [{ text: "Defend [P1]!", requiresPlayer: true }],
greet: [{ text: "Hello!", requiresPlayer: false }],
misc: [{ text: "Lets go!", requiresPlayer: false }],
};
@customElement("chat-modal")
export class ChatModal extends LitElement {
@query("o-modal") private modalEl!: HTMLElement & {
open: () => void;
close: () => void;
};
createRenderRoot() {
return this;
}
private previewText: string | null = null;
private requiresPlayerSelection: boolean = false;
private players: string[] = ["Slovakia", "Germany", "Japan"];
private selectedCategory: string | null = null;
quickChatPhrases: Record<
string,
Array<{ text: string; requiresPlayer: boolean }>
> = {
help: [{ text: "Please give me troops!", requiresPlayer: false }],
attack: [{ text: "Attack [P1]!", requiresPlayer: true }],
defend: [{ text: "Defend [P1]!", requiresPlayer: true }],
greet: [{ text: "Hello!", requiresPlayer: false }],
misc: [{ text: "Let's go!", requiresPlayer: false }],
};
private categories = [
{ id: "help", name: "Help" },
{ id: "attack", name: "Attack" },
{ id: "defend", name: "Defend" },
{ id: "greet", name: "Greetings" },
{ id: "misc", name: "Miscellaneous" },
];
private getPhrasesForCategory(categoryId: string) {
return quickChatPhrases[categoryId] ?? [];
}
render() {
return html`
<o-modal title="Quick Chat">
<div class="chat-modal-content">
<!-- 入力中のチャットプレビュー -->
<div class="chat-preview">
<span>${this.previewText || "Select a phrase"}</span>
</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>
`
: null}
<!-- プレイヤー選択(変数が必要な場合のみ表示) -->
${this.requiresPlayerSelection
? html`
<div class="chat-section">
<div class="chat-section-title">Select Player</div>
<div class="chat-options">
${this.players.map(
(player) => html`
<button
class="chat-option-button"
@click=${() => this.selectPlayer(player)}
>
${player}
</button>
`,
)}
</div>
</div>
`
: null}
<!-- 送信ボタン -->
<div class="chat-send">
<button
class="chat-send-button"
@click=${this.sendChatMessage}
?disabled=${!this.previewText}
>
Send
</button>
</div>
</div>
</o-modal>
`;
}
private selectCategory(categoryId: string) {
this.selectedCategory = categoryId;
this.previewText = null;
this.requiresPlayerSelection = false;
this.requestUpdate();
}
private selectPhrase(phrase: { text: string; requiresPlayer: boolean }) {
this.previewText = phrase.text;
this.requiresPlayerSelection = phrase.requiresPlayer;
this.requestUpdate();
}
private renderPhrasePreview(phrase: { text: string }) {
return phrase.text.replace("[P1]", "___"); // 仮表示
}
private selectPlayer(player: string) {
if (this.previewText) {
this.previewText = this.previewText.replace("[P1]", player);
this.requiresPlayerSelection = false;
this.requestUpdate();
}
}
private sendChatMessage() {
console.log("Sent message:", this.previewText);
this.previewText = null;
this.selectedCategory = null;
this.requiresPlayerSelection = false;
this.close(); // モーダルを閉じる
}
public open() {
this.modalEl?.open();
}
public close() {
this.modalEl?.close();
}
}
+8
View File
@@ -28,6 +28,8 @@ import "./components/baseComponents/Modal";
import { GameStartingModal } from "./gameStartingModal";
import "./styles.css";
import { ChatModal } from "./ChatModal";
export interface JoinLobbyEvent {
clientID: string;
// Multiplayer games only have gameID, gameConfig is not known until game starts.
@@ -105,6 +107,12 @@ class Client {
}
});
const ctModal = document.querySelector("chat-modal") as ChatModal;
ctModal instanceof ChatModal;
document.getElementById("chat-button").addEventListener("click", () => {
ctModal.open();
});
const hlpModal = document.querySelector("help-modal") as HelpModal;
hlpModal instanceof HelpModal;
document.getElementById("help-button").addEventListener("click", () => {
+7
View File
@@ -243,6 +243,12 @@
block
secondary
></o-button>
<o-button
id="chat-button"
title="Chat Test"
block
secondary
></o-button>
</div>
<o-button
@@ -339,6 +345,7 @@
<player-panel></player-panel>
<help-modal></help-modal>
<dark-mode-button></dark-mode-button>
<chat-modal></chat-modal>
<!-- Scripts -->
<script>
// Remove preload class after everything is loaded
+63
View File
@@ -491,3 +491,66 @@ label.option-card:hover {
color: #fff;
border: 1px solid rgba(255, 255, 255, 0.2);
}
.chat-modal-content {
display: flex;
flex-direction: column;
gap: 12px;
}
.chat-preview {
background: #222;
padding: 10px;
border-radius: 6px;
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;
}
.chat-option-button {
background: #444;
border: none;
border-radius: 4px;
padding: 6px 10px;
cursor: pointer;
}
.chat-option-button.selected {
background: #66c;
color: white;
}
.chat-send {
display: flex;
justify-content: space-between;
margin-top: 10px;
}
.chat-send-button {
background: #4caf50;
color: white;
padding: 8px 14px;
border-radius: 4px;
}
.chat-cancel-button {
background: #aaa;
color: black;
padding: 8px 14px;
border-radius: 4px;
}