Polish public page navigation and copy
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
:root {
|
||||
:root {
|
||||
--bg: #0f120d;
|
||||
--bg-deep: #090b08;
|
||||
--bg-elevated: rgba(27, 33, 24, 0.92);
|
||||
@@ -85,6 +85,58 @@ a {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.public-nav {
|
||||
width: min(var(--page-shell-width), calc(100vw - (var(--page-shell-gutter) * 2)));
|
||||
margin: 0 auto 16px;
|
||||
padding: 10px;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||||
gap: 12px;
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 22px;
|
||||
background:
|
||||
linear-gradient(180deg, rgba(24, 30, 22, 0.9), rgba(10, 13, 9, 0.96)),
|
||||
radial-gradient(circle at top center, rgba(183, 201, 125, 0.08), transparent 40%);
|
||||
box-shadow: var(--shadow-soft);
|
||||
}
|
||||
|
||||
.public-nav__link {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-height: 50px;
|
||||
padding: 0 18px;
|
||||
border: 1px solid rgba(159, 168, 141, 0.22);
|
||||
border-radius: 999px;
|
||||
background: linear-gradient(180deg, rgba(18, 23, 16, 0.88), rgba(10, 12, 9, 0.96));
|
||||
color: var(--text-soft);
|
||||
font-size: 0.82rem;
|
||||
font-weight: 800;
|
||||
letter-spacing: 0.12em;
|
||||
text-transform: uppercase;
|
||||
transition:
|
||||
transform 160ms ease,
|
||||
border-color 160ms ease,
|
||||
background 160ms ease,
|
||||
color 160ms ease,
|
||||
box-shadow 160ms ease;
|
||||
}
|
||||
|
||||
.public-nav__link:hover,
|
||||
.public-nav__link:focus-visible {
|
||||
transform: translateY(-1px);
|
||||
border-color: rgba(210, 182, 118, 0.48);
|
||||
background: linear-gradient(180deg, rgba(43, 50, 36, 0.94), rgba(16, 20, 14, 0.98));
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
.public-nav__link.is-active {
|
||||
border-color: rgba(183, 201, 125, 0.42);
|
||||
background: linear-gradient(180deg, rgba(183, 201, 125, 0.22), rgba(89, 101, 58, 0.28));
|
||||
color: var(--text);
|
||||
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.04);
|
||||
}
|
||||
|
||||
.hero {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
@@ -920,6 +972,11 @@ h2 {
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.stats-hero .hero__brand,
|
||||
.ranking-hero .hero__brand {
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.stats-search-form {
|
||||
margin: 0 0 14px;
|
||||
display: grid;
|
||||
@@ -1401,6 +1458,10 @@ h2 {
|
||||
}
|
||||
|
||||
@media (max-width: 760px) {
|
||||
.public-nav {
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
}
|
||||
|
||||
.servers-grid,
|
||||
.servers-grid--section,
|
||||
.clans-grid {
|
||||
@@ -1430,6 +1491,18 @@ h2 {
|
||||
font-size: 0.98rem;
|
||||
}
|
||||
|
||||
.public-nav {
|
||||
padding: 8px;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.public-nav__link {
|
||||
min-height: 46px;
|
||||
padding-inline: 12px;
|
||||
font-size: 0.74rem;
|
||||
letter-spacing: 0.08em;
|
||||
}
|
||||
|
||||
.stats-search-form__fields {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
@@ -1475,7 +1548,8 @@ h2 {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.secondary-button {
|
||||
.secondary-button,
|
||||
.public-nav__link {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
@@ -1541,3 +1615,4 @@ h2 {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
const backendBaseUrl = document.body.dataset.backendBaseUrl || "http://127.0.0.1:8000";
|
||||
const form = document.getElementById("ranking-form");
|
||||
const timeframeSelect = document.getElementById("ranking-timeframe");
|
||||
@@ -185,7 +185,7 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||
|
||||
if (isAnnual) {
|
||||
setFilterNote(
|
||||
"El ranking anual sigue limitado a kills porque solo esa metrica tiene lectura snapshot segura.",
|
||||
"El ranking anual sigue limitado a kills porque solo esa m\u00e9trica tiene lectura snapshot segura.",
|
||||
"warning",
|
||||
);
|
||||
return;
|
||||
@@ -272,7 +272,7 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||
if (!isBackendOnline) {
|
||||
setRankingState("error", "Backend no disponible. El ranking queda en estado offline.");
|
||||
renderEmptyState(
|
||||
"No fue posible contactar el backend. Reintenta cuando el servicio vuelva a estar operativo.",
|
||||
"No fue posible contactar el backend. Reintenta cuando el servicio vuelva a estar disponible.",
|
||||
);
|
||||
return;
|
||||
}
|
||||
@@ -281,8 +281,8 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||
if (timeframe === "annual") {
|
||||
year = Number.parseInt(String(yearInput?.value || "").trim(), 10);
|
||||
if (!Number.isFinite(year) || year <= 0) {
|
||||
setRankingState("error", "El ano solicitado no es valido.");
|
||||
renderEmptyState("Corrige el ano y vuelve a consultar el ranking anual.");
|
||||
setRankingState("error", "El a\u00f1o solicitado no es v\u00e1lido.");
|
||||
renderEmptyState("Corrige el a\u00f1o y vuelve a consultar el ranking anual.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -322,7 +322,7 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||
setBackendState("Backend no disponible", false);
|
||||
setRankingState("error", "Error controlado al cargar el ranking.");
|
||||
renderEmptyState(
|
||||
"La lectura del ranking fallo en este intento. Revisa el backend o actualiza la pagina.",
|
||||
"La lectura del ranking fall\u00f3 en este intento. Revisa el backend o actualiza la p\u00e1gina.",
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -343,20 +343,20 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||
) {
|
||||
setRankingState("warning", "El ranking anual solo admite kills por ahora.");
|
||||
renderEmptyState(
|
||||
"Las metricas extra estan disponibles en semanal y mensual. El ranking anual sigue limitado a kills mientras no existan snapshots seguros adicionales.",
|
||||
"Las m\u00e9tricas extra est\u00e1n disponibles en semanal y mensual. El ranking anual sigue limitado a kills mientras no existan snapshots seguros adicionales.",
|
||||
);
|
||||
return;
|
||||
}
|
||||
if (statusCode === 400 && normalizedMessage.includes("metric")) {
|
||||
setRankingState("warning", "La metrica solicitada no esta soportada.");
|
||||
setRankingState("warning", "La m\u00e9trica solicitada no est\u00e1 soportada.");
|
||||
renderEmptyState(
|
||||
"Usa kills, deaths, teamkills, partidas jugadas, K/D o kills por partida.",
|
||||
);
|
||||
return;
|
||||
}
|
||||
if (statusCode === 400 && normalizedMessage.includes("year")) {
|
||||
setRankingState("warning", "El ranking anual requiere un ano valido.");
|
||||
renderEmptyState("Define un ano valido para consultar la lectura anual.");
|
||||
setRankingState("warning", "El ranking anual requiere un a\u00f1o v\u00e1lido.");
|
||||
renderEmptyState("Define un a\u00f1o v\u00e1lido para consultar la lectura anual.");
|
||||
return;
|
||||
}
|
||||
if (statusCode === 400 && normalizedMessage.includes("timeframe")) {
|
||||
@@ -398,7 +398,7 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||
if (timeframe === "annual" && snapshotStatus === "missing") {
|
||||
setRankingState("warning", "El snapshot anual solicitado aun no fue generado.");
|
||||
renderEmptyState(
|
||||
"No existe snapshot anual para el ano y servidor elegidos. Este estado es informativo y no implica caida del backend.",
|
||||
"No existe snapshot anual para el a\u00f1o y servidor elegidos. Este estado es informativo y no implica ca\u00edda del backend.",
|
||||
);
|
||||
return;
|
||||
}
|
||||
@@ -441,10 +441,9 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||
const cards = [
|
||||
{ label: "Periodo activo", value: labelForTimeframe(timeframe), active: true },
|
||||
{ label: "Servidor activo", value: labelForServer(data.server_id), active: true },
|
||||
{ label: "Metrica activa", value: labelForMetric(metric), active: true },
|
||||
{ label: "Limite", value: `Top ${safeInt(data.limit, safeInt(defaultLimit, 20))}` },
|
||||
{ label: "M\u00e9trica activa", value: labelForMetric(metric), active: true },
|
||||
{ label: "L\u00edmite", value: `Top ${safeInt(data.limit, safeInt(defaultLimit, 20))}` },
|
||||
{ label: "Ventana", value: labelForWindow(data) },
|
||||
{ label: "Fuente", value: String(source.read_model || "No disponible") },
|
||||
{ label: "Actualizado", value: formatDateTime(source.generated_at) },
|
||||
];
|
||||
|
||||
@@ -490,7 +489,7 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||
|
||||
function labelForWindow(data) {
|
||||
if (String(data.timeframe || "") === "annual") {
|
||||
return `Ano ${safeInt(data.year, currentYear)}`;
|
||||
return `A\u00f1o ${safeInt(data.year, currentYear)}`;
|
||||
}
|
||||
return String(data.window_label || data.window_kind || "Ventana activa");
|
||||
}
|
||||
@@ -586,3 +585,4 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||
.replaceAll("'", "'");
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
const backendBaseUrl = document.body.dataset.backendBaseUrl || "http://127.0.0.1:8000";
|
||||
const searchForm = document.getElementById("stats-search-form");
|
||||
const searchInput = document.getElementById("stats-search-input");
|
||||
@@ -39,22 +39,22 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||
"Error al buscar jugadores. Verifica backend y reintenta.",
|
||||
searchReadyPrefix: "Se encontraron ",
|
||||
searchReadySuffix:
|
||||
" jugador(es). Selecciona uno para ver sus estadisticas.",
|
||||
" jugador(es). Selecciona uno para ver sus estad\u00edsticas.",
|
||||
searchShortQueryHelp:
|
||||
"Usa al menos 1 caracter para iniciar la busqueda.",
|
||||
profileLoading: "Cargando estadisticas personales...",
|
||||
"Usa al menos 1 car\u00e1cter para iniciar la b\u00fasqueda.",
|
||||
profileLoading: "Cargando estad\u00edsticas personales...",
|
||||
profileNoStats:
|
||||
"Jugador sin estadisticas suficientes para mostrar datos personales.",
|
||||
profileError: "No fue posible cargar las estadisticas del jugador.",
|
||||
"Jugador sin estad\u00edsticas suficientes para mostrar datos personales.",
|
||||
profileError: "No fue posible cargar las estad\u00edsticas del jugador.",
|
||||
annualLoading: "Cargando ranking anual...",
|
||||
annualMissing:
|
||||
"No hay snapshot generado para el ano solicitado. Mostrara estado missing hasta que exista.",
|
||||
"No hay snapshot generado para el a\u00f1o solicitado. Mostrar\u00e1 estado pending hasta que exista.",
|
||||
annualReadyEmpty:
|
||||
"Snapshot anual listo pero sin datos para el ano y servidor seleccionado.",
|
||||
"Ranking anual listo, pero sin datos para el a\u00f1o y servidor seleccionados.",
|
||||
annualUnsupportedMetric:
|
||||
"La metrica anual solicitada no esta soportada en V1.",
|
||||
"La m\u00e9trica anual solicitada no est\u00e1 soportada en V1.",
|
||||
annualMetricInvalid:
|
||||
"Parametro de ranking anual invalido. Usa metric=kills en V1.",
|
||||
"Par\u00e1metro de ranking anual inv\u00e1lido. Usa metric=kills en V1.",
|
||||
annualReadyPrefix: "Ranking anual listo para",
|
||||
weeklyPlaceholder:
|
||||
"Sin datos semanales. El ranking semanal se actualiza al cargar un jugador.",
|
||||
@@ -69,7 +69,7 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||
monthlyWindowUnavailableSummary:
|
||||
"Resumen mensual no disponible temporalmente.",
|
||||
profileReadyTitle: "Perfil personal",
|
||||
profileEmptyTitle: "Selecciona un jugador para ver sus estadisticas.",
|
||||
profileEmptyTitle: "Selecciona un jugador para ver sus estad\u00edsticas.",
|
||||
partialProfileLoadWarning:
|
||||
"Algunos bloques de ranking no se cargaron; se mantienen los disponibles.",
|
||||
};
|
||||
@@ -78,8 +78,8 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||
|
||||
if (searchHelpNode) {
|
||||
searchHelpNode.textContent =
|
||||
"Usa el buscador para encontrar un jugador. Al seleccionar uno veras resumen semanal y mensual. " +
|
||||
"El ranking anual se consulta por separado con el ano indicado.";
|
||||
"Usa el buscador para encontrar un jugador. Al seleccionar uno ver\u00e1s resumen semanal y mensual. " +
|
||||
"El ranking anual se consulta por separado con el a\u00f1o indicado.";
|
||||
}
|
||||
|
||||
setBackendState(messages.backendChecking, false);
|
||||
@@ -176,7 +176,7 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||
setBackendState(messages.backendOnline, true);
|
||||
setAnnualState(
|
||||
"neutral",
|
||||
"Backend disponible. Selecciona un ano para cargar el ranking anual (kills).",
|
||||
"Backend disponible. Selecciona un a\u00f1o para cargar el ranking anual (kills).",
|
||||
);
|
||||
void loadAnnualRanking();
|
||||
} catch (error) {
|
||||
@@ -252,7 +252,7 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||
|
||||
const year = resolveAnnualYear();
|
||||
if (year === null) {
|
||||
setAnnualState("error", "El ano ingresado no es valido.");
|
||||
setAnnualState("error", "El a\u00f1o ingresado no es v\u00e1lido.");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -345,7 +345,7 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||
|
||||
setAnnualState(
|
||||
"neutral",
|
||||
`${messages.annualReadyPrefix} ${serverId}, ano ${year}, metrica ${metric}`,
|
||||
`${messages.annualReadyPrefix} ${serverId}, a\u00f1o ${year}, m\u00e9trica ${metric}`,
|
||||
);
|
||||
|
||||
annualContentNode.innerHTML = `
|
||||
@@ -353,7 +353,7 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||
<p class="stats-summary-title">Top ${limit} anual</p>
|
||||
<div class="stats-annual-meta">
|
||||
<p><strong>Servidor:</strong> ${escapeHtml(serverId)}</p>
|
||||
<p><strong>Metrica:</strong> ${escapeHtml(metric)}</p>
|
||||
<p><strong>M\u00e9trica:</strong> ${escapeHtml(metric)}</p>
|
||||
<p><strong>Partidas fuente:</strong> ${safeInt(sourceMatches, 0)}</p>
|
||||
<p><strong>Actualizado:</strong> ${escapeHtml(generatedAt || "No disponible")}</p>
|
||||
</div>
|
||||
@@ -755,8 +755,8 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||
const metric = escapeHtml(String(ranking.metric || annualMetric));
|
||||
|
||||
return `
|
||||
<p><strong>Posicion:</strong> ${rank}</p>
|
||||
<p><strong>Metric:</strong> ${metric}</p>
|
||||
<p><strong>Posici\u00f3n:</strong> ${rank}</p>
|
||||
<p><strong>M\u00e9trica:</strong> ${metric}</p>
|
||||
<p>${escapeHtml(formatWindowRange(ranking))}</p>
|
||||
`;
|
||||
}
|
||||
@@ -783,7 +783,7 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||
if (Number.isFinite(safeParseNumber(ranking.ranking_position))) {
|
||||
return {
|
||||
tone: "ok",
|
||||
title: `Posicion #${safeInt(ranking.ranking_position, 0)}`,
|
||||
title: `Posici\u00f3n #${safeInt(ranking.ranking_position, 0)}`,
|
||||
detail: `Jugador posicionado en el ranking ${label} activo por kills.`,
|
||||
};
|
||||
}
|
||||
@@ -902,3 +902,4 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||
.replaceAll("'", "'");
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user