Aggiunge i18n IT/EN/FR/DE/ES, pagine pubbliche squadre e UX archivio.
Il selettore lingua funziona sul web e sulle app native; su Android la preferenza è persistita e applicata al riavvio. Incluse anche eliminazione replay a scope e campi pagina pubblica squadra. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -1,20 +1,21 @@
|
||||
<div id="cookie-banner" class="cookie-banner" role="dialog" aria-labelledby="cookie-banner-title" aria-describedby="cookie-banner-desc" hidden>
|
||||
<div class="cookie-banner__inner">
|
||||
<div class="cookie-banner__text">
|
||||
<p id="cookie-banner-title" class="cookie-banner__title">Cookie e privacy</p>
|
||||
<p id="cookie-banner-title" class="cookie-banner__title"><%= t("cookie.title") %></p>
|
||||
<p id="cookie-banner-desc" class="cookie-banner__desc">
|
||||
Usiamo cookie necessari per login e sicurezza. Con il tuo consenso attiviamo anche
|
||||
<strong>Google Analytics</strong> per statistiche aggregate sul sito.
|
||||
<%= link_to "Cookie policy", public_cookies_path, class: "cookie-banner__link" %>
|
||||
e <%= link_to "Privacy", public_privacy_path, class: "cookie-banner__link" %>.
|
||||
<%= raw t(
|
||||
"cookie.body_html",
|
||||
cookie_link: link_to(t("cookie.policy"), public_cookies_path, class: "cookie-banner__link"),
|
||||
privacy_link: link_to(t("cookie.privacy"), public_privacy_path, class: "cookie-banner__link")
|
||||
) %>
|
||||
</p>
|
||||
</div>
|
||||
<div class="cookie-banner__actions">
|
||||
<button type="button" class="btn btn-secondary cookie-banner__btn" data-cookie-reject>
|
||||
Solo necessari
|
||||
<%= t("cookie.reject") %>
|
||||
</button>
|
||||
<button type="button" class="btn btn-primary cookie-banner__btn" data-cookie-accept-all>
|
||||
Accetta tutti
|
||||
<%= t("cookie.accept_all") %>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
<%# Selettore lingua a bandiere (allineato a destra nel menu) %>
|
||||
<% current = current_language_option %>
|
||||
<div class="lang-switcher" data-lang-switcher>
|
||||
<button
|
||||
type="button"
|
||||
class="lang-switcher__toggle"
|
||||
id="lang-switcher-toggle"
|
||||
aria-haspopup="listbox"
|
||||
aria-expanded="false"
|
||||
aria-controls="lang-switcher-menu"
|
||||
aria-label="<%= t('language.choose') %>: <%= current[:native] %>"
|
||||
title="<%= current[:native] %>"
|
||||
>
|
||||
<span class="lang-switcher__flag" aria-hidden="true"><%= current[:flag] %></span>
|
||||
<span class="lang-switcher__chevron" aria-hidden="true"></span>
|
||||
</button>
|
||||
|
||||
<div
|
||||
class="lang-switcher__menu"
|
||||
id="lang-switcher-menu"
|
||||
role="listbox"
|
||||
aria-label="<%= t('language.label') %>"
|
||||
hidden
|
||||
>
|
||||
<% language_options.each do |opt| %>
|
||||
<% selected = opt[:code].to_s == current_locale.to_s %>
|
||||
<%= button_to public_locale_path,
|
||||
method: :patch,
|
||||
params: { locale: opt[:code] },
|
||||
class: "lang-switcher__option#{' is-active' if selected}",
|
||||
form: { class: "lang-switcher__option-form" },
|
||||
role: "option",
|
||||
aria: { selected: selected, label: opt[:native] },
|
||||
title: opt[:native] do %>
|
||||
<span class="lang-switcher__flag" aria-hidden="true"><%= opt[:flag] %></span>
|
||||
<span class="visually-hidden"><%= opt[:native] %></span>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
(function () {
|
||||
var root = document.querySelector("[data-lang-switcher]");
|
||||
if (!root || root.dataset.bound === "1") return;
|
||||
root.dataset.bound = "1";
|
||||
|
||||
var toggle = root.querySelector(".lang-switcher__toggle");
|
||||
var menu = root.querySelector(".lang-switcher__menu");
|
||||
if (!toggle || !menu) return;
|
||||
|
||||
function setOpen(open) {
|
||||
menu.hidden = !open;
|
||||
toggle.setAttribute("aria-expanded", open ? "true" : "false");
|
||||
root.classList.toggle("is-open", open);
|
||||
}
|
||||
|
||||
toggle.addEventListener("click", function (e) {
|
||||
e.stopPropagation();
|
||||
setOpen(menu.hidden);
|
||||
});
|
||||
|
||||
document.addEventListener("click", function (e) {
|
||||
if (!root.contains(e.target)) setOpen(false);
|
||||
});
|
||||
|
||||
document.addEventListener("keydown", function (e) {
|
||||
if (e.key === "Escape") setOpen(false);
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
@@ -1,20 +1,20 @@
|
||||
<footer class="site-footer">
|
||||
<div class="wrap">
|
||||
<div>
|
||||
<strong style="color:#fff">Match Live TV</strong> — Ogni partita, ogni evento, per chi non può esserci
|
||||
<strong style="color:#fff">Match Live TV</strong> — <%= t("footer.tagline") %>
|
||||
</div>
|
||||
<div>
|
||||
<%= link_to "Prezzi", public_prezzi_path %> ·
|
||||
<%= link_to "Dirette", public_live_index_path %> ·
|
||||
<%= link_to "FAQ", public_faq_path %> ·
|
||||
<%= link_to "Privacy", public_privacy_path %> ·
|
||||
<%= link_to "Cookie", public_cookies_path %> ·
|
||||
<%= link_to "Termini", public_termini_path %>
|
||||
· <button type="button" class="footer-link-btn" data-cookie-manage>Gestisci cookie</button>
|
||||
<%= link_to t("common.pricing"), public_prezzi_path %> ·
|
||||
<%= link_to t("footer.live"), public_live_index_path %> ·
|
||||
<%= link_to t("common.faq"), public_faq_path %> ·
|
||||
<%= link_to t("common.privacy"), public_privacy_path %> ·
|
||||
<%= link_to t("common.cookies"), public_cookies_path %> ·
|
||||
<%= link_to t("common.terms"), public_termini_path %>
|
||||
· <button type="button" class="footer-link-btn" data-cookie-manage><%= t("footer.manage_cookies") %></button>
|
||||
</div>
|
||||
<div class="site-footer__legal">
|
||||
<p>© 2026 Emiliano Frascaro – P. IVA 14230270960</p>
|
||||
<p>I contenuti trasmessi sono di esclusiva responsabilità delle società sportive che li pubblicano.</p>
|
||||
<p><%= t("footer.copyright") %></p>
|
||||
<p><%= t("footer.responsibility") %></p>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
@@ -7,35 +7,41 @@
|
||||
<span class="brand" aria-hidden="true">Match <span>Live TV</span></span>
|
||||
<% end %>
|
||||
|
||||
<button type="button" class="nav-toggle" aria-label="Apri menu" aria-expanded="false" aria-controls="site-nav">
|
||||
<span class="nav-toggle-bar" aria-hidden="true"></span>
|
||||
<span class="nav-toggle-bar" aria-hidden="true"></span>
|
||||
<span class="nav-toggle-bar" aria-hidden="true"></span>
|
||||
</button>
|
||||
<div class="mast-tools">
|
||||
<button type="button" class="nav-toggle" aria-label="<%= t('nav.open_menu') %>" aria-expanded="false" aria-controls="site-nav">
|
||||
<span class="nav-toggle-bar" aria-hidden="true"></span>
|
||||
<span class="nav-toggle-bar" aria-hidden="true"></span>
|
||||
<span class="nav-toggle-bar" aria-hidden="true"></span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<nav id="site-nav" class="nav" aria-label="Menu principale" aria-hidden="true">
|
||||
<nav id="site-nav" class="nav" aria-label="<%= t('nav.main_menu') %>" aria-hidden="true">
|
||||
<div class="nav-panel">
|
||||
<%= link_to "Home", root_path, class: (request.path == "/" ? "nav-active" : nil) %>
|
||||
<%= link_to "Funzionalità", public_features_path, class: (request.path == "/funzionalita" ? "nav-active" : nil) %>
|
||||
<%= link_to "Prezzi", public_prezzi_path, class: (request.path == "/prezzi" ? "nav-active" : nil) %>
|
||||
<%= link_to "FAQ", public_faq_path, class: (request.path == "/faq" ? "nav-active" : nil) %>
|
||||
<%= link_to "Dirette live", public_live_index_path, class: (live_section ? "nav-active" : nil) %>
|
||||
<%= link_to t("nav.home"), root_path, class: (request.path == "/" ? "nav-active" : nil) %>
|
||||
<%= link_to t("nav.features"), public_features_path, class: (request.path == "/funzionalita" ? "nav-active" : nil) %>
|
||||
<%= link_to t("nav.pricing"), public_prezzi_path, class: (request.path == "/prezzi" ? "nav-active" : nil) %>
|
||||
<%= link_to t("nav.faq"), public_faq_path, class: (request.path == "/faq" ? "nav-active" : nil) %>
|
||||
<%= link_to t("nav.live"), public_live_index_path, class: (live_section ? "nav-active" : nil) %>
|
||||
<%= link_to t("nav.teams"), public_team_pages_path, class: (request.path.start_with?("/squadre") ? "nav-active" : nil) %>
|
||||
<div class="nav-actions">
|
||||
<% if logged_in? %>
|
||||
<% if current_user.primary_club || current_user.manageable_teams.any? %>
|
||||
<% if current_user.primary_club %>
|
||||
<%= link_to "Società", public_club_path(current_user.primary_club), class: "nav-link-item" %>
|
||||
<%= link_to t("nav.my_club"), public_club_path(current_user.primary_club), class: "nav-link-item" %>
|
||||
<% elsif current_user.manageable_teams.first %>
|
||||
<%= link_to "Dettagli squadra", public_team_details_path(current_user.manageable_teams.first), class: "nav-link-item" %>
|
||||
<%= link_to t("nav.my_team"), public_team_details_path(current_user.manageable_teams.first), class: "nav-link-item" %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
<%= button_to "Esci", public_logout_path, method: :delete, class: "btn btn-secondary nav-btn" %>
|
||||
<%= button_to t("nav.logout"), public_logout_path, method: :delete, class: "btn btn-secondary nav-btn" %>
|
||||
<% else %>
|
||||
<%= link_to "Accedi", public_login_path, class: "nav-link-item" %>
|
||||
<%= link_to "Registra squadra", public_signup_path, class: "btn btn-primary nav-btn" %>
|
||||
<%= link_to t("nav.login"), public_login_path, class: "nav-link-item" %>
|
||||
<%= link_to t("nav.signup"), public_signup_path, class: "btn btn-primary nav-btn" %>
|
||||
<% end %>
|
||||
<div class="nav-lang">
|
||||
<%= render "shared/language_switcher" %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
@@ -50,12 +56,14 @@
|
||||
var backdrop = document.getElementById("nav-backdrop");
|
||||
var nav = document.getElementById("site-nav");
|
||||
if (!chrome || !toggle || !nav) return;
|
||||
var openLabel = <%= raw t("nav.open_menu").to_json %>;
|
||||
var closeLabel = <%= raw t("nav.close_menu").to_json %>;
|
||||
|
||||
function setOpen(open) {
|
||||
chrome.classList.toggle("nav-open", open);
|
||||
document.body.classList.toggle("nav-menu-open", open);
|
||||
toggle.setAttribute("aria-expanded", open ? "true" : "false");
|
||||
toggle.setAttribute("aria-label", open ? "Chiudi menu" : "Apri menu");
|
||||
toggle.setAttribute("aria-label", open ? closeLabel : openLabel);
|
||||
nav.setAttribute("aria-hidden", open ? "false" : "true");
|
||||
if (backdrop) backdrop.setAttribute("aria-hidden", open ? "false" : "true");
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<% description = content_for?(:meta_description) ? yield(:meta_description) : "Diretta live delle partite giovanili dal telefono: genitori e nonni guardano dal browser, senza app. Archivio partite per non perderle." %>
|
||||
<% page_title = content_for?(:title) ? yield(:title) : "Match Live TV — Diretta live partite giovanili" %>
|
||||
<% description = content_for?(:meta_description) ? yield(:meta_description) : t("meta.default_description") %>
|
||||
<% page_title = content_for?(:title) ? yield(:title) : t("meta.default_title") %>
|
||||
<meta name="description" content="<%= description %>">
|
||||
<meta name="application-name" content="Match Live TV">
|
||||
<meta name="robots" content="<%= seo_robots_content %>">
|
||||
@@ -9,9 +9,9 @@
|
||||
<meta property="og:description" content="<%= description %>">
|
||||
<meta property="og:type" content="website">
|
||||
<meta property="og:url" content="<%= seo_canonical_url %>">
|
||||
<meta property="og:locale" content="it_IT">
|
||||
<meta property="og:locale" content="<%= og_locale_tag %>">
|
||||
<meta property="og:image" content="<%= seo_og_image_url %>">
|
||||
<meta property="og:image:alt" content="Match Live TV — diretta live partite giovanili da smartphone">
|
||||
<meta property="og:image:alt" content="<%= t('meta.og_image_alt') %>">
|
||||
<meta name="twitter:card" content="summary_large_image">
|
||||
<meta name="twitter:title" content="<%= page_title %>">
|
||||
<meta name="twitter:description" content="<%= description %>">
|
||||
|
||||
Reference in New Issue
Block a user