asxpio/views/bingo/index.erb
Sergei Poljanski 9e885dd8c1
bingo: operational-only view of the card
The card mixes facilities in service with construction projects (Sber
Balakovo at #1, MOS7, MOS11, Yandex Vladimir-2), which is fine for a
bingo but not when you want to compare what actually runs today. Add a
toggle that builds the card from operational rows only, in the same
ranking, with bingo lines recomputed for that card. The filtered view is
noindex with canonical to the plain locale URL, so it does not compete
with the main page in search.

Assisted-by: Claude:opus-5
2026-10-10 06:58:30 +04:00

110 lines
4.5 KiB
Text

<% b = @board %>
<main>
<header>
<h1><%= t(:lead) %> <span><%= t(:accent) %></span></h1>
<div class="switches">
<nav class="toggle" aria-label="<%= t(:view_label) %>">
<% Bingo::VIEWS.each do |v| %>
<a href="<%= card_path(@locale, v) %>" rel="nofollow" <%== 'aria-current="page"' if v == @view %>><%= t(:"view_#{v}") %></a>
<% end %>
</nav>
<nav class="langs">
<% Bingo::LOCALES.each do |l| %>
<a href="<%= card_path(l) %>" hreflang="<%= l %>" lang="<%= l %>" <%== 'aria-current="page"' if l == @locale %>><%= l %></a>
<% end %>
</nav>
</div>
</header>
<p class="lead"><%= t(:desc) %></p>
<p class="meta">
<%= t(:crossed) %> <b><%= b.hit.count(true) %></b>/<%= b.cells.size %>
· <%= t(:lines) %> <b><%= b.wins.size %></b>
<% if b.updated_on %>· <%= t(:updated) %> <b><%= fmt_date(b.updated_on) %></b><% end %>
</p>
<% if b.wins.any? %>
<div class="banner">
<%= b.wins.size == Bingo::LINES.size ? t(:full) : b.wins.size > 1 ? format(t(:bingo_n), b.wins.size) : t(:bingo) %>
</div>
<% end %>
<div class="letters" aria-hidden="true"><% t(:letters).each do |ch| %><div><%= ch %></div><% end %></div>
<div class="grid">
<% b.cells.each_with_index do |dc, idx| %>
<% photo = photo_path(dc, 480) %>
<button type="button" data-dlg="dlg-<%= dc.slug %>"
class="cell<%= ' photo' if photo %><%= ' hit' if b.hit[idx] %><%= ' win' if b.win_cells.include?(idx) %>"
aria-label="<%= dc.l(:name, @locale) %><%= " — #{kind_label(dc.incidents.first.kind)}" if b.hit[idx] %>">
<% if photo %><img class="bg" src="<%= photo %>" alt="" width="480" height="480" decoding="async"<%== ' loading="lazy"' if idx >= 10 %>><% end %>
<div>
<div class="n">#<%= idx + 1 %><%= " · #{mw(dc)}" if mw(dc) %></div>
<% if dc.building? %><div class="tag"><%= t(:building) %></div><% end %>
</div>
<div>
<div class="name"><%= dc.l(:name, @locale) %></div>
<div class="sub"><%= dc.l(:city, @locale) %></div>
</div>
<% if b.hit[idx] %><div class="stamp"><%= kind_icon(dc.incidents.first.kind) %></div><% end %>
</button>
<% end %>
</div>
<section>
<h2><%= t(:log) %></h2>
<ul class="log">
<% if b.incidents.empty? %>
<li class="empty"><%= t(:empty) %></li>
<% end %>
<% b.incidents.each do |i| %>
<li>
<time datetime="<%= i.occurred_on %>"><%= fmt_date(i.occurred_on) %></time>
<span><%= kind_icon(i.kind) %></span>
<div>
<% if i.url %><a href="<%= i.url %>" target="_blank" rel="noopener nofollow"><%= i.l(:title, @locale) %></a><% else %><%= i.l(:title, @locale) %><% end %>
<div class="dc"><%= i.datacenter.l(:name, @locale) %> · <%= kind_label(i.kind) %></div>
</div>
</li>
<% end %>
</ul>
</section>
<footer>
<p><%= t(:footer) %></p>
<p>© <%= Date.today.year %> <a href="https://asxp.io">asxp.io</a></p>
</footer>
</main>
<% b.cells.each do |dc| %>
<dialog id="dlg-<%= dc.slug %>">
<% if (photo = photo_path(dc, 1200)) %><img src="<%= photo %>" alt="<%= dc.l(:name, @locale) %>, <%= dc.l(:city, @locale) %>" loading="lazy" decoding="async"><% end %>
<div class="body">
<h3><%= dc.l(:name, @locale) %></h3>
<div class="meta">
<%= [dc.operator, mw(dc), dc.l(:city, @locale), dc.building? ? t(:building) : (dc.year && format(t(:since), dc.year))].compact.join(' · ') %>
</div>
<% if dc.photo_credit || dc.info_url %>
<div class="credit">
<% if dc.photo_credit %><%= t(:photo) %>: <%= dc.photo_credit %><% end %>
<% if dc.info_url %> · <a href="<%= dc.info_url %>" target="_blank" rel="noopener nofollow"><%= t(:source) %></a><% end %>
</div>
<% end %>
<% if dc.incidents.empty? %>
<p class="empty"><%= t(:no_incidents) %></p>
<% else %>
<ul>
<% dc.incidents.each do |i| %>
<li><%= kind_icon(i.kind) %> <%= fmt_date(i.occurred_on) %> —
<% if i.url %><a href="<%= i.url %>" target="_blank" rel="noopener nofollow"><%= i.l(:title, @locale) %></a><% else %><%= i.l(:title, @locale) %><% end %></li>
<% end %>
</ul>
<% end %>
<form method="dialog"><button><%= t(:close) %></button></form>
</div>
</dialog>
<% end %>
<script>
document.querySelectorAll('[data-dlg]').forEach(b =>
b.addEventListener('click', () => document.getElementById(b.dataset.dlg).showModal()));
</script>