掲示板実装
This commit is contained in:
133
app/views/games/_header.html.erb
Normal file
133
app/views/games/_header.html.erb
Normal file
@@ -0,0 +1,133 @@
|
||||
<div class="mb-6 flex items-center justify-between">
|
||||
<div>
|
||||
<h1 class="text-3xl font-bold text-gray-900"><%= h(game.title) %></h1>
|
||||
<% if game.memo.present? %>
|
||||
<p class="mt-1 text-sm text-gray-500"><%= h(game.memo) %></p>
|
||||
<% end %>
|
||||
<div class="mt-2 flex items-center space-x-4 text-sm text-gray-600">
|
||||
<span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium
|
||||
<%= game.solo_mode? ? 'bg-purple-100 text-purple-800' : 'bg-blue-100 text-blue-800' %>">
|
||||
<%= game.solo_mode? ? 'ソロモード' : 'マルチプレイヤーモード' %>
|
||||
</span>
|
||||
<% if game.administrator %>
|
||||
<span>管理者: <%= h(game.administrator.username) %></span>
|
||||
<% end %>
|
||||
<span>状態: <%= game.status %></span>
|
||||
</div>
|
||||
<% if game.year_limit.present? || game.victory_sc_count != 18 || game.scoring_system != "none" || game.auto_turn? %>
|
||||
<div class="mt-2 flex flex-wrap items-center gap-2 text-xs">
|
||||
<span class="font-medium text-gray-500">ハウスルール:</span>
|
||||
<% if game.auto_turn? %>
|
||||
<span class="inline-flex items-center px-2 py-0.5 rounded-full bg-blue-100 text-blue-800">
|
||||
<i class="fa-solid fa-clock mr-1"></i> <%= game.schedule_display %>
|
||||
</span>
|
||||
<% end %>
|
||||
<% if game.year_limit.present? %>
|
||||
<span class="inline-flex items-center px-2 py-0.5 rounded-full bg-amber-100 text-amber-800">
|
||||
<i class="fa-solid fa-hourglass-half mr-1"></i> <%= game.year_limit %>年制限
|
||||
</span>
|
||||
<% end %>
|
||||
<% if game.victory_sc_count != 18 %>
|
||||
<span class="inline-flex items-center px-2 py-0.5 rounded-full bg-green-100 text-green-800">
|
||||
<i class="fa-solid fa-crown mr-1"></i> 目標SC: <%= game.victory_sc_count %>
|
||||
</span>
|
||||
<% end %>
|
||||
<% if game.scoring_system != "none" %>
|
||||
<span class="inline-flex items-center px-2 py-0.5 rounded-full bg-indigo-100 text-indigo-800">
|
||||
<i class="fa-solid fa-chart-bar mr-1"></i> <%= game.scoring_system_name %>
|
||||
</span>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
<% if game.auto_turn? && game.next_deadline_at.present? && game.status == "in_progress" %>
|
||||
<div class="mt-2 px-3 py-1.5 rounded-md bg-blue-50 border border-blue-200 text-sm text-blue-800 flex items-center gap-2">
|
||||
<i class="fa-solid fa-clock"></i>
|
||||
<span>次のターン締切: <strong><%= game.next_deadline_at.in_time_zone("Asia/Tokyo").strftime("%Y-%m-%d %H:%M") %></strong></span>
|
||||
<span class="text-blue-600" id="deadline-countdown"></span>
|
||||
</div>
|
||||
<script>
|
||||
(function() {
|
||||
const deadline = new Date("<%= game.next_deadline_at.iso8601 %>");
|
||||
const countdownEl = document.getElementById('deadline-countdown');
|
||||
function updateCountdown() {
|
||||
const now = new Date();
|
||||
const diff = deadline - now;
|
||||
if (diff <= 0) {
|
||||
countdownEl.textContent = '(締切済み — まもなく処理されます)';
|
||||
return;
|
||||
}
|
||||
const hours = Math.floor(diff / (1000 * 60 * 60));
|
||||
const minutes = Math.floor((diff % (1000 * 60 * 60)) / (1000 * 60));
|
||||
countdownEl.textContent = `(残り ${hours}時間 ${minutes}分)`;
|
||||
}
|
||||
if (countdownEl) {
|
||||
updateCountdown();
|
||||
setInterval(updateCountdown, 60000);
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
<% end %>
|
||||
|
||||
</div>
|
||||
|
||||
<% unless local_assigns[:hide_controls] %>
|
||||
<div class="flex space-x-3">
|
||||
<% if current_user&.admin? || game.administrator == current_user %>
|
||||
<%= link_to "設定", edit_game_path(game), class: "inline-flex items-center px-4 py-2 border border-gray-300 shadow-sm text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500" %>
|
||||
<%= button_to "削除", game, method: :delete, class: "inline-flex items-center px-4 py-2 border border-transparent text-sm font-medium rounded-md text-white bg-red-600 hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500", data: { turbo_confirm: "本当に削除しますか?" } %>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<% # ゲーム画面(games/show)と統一されたデザインでターン情報を表示 %>
|
||||
<%
|
||||
target_turn = defined?(display_turn) && display_turn ? display_turn : game.latest_turn
|
||||
%>
|
||||
<% if target_turn && target_turn.phase.present? %>
|
||||
<%
|
||||
# フェーズ名パース (例: S1901M)
|
||||
phase = target_turn.phase
|
||||
year = phase[1..4]
|
||||
season_code = phase[0]
|
||||
type_code = phase[-1]
|
||||
|
||||
season = case season_code
|
||||
when 'S' then '春'
|
||||
when 'F' then '秋'
|
||||
when 'W' then '冬'
|
||||
else ''
|
||||
end
|
||||
|
||||
type = case type_code
|
||||
when 'M' then '移動'
|
||||
when 'R' then '撤退'
|
||||
when 'A' then '調整'
|
||||
else ''
|
||||
end
|
||||
|
||||
display_date = "#{year}年 #{season} (#{type})"
|
||||
%>
|
||||
|
||||
<div class="bg-white shadow overflow-hidden sm:rounded-lg border border-gray-200 mb-6">
|
||||
<div class="px-6 py-4 border-b border-gray-200 flex justify-between items-center bg-gray-50">
|
||||
<div>
|
||||
<h2 class="text-2xl font-bold text-gray-900"><%= display_date %></h2>
|
||||
<div class="mt-1 flex items-center space-x-4 text-sm text-gray-600">
|
||||
<span>ターン: <%= target_turn.number %></span>
|
||||
<span class="text-gray-400">|</span>
|
||||
<span>フェーズ: <%= phase %></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center space-x-4">
|
||||
<% if defined?(current_participant) && current_participant&.power %>
|
||||
<div class="flex items-center bg-white px-4 py-2 rounded border border-gray-300 shadow-sm">
|
||||
<span class="mr-2 text-sm text-gray-500">あなたの担当国:</span>
|
||||
<span class="text-lg font-bold text-indigo-700"><%= current_participant.power %></span>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
@@ -414,6 +414,45 @@
|
||||
|
||||
<!-- 右カラム: 情報パネル (1/3) -->
|
||||
<div class="space-y-6">
|
||||
<!-- 掲示板リンク -->
|
||||
<div class="bg-white shadow rounded-lg border border-gray-200 overflow-hidden">
|
||||
<div class="p-4 flex items-center justify-between">
|
||||
<div class="flex items-center">
|
||||
<div class="flex-shrink-0 bg-indigo-100 rounded-md p-3">
|
||||
<i class="fa-solid fa-comments text-indigo-600 text-xl"></i>
|
||||
</div>
|
||||
<div class="ml-4">
|
||||
<h3 class="text-lg font-medium text-gray-900">外交・交渉掲示板</h3>
|
||||
<p class="text-sm text-gray-500">
|
||||
秘密交渉や全体アナウンスはこちら
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<%= link_to game_boards_path(@game), class: "inline-flex items-center px-4 py-2 border border-transparent text-sm font-medium rounded-md shadow-sm text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500" do %>
|
||||
掲示板へ
|
||||
<%
|
||||
# 未読件数取得(参加中の全掲示板の合計)
|
||||
current_participant = @game.participants.find_by(user: current_user)
|
||||
if current_participant
|
||||
total_unread = 0
|
||||
current_participant.boards.each do |board|
|
||||
total_unread += board.unread_count_for(current_participant)
|
||||
end
|
||||
if total_unread > 0
|
||||
%>
|
||||
<span class="ml-2 inline-flex items-center justify-center px-2 py-1 text-xs font-bold leading-none text-red-100 bg-red-600 rounded-full">
|
||||
<%= total_unread %>
|
||||
</span>
|
||||
<%
|
||||
end
|
||||
end
|
||||
%>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 国ステータス表 -->
|
||||
<div class="bg-white shadow rounded-lg border border-gray-200 overflow-hidden">
|
||||
<div class="px-4 py-3 bg-gray-50 border-b border-gray-200">
|
||||
|
||||
Reference in New Issue
Block a user