feat: randomize community clans section

This commit is contained in:
devRaGonSa
2026-03-21 00:32:37 +01:00
parent 566a5d0296
commit 0917a0be1f
10 changed files with 287 additions and 56 deletions

View File

@@ -0,0 +1,107 @@
# TASK-040-randomized-community-clans-section
## Goal
Implementar una sección única de clanes/comunidades en la landing principal, mostrando los clanes indicados con sus logos y enlaces a Discord, en orden aleatorio en cada carga de página.
## Context
La home ya incorpora una sección de clanes/comunidad, pero ahora hay una definición concreta de qué clanes deben aparecer, qué logos deben usarse y qué Discord debe enlazarse en cada caso. La sección debe ser única, clara y mantenible, y el orden de los clanes debe variar aleatoriamente cada vez que se cargue la página.
## Datos a usar
Los clanes/comunidades que deben mostrarse son estos:
1. LCM
- Discord: `https://discord.gg/9F9S353QZv`
- Logo: usar la imagen proporcionada para LCM
2. La 129
- Discord: placeholder por ahora
- Logo: usar la imagen proporcionada para La 129
3. 250 Hispania
- Discord: `https://discord.gg/3E62Yb6Aw3`
- Logo: usar solo el escudo de la imagen proporcionada, quitando la parte de texto `Historia de la 250` y quedándose únicamente con el emblema/escudo
4. H9H
- Discord: `https://discord.gg/tYnXK7MQjB`
- Logo: placeholder por ahora
5. BxB
- Discord: placeholder por ahora
- Logo: usar la imagen proporcionada para BxB
6. 7dv
- Discord: `https://discord.gg/3sxNQZwrg6`
- Logo: usar la imagen proporcionada para 7dv
## Steps
1. Revisar la landing actual y la sección de clanes/comunidad ya existente.
2. Ajustar la sección para que muestre exactamente estos 6 clanes/comunidades y no una lista distinta.
3. Mantener toda la información de los clanes en una estructura de datos clara y mantenible, preferiblemente en JS si eso encaja mejor con el renderizado actual.
4. Implementar la sección para mostrar, como mínimo, por cada clan:
- logo
- nombre
- botón o enlace a Discord
5. Hacer que el orden de aparición de los clanes sea aleatorio en cada carga de página.
6. Asegurar que la aleatorización no rompe la estructura visual ni genera duplicados.
7. Para los clanes con Discord aún no definido (`La 129` y `BxB`), mostrar un estado coherente y no roto, por ejemplo:
- botón deshabilitado
- etiqueta `Próximamente`
- o equivalente visual claro y honesto
8. Para los clanes con logo pendiente (`H9H`), usar un placeholder visual coherente con la estética de la web.
9. Para `250 Hispania`, usar solo el escudo/emblema, sin el texto `Historia de la 250`.
10. Mantener la sección como una única sección de comunidad/clanes en la home, sin duplicarla.
11. Asegurar que la sección funciona correctamente en escritorio y móvil.
12. Mantener la estética coherente con la landing actual.
13. Al completar la implementación:
- dejar el repositorio consistente
- hacer commit
- hacer push al remoto si el entorno lo permite
## Files to Read First
- AGENTS.md
- frontend/index.html
- frontend/assets/css/styles.css
- frontend/assets/js/main.js
- cualquier archivo actual de datos/renderizado de la sección de clanes si ya existe
- assets actuales relacionados con logos de comunidad
## Expected Files to Modify
- frontend/index.html
- frontend/assets/css/styles.css
- frontend/assets/js/main.js
- opcionalmente un archivo de datos/config si mejora claridad, por ejemplo:
- frontend/assets/js/community-clans.js
- opcionalmente nuevos assets referenciados correctamente si la implementación los necesita, por ejemplo dentro de:
- frontend/assets/img/clans/
## Constraints
- No romper la landing actual.
- No crear varias secciones de clanes; debe quedar una sola.
- No introducir frameworks nuevos.
- No depender de widgets externos o iframes de Discord para esta sección.
- No hacer cambios destructivos.
- Mantener el trabajo centrado en la sección de clanes, su contenido real y el orden aleatorio por carga.
## Validation
- La home muestra una única sección de clanes/comunidades.
- Aparecen exactamente estos 6 clanes/comunidades:
- LCM
- La 129
- 250 Hispania
- H9H
- BxB
- 7dv
- El orden cambia aleatoriamente en cada carga de página.
- Los enlaces de Discord correctos funcionan para:
- LCM
- 250 Hispania
- H9H
- 7dv
- Los clanes sin enlace definitivo no muestran botones rotos.
- `250 Hispania` usa solo el escudo/emblema, sin el texto lateral.
- La sección sigue siendo visualmente coherente y responsive.
- Los cambios quedan committeados y se hace push al remoto si el entorno lo permite.
## Change Budget
- Preferir menos de 6 archivos modificados o creados.
- Preferir menos de 260 líneas cambiadas.

View File

@@ -790,6 +790,14 @@ h2 {
background: linear-gradient(180deg, rgba(19, 24, 16, 0.82), rgba(10, 13, 9, 0.66));
}
.clan-card__logo--wide {
padding-inline: 8px;
}
.clan-card__logo--shield {
padding-inline: 18px;
}
.clan-card__logo img {
width: auto;
height: auto;
@@ -798,6 +806,29 @@ h2 {
object-fit: contain;
}
.clan-card__logo-placeholder {
width: 100%;
min-height: 84px;
display: grid;
place-items: center;
border: 1px dashed rgba(210, 182, 118, 0.22);
border-radius: 14px;
background:
linear-gradient(180deg, rgba(28, 32, 24, 0.88), rgba(12, 15, 11, 0.7)),
repeating-linear-gradient(
135deg,
rgba(255, 255, 255, 0.02) 0,
rgba(255, 255, 255, 0.02) 10px,
transparent 10px,
transparent 20px
);
color: var(--accent-warm);
font-size: 0.88rem;
font-weight: 700;
letter-spacing: 0.18em;
text-transform: uppercase;
}
.clan-card__copy {
display: grid;
gap: 8px;
@@ -831,6 +862,14 @@ h2 {
min-width: 180px;
}
.server-action-link--disabled {
border-color: rgba(159, 168, 141, 0.18);
background: linear-gradient(180deg, rgba(42, 46, 39, 0.5), rgba(19, 22, 17, 0.7));
color: var(--muted);
cursor: default;
pointer-events: none;
}
@media (max-width: 1120px) {
.hero__brand {
grid-template-columns: 1fr;
@@ -947,6 +986,10 @@ h2 {
justify-items: start;
}
.clan-card__logo {
width: 100%;
}
.clan-card__link {
width: 100%;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 362 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 MiB

View File

@@ -6,13 +6,70 @@ const SERVER_HISTORY_URLS = Object.freeze({
});
const COMMUNITY_CLANS = Object.freeze([
{
name: "Comunidad Hispana HLL Vietnam",
badge: "Comunidad anfitriona",
name: "LCM",
badge: "Comunidad aliada",
description:
"Punto principal de reunion para escuadras, anuncios y acceso directo al Discord del proyecto.",
logoSrc: "./assets/img/logo.png",
logoAlt: "Logo de Comunidad Hispana HLL Vietnam",
discordUrl: "https://discord.com/invite/PedEqZ2Xsa",
"Clan visible dentro de la red comunitaria hispana con acceso confirmado a Discord.",
logoSrc: "./assets/img/clans/lcm.png",
logoAlt: "Logo de LCM",
logoClassName: "",
discordUrl: "https://discord.gg/9F9S353QZv",
discordLabel: "Abrir Discord",
},
{
name: "La 129",
badge: "Discord pendiente",
description:
"Presencia confirmada para la seccion comunitaria mientras se publica su acceso definitivo.",
logoSrc: "./assets/img/clans/la129.png",
logoAlt: "Logo de La 129",
logoClassName: "clan-card__logo--wide",
discordUrl: "",
discordLabel: "Proximamente",
},
{
name: "250 Hispania",
badge: "Comunidad aliada",
description:
"Entrada mostrada con su emblema principal y acceso confirmado al Discord compartido.",
logoSrc: "./assets/img/clans/250hispania-shield.png",
logoAlt: "Escudo de 250 Hispania",
logoClassName: "clan-card__logo--shield",
discordUrl: "https://discord.gg/3E62Yb6Aw3",
discordLabel: "Abrir Discord",
},
{
name: "H9H",
badge: "Logo pendiente",
description:
"Comunidad incluida en la rotacion mientras se incorpora su identidad visual final.",
logoSrc: "",
logoAlt: "",
logoClassName: "",
discordUrl: "https://discord.gg/tYnXK7MQjB",
discordLabel: "Abrir Discord",
placeholderLabel: "H9H",
},
{
name: "BxB",
badge: "Discord pendiente",
description:
"Clan incorporado a la red visible con su emblema actual y enlace aun por confirmar.",
logoSrc: "./assets/img/clans/bxb.png",
logoAlt: "Logo de BxB",
logoClassName: "",
discordUrl: "",
discordLabel: "Proximamente",
},
{
name: "7dv",
badge: "Comunidad aliada",
description:
"Entrada activa dentro de la seccion con acceso disponible a su Discord comunitario.",
logoSrc: "./assets/img/clans/7dv.png",
logoAlt: "Logo de 7dv",
logoClassName: "",
discordUrl: "https://discord.gg/3sxNQZwrg6",
discordLabel: "Abrir Discord",
},
]);
@@ -246,28 +303,70 @@ function hydrateCommunityClans(listNode) {
return;
}
listNode.innerHTML = COMMUNITY_CLANS.map((clan) => renderCommunityClanCard(clan)).join("");
listNode.innerHTML = shuffleItems(COMMUNITY_CLANS)
.map((clan) => renderCommunityClanCard(clan))
.join("");
}
function renderCommunityClanCard(clan) {
const logoMarkup = renderClanLogo(clan);
const discordMarkup = renderClanDiscordLink(clan);
return `
<article class="clan-card">
<div class="clan-card__brand">
<div class="clan-card__logo">
<img
src="${escapeHtml(clan.logoSrc)}"
alt="${escapeHtml(clan.logoAlt)}"
width="1024"
height="1044"
decoding="async"
/>
</div>
${logoMarkup}
<div class="clan-card__copy">
<p class="clan-card__eyebrow">${escapeHtml(clan.badge)}</p>
<h3>${escapeHtml(clan.name)}</h3>
<p>${escapeHtml(clan.description)}</p>
</div>
</div>
${discordMarkup}
</article>
`;
}
function renderClanLogo(clan) {
const logoClassNames = ["clan-card__logo"];
if (clan.logoClassName) {
logoClassNames.push(clan.logoClassName);
}
if (clan.logoSrc) {
return `
<div class="${escapeHtml(logoClassNames.join(" "))}">
<img
src="${escapeHtml(clan.logoSrc)}"
alt="${escapeHtml(clan.logoAlt)}"
decoding="async"
/>
</div>
`;
}
return `
<div class="${escapeHtml(logoClassNames.join(" "))}">
<div class="clan-card__logo-placeholder" aria-label="Logo pendiente de ${escapeHtml(clan.name)}">
${escapeHtml(clan.placeholderLabel || clan.name)}
</div>
</div>
`;
}
function renderClanDiscordLink(clan) {
if (!clan.discordUrl) {
return `
<span
class="server-action-link server-action-link--disabled clan-card__link"
aria-disabled="true"
>
${escapeHtml(clan.discordLabel)}
</span>
`;
}
return `
<a
class="server-action-link clan-card__link"
href="${escapeHtml(clan.discordUrl)}"
@@ -276,7 +375,6 @@ function renderCommunityClanCard(clan) {
>
${escapeHtml(clan.discordLabel)}
</a>
</article>
`;
}
@@ -384,6 +482,19 @@ async function fetchJson(url) {
return response.json();
}
function shuffleItems(items) {
const shuffledItems = [...items];
for (let currentIndex = shuffledItems.length - 1; currentIndex > 0; currentIndex -= 1) {
const randomIndex = Math.floor(Math.random() * (currentIndex + 1));
[shuffledItems[currentIndex], shuffledItems[randomIndex]] = [
shuffledItems[randomIndex],
shuffledItems[currentIndex],
];
}
return shuffledItems;
}
function escapeHtml(value) {
return String(value)
.replaceAll("&", "&amp;")

View File

@@ -172,40 +172,10 @@
<h2 id="clans-title">Red de comunidad</h2>
</div>
<p class="panel__intro">
Espacio para mantener visibles las comunidades y clanes con los que
compartimos actividad, eventos o coordinacion en Discord.
Clanes y comunidades activas de la escena hispana con presencia
confirmada o en preparacion para esta red compartida.
</p>
<div class="clans-grid" id="community-clans-list">
<article class="clan-card">
<div class="clan-card__brand">
<div class="clan-card__logo">
<img
src="./assets/img/logo.png"
alt="Logo de Comunidad Hispana HLL Vietnam"
width="1024"
height="1044"
decoding="async"
/>
</div>
<div class="clan-card__copy">
<p class="clan-card__eyebrow">Comunidad anfitriona</p>
<h3>Comunidad Hispana HLL Vietnam</h3>
<p>
Punto principal de reunion para escuadras, anuncios y acceso
directo al Discord del proyecto.
</p>
</div>
</div>
<a
class="server-action-link clan-card__link"
href="https://discord.com/invite/PedEqZ2Xsa"
target="_blank"
rel="noreferrer"
>
Abrir Discord
</a>
</article>
</div>
<div class="clans-grid" id="community-clans-list"></div>
</div>
</section>
</main>