掲示板実装
This commit is contained in:
73
app/javascript/controllers/board_channel_controller.js
Normal file
73
app/javascript/controllers/board_channel_controller.js
Normal file
@@ -0,0 +1,73 @@
|
||||
import { Controller } from "@hotwired/stimulus"
|
||||
import { createConsumer } from "@rails/actioncable"
|
||||
|
||||
export default class extends Controller {
|
||||
static values = {
|
||||
boardId: Number,
|
||||
currentParticipantId: Number
|
||||
}
|
||||
|
||||
connect() {
|
||||
this.channel = createConsumer().subscriptions.create(
|
||||
{ channel: "BoardChannel", board_id: this.boardIdValue },
|
||||
{
|
||||
received: (data) => {
|
||||
this._insertMessage(data)
|
||||
}
|
||||
}
|
||||
)
|
||||
this.element.scrollTop = this.element.scrollHeight
|
||||
}
|
||||
|
||||
disconnect() {
|
||||
if (this.channel) {
|
||||
this.channel.unsubscribe()
|
||||
}
|
||||
}
|
||||
|
||||
_insertMessage(data) {
|
||||
const isMe = data.participant_id === this.currentParticipantIdValue
|
||||
|
||||
// 最初の投稿の場合、"まだ投稿がありません"メッセージを消す
|
||||
const noPostsMessage = document.getElementById("no-posts-message")
|
||||
if (noPostsMessage) {
|
||||
noPostsMessage.remove()
|
||||
}
|
||||
|
||||
const html = `
|
||||
<div class="flex ${isMe ? 'justify-end' : 'justify-start'} mb-4 message-item" id="post_${data.post_id}">
|
||||
${!isMe ? `
|
||||
<div class="flex-shrink-0 mr-3">
|
||||
<span class="inline-flex items-center justify-center h-8 w-8 rounded-full text-xs font-bold border border-gray-300 bg-white text-gray-700 shadow-sm" title="${data.power}">
|
||||
${data.power ? data.power.substring(0, 2) : '?'}
|
||||
</span>
|
||||
</div>
|
||||
` : ''}
|
||||
|
||||
<div class="max-w-lg ${isMe ? 'order-1' : 'order-2'}">
|
||||
<div class="flex items-baseline space-x-2 mb-1 ${isMe ? 'justify-end' : 'justify-start'}">
|
||||
${!isMe ? `<span class="text-xs font-bold text-gray-900">${data.power}</span>` : ''}
|
||||
<span class="text-xs text-gray-500">${data.created_at}</span>
|
||||
${data.phase ? `<span class="text-xs bg-gray-100 px-1 rounded text-gray-600 border border-gray-200">${data.phase}</span>` : ''}
|
||||
</div>
|
||||
|
||||
<div class="px-4 py-2 rounded-lg shadow-sm text-sm ${isMe ? 'bg-indigo-600 text-white rounded-br-none' : 'bg-white border border-gray-200 text-gray-900 rounded-bl-none'}">
|
||||
<div>${this._escapeHtml(data.body).replace(/\n/g, '<br>')}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`
|
||||
|
||||
this.element.insertAdjacentHTML('afterbegin', html)
|
||||
// this.element.scrollTop = 0 // 必要ならトップへスクロール
|
||||
}
|
||||
|
||||
_escapeHtml(unsafe) {
|
||||
return unsafe
|
||||
.replace(/&/g, "&")
|
||||
.replace(/</g, "<")
|
||||
.replace(/>/g, ">")
|
||||
.replace(/"/g, """)
|
||||
.replace(/'/g, "'")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user