18 Commits

Author SHA1 Message Date
99b6f76874 Merge pull request 'Linux party 2026' (#24) from linux-party-2026 into main
Reviewed-on: #24
2026-02-19 21:33:34 +01:00
Abdulee
0e2c65b779 Changes to description 2026-02-19 21:31:58 +01:00
Abdulee
ea226e7c48 Fixed finalizado false 2026-02-19 16:36:23 +01:00
Abdulee
07e42e3d04 Linux party 2026 2026-02-19 16:33:07 +01:00
b451fdfaf2 Merge pull request 'Update README with current status' (#21) from feature/main-UpdateREADME into main
Reviewed-on: #21
2026-01-23 14:22:13 +01:00
58cb5fb5ee Update README with current status 2026-01-23 14:21:59 +01:00
d4b972cc4e Merge pull request 'feature/main-19-ActivitiesTab' (#20) from feature/main-19-ActivitiesTab into main
Reviewed-on: #20
Reviewed-by: Pablo Ferreiro <me@pabloferreiro.es>
2026-01-20 20:22:44 +01:00
326e76aac4 Delete files 2026-01-19 09:01:34 +01:00
66027471f6 Limit scope 2026-01-19 09:01:23 +01:00
2d509e352d Delete limit 2026-01-18 21:55:07 +01:00
f6ed158b0f Add Activities tab 2026-01-18 21:49:53 +01:00
404d2cb716 Merge pull request 'Update index.md' (#16) from feature/main-UpdateMainPage into main
Reviewed-on: #16
2026-01-16 19:40:03 +01:00
9bc8d09525 Update index.md 2026-01-16 19:38:49 +01:00
00b79db0d2 Merge pull request 'Fix typo in title' (#15) from fix/main-FixTypo into main
Reviewed-on: #15
2026-01-15 21:10:06 +01:00
45d8af4fb2 Fix typo in title 2026-01-15 21:09:53 +01:00
8de18ffea9 Merge pull request 'fix/main-AddNewLine' (#14) from fix/main-AddNewLine into main
Reviewed-on: #14
2026-01-15 18:27:37 +01:00
11378e5fd5 Add new line 2026-01-15 18:27:02 +01:00
2a4c4d731e Add new line 2026-01-15 18:25:47 +01:00
13 changed files with 762 additions and 14 deletions

View File

@@ -1,11 +1,7 @@
*WIP*
# Website for Open Bokeron
This repo hosts the website for Open Bokeron which is a student organization in University of Málaga whose aim is to promote the use of free(as in freedom) software.
The philosophy with this website for now is to KISS(keep it stupid simple) using only HTML5 & CSS 3.
## Developer preview
You need [Hugo](https://gohugo.io/) installed.
@@ -18,7 +14,7 @@ hugo server
## TODO
- [x] Add our logo on the website, favicon.
- [ ] Add content describing our association and other pages as needed.
- [x] Add content describing our association and other pages as needed.
- [x] Work on SEO (OpenGraph, Twitter meta tags...)
- [x] Multilingual support(English + Spanish)
- [x] Support for RSS (index.xml)

View File

@@ -1,12 +1,340 @@
/* Override colors from CSS library */
:root {
--accent: green;
--accent-hover: darkgreen;
--accent: green;
--accent-hover: darkgreen;
}
/* Custom style for the logo */
img.icon {
max-width: 128px;
max-height: 128px;
margin-top: 10px;
max-width: 128px;
max-height: 128px;
margin-top: 10px;
}
:root {
--activity-bg: transparent;
--activity-panel: rgba(255, 255, 255, 0.03);
--activity-card: rgba(255, 255, 255, 0.04);
--activity-border: rgba(255, 255, 255, 0.08);
--activity-muted: rgba(255, 255, 255, 0.58);
--activity-accent: rgba(255, 255, 255, 0.82);
--activity-accent-soft: rgba(255, 255, 255, 0.1);
--activity-warning: #b9986a;
--activity-tag: rgba(255, 255, 255, 0.06);
}
.activities-shell {
margin-top: 2.5rem;
padding: 0;
background: transparent;
border: none;
border-radius: 0;
box-shadow: none;
}
.activities-header {
display: flex;
flex-wrap: wrap;
gap: 2rem;
justify-content: space-between;
align-items: flex-start;
margin-bottom: 2.5rem;
}
.activities-kicker {
letter-spacing: 0.14em;
text-transform: uppercase;
font-size: 0.62rem;
color: var(--activity-muted);
margin-bottom: 0.6rem;
}
.activities-title {
margin-top: 0;
margin-bottom: 0.8rem;
font-size: clamp(1.7rem, 2vw + 1.2rem, 2.4rem);
}
.activities-lead {
max-width: 38rem;
color: var(--activity-muted);
}
.activities-actions {
display: flex;
flex-wrap: wrap;
gap: 0.8rem;
align-items: center;
}
.activities-actions .button {
background: transparent;
border: 1px solid var(--activity-border);
color: #e7e9ec;
padding: 0.45rem 0.9rem;
border-radius: 999px;
transition: all 0.2s ease;
}
.activities-actions .button:hover {
border-color: rgba(255, 255, 255, 0.22);
color: #f5f7fa;
}
.activities-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 1.25rem;
}
.activity-card {
border-radius: 12px;
padding: 1.25rem;
background: var(--activity-card);
border: 1px solid var(--activity-border);
position: relative;
overflow: hidden;
min-height: 210px;
display: flex;
flex-direction: column;
gap: 0.8rem;
transition: border-color 0.2s ease;
}
.activity-card:hover {
border-color: rgba(255, 255, 255, 0.18);
}
.activity-card h3 {
margin: 0;
font-size: 1.1rem;
}
.activity-card p {
margin: 0;
color: var(--activity-muted);
font-size: 0.92rem;
}
.activity-head {
display: flex;
justify-content: space-between;
align-items: center;
gap: 0.5rem;
}
.activity-status {
display: inline-flex;
align-items: center;
gap: 0.4rem;
font-size: 0.7rem;
padding: 0.18rem 0.5rem;
border-radius: 999px;
background: rgba(255, 255, 255, 0.12);
color: rgba(255, 255, 255, 0.8);
}
.activity-status::before {
content: "●";
font-size: 0.6rem;
}
.activity-status.status-closed {
background: rgba(185, 152, 106, 0.25);
color: var(--activity-warning);
}
.activity-status.status-cooking {
background: green;
color: #f5f7fa;
}
.activity-meta {
display: flex;
flex-wrap: wrap;
gap: 0.4rem;
font-size: 0.75rem;
color: var(--activity-muted);
}
.activity-tags {
display: flex;
flex-wrap: wrap;
gap: 0.4rem;
}
.activity-tags .activity-tag:nth-child(n + 3) {
display: none;
}
.activity-tag {
padding: 0.2rem 0.5rem;
border-radius: 999px;
background: var(--activity-tag);
color: #d5d9e0;
font-size: 0.68rem;
}
.activity-link {
margin-top: auto;
color: #f5f7fa;
font-weight: 600;
text-decoration: none;
}
.activity-link:hover {
text-decoration: underline;
}
.activities-section {
margin-bottom: 2.5rem;
}
.activities-section-head {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
align-items: baseline;
gap: 0.8rem;
margin-bottom: 1.2rem;
}
.activities-section-head h3 {
margin: 0;
font-size: 1.05rem;
}
.activities-section-head p {
margin: 0;
color: var(--activity-muted);
font-size: 0.88rem;
}
.activities-ideas {
list-style: none;
margin: 0;
padding: 0;
display: grid;
gap: 0.75rem;
}
.activities-idea {
padding: 0.75rem 0.9rem;
border-radius: 10px;
border: 1px solid var(--activity-border);
background: var(--activity-panel);
display: flex;
flex-wrap: wrap;
gap: 0.6rem 1rem;
justify-content: space-between;
align-items: center;
color: #e0e5ea;
font-size: 0.92rem;
}
.activities-idea a {
color: #f5f7fa;
font-weight: 600;
text-decoration: none;
}
.activities-idea a:hover {
text-decoration: underline;
}
.activities-footer {
margin-top: 2.4rem;
padding: 1.4rem 1.6rem;
border-radius: 16px;
background: var(--activity-panel);
border: 1px solid var(--activity-border);
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: space-between;
gap: 1rem;
}
.activities-footer p {
margin: 0;
color: var(--activity-muted);
}
.activities-footer .button {
background: transparent;
border: 1px solid rgba(255, 255, 255, 0.22);
color: #f5f7fa;
padding: 0.5rem 1.1rem;
border-radius: 999px;
}
.skeleton {
position: relative;
overflow: hidden;
}
.skeleton::before {
content: "";
position: absolute;
inset: 0;
background: linear-gradient(110deg, rgba(255, 255, 255, 0.08), rgba(255, 255, 255, 0.18), rgba(255, 255, 255, 0.08));
animation: shimmer 1.8s infinite;
}
@keyframes shimmer {
0% {
transform: translateX(-100%);
}
100% {
transform: translateX(100%);
}
}
.activities-empty {
grid-column: 1 / -1;
padding: 1.5rem;
text-align: center;
background: var(--activity-panel);
border-radius: 12px;
border: 1px dashed var(--activity-border);
color: var(--activity-muted);
}
.activities-fallback {
margin-top: 1.2rem;
padding: 1rem 1.2rem;
border-radius: 12px;
border: 1px solid var(--activity-border);
color: var(--activity-muted);
font-size: 0.9rem;
}
.activities-fallback a {
color: #f5f7fa;
}
@media (max-width: 720px) {
.activities-shell {
padding: 0;
}
.activities-actions {
width: 100%;
}
.activities-actions .button {
width: 100%;
text-align: center;
}
.activities-idea {
flex-direction: column;
align-items: flex-start;
}
.activities-footer {
flex-direction: column;
align-items: flex-start;
}
}

View File

@@ -0,0 +1,42 @@
---
title: Activities in progress
---
See what we are preparing and the current status of each proposal. Everything lives in our public Gitea board.
<div class="activities-shell" data-activities-root>
<header class="activities-header">
<div class="activities-actions">
<a class="button" href="https://openbokeron.uma.es/gitea/OpenBokeron/-/projects/5" target="_blank" rel="noopener">View board</a>
<a class="button" href="https://openbokeron.uma.es/gitea/OpenBokeron/Actividades/issues" target="_blank" rel="noopener">View issues</a>
</div>
</header>
<section class="activities-section" data-activities-working>
<div class="activities-section-head">
<h3>In development</h3>
</div>
<div class="activities-grid" data-activities-grid>
<article class="activity-card skeleton">
<div class="activity-head">
<span class="activity-status">Loading</span>
</div>
<h3>Loading...</h3>
</article>
</div>
</section>
<section class="activities-section" data-activities-ideas>
<div class="activities-section-head">
<h3>Backlog</h3>
</div>
<ul class="activities-ideas" data-activities-ideas-list>
<li class="activities-idea skeleton">Loading...</li>
</ul>
</section>
<footer class="activities-footer">
<p>Looking for past activities? You will find them in the Projects tab.</p>
<p>Want to propose something new? Drop by the Contact tab, we do not bite.</p>
</footer>
</div>

View File

@@ -0,0 +1,41 @@
+++
title="Linux Party 2026"
description="Sick of Windows forcing AI down your throat and your laptop becoming obsolete due to Windows 10's End of Life? Free your machine and discover GNU/Linux!"
image="assets/linux-party26.jpg"
date="2026-03-04T17:00:00+01:00"
draft=false
place="Room 4.1.1 (Coworking Space)"
finished=false
+++
# Free your laptop! Join the Open Bokeron Linux Party at ETSII UMA
The end of support for Windows 10 is here, and the alternative they offer is a resource-hungry Windows 11, plagued with bugs, and cramming AI assistants like Copilot that you never asked for (and which compromise your privacy) down your throat. If you're tired of an operating system that treats you like the product, forces updates at the worst possible times, and decides things for you: **It's time to liberate your laptop from all that junk!**
From **Open Bokeron**, the free software student association at the University of Málaga, we invite you on **Wednesday, March 4th at 17:00**, in the Coworking Space (Room 4.1.1) of the Computer Engineering School (ETSII UMA), to our **Linux Party**. An event designed to rescue your computer, take back control of your tech, and learn from scratch.
## What are we going to do?
### 🌟 Presentation: The Power of Free/Libre Software
Why settle for a system that spies on you when you can have one that respects your freedom? We'll tell you the basics of GNU/Linux, the huge privacy, security, and performance advantages it offers, and why it's the fundamental tool every computer science student (and digital citizen) should master.
### 💻 Install Party: Say goodbye to Windows
Do you want to install Linux but feel dizzy doing it alone? Don't worry! **We will have expert volunteers who use different distributions** (Ubuntu, Fedora, Linux Mint, Debian, Arch, Gentoo, etc.). We will help you choose the "distro" that best suits your level and your laptop (perfect for reviving those machines that Windows no longer supports!) and guide you step by step through the installation. Just bring your laptop with a backup of your important data, and we'll help you with the rest.
### 🛠️ Learn and master your environment
Linux isn't just an OS to "escape" Windows; it's an ecosystem full of professional and learning possibilities. We'll show you free tools for programming, office work, and design. Plus, we'll help you lose your fear of the terminal by teaching you your first basic commands so you can start feeling like a real *sysadmin*.
## Why should you come?
- **Save your PC from the e-waste bin:** The EOL (End of Life) of Windows 10 doesn't mean the end of your laptop. Linux is much lighter and will give it a second (and better) life.
- **Zero bloatware, zero forced AI:** Discover what it's like to use a computer that does exactly what you tell it to do, with no ads in the start menu and no hidden telemetry.
- **Learn real skills:** Understanding and knowing how to use Linux will give you a huge advantage in your studies and your future career.
- **Open Bokeron Community:** Meet people with the same interests, network, and solve your doubts with peers who are ready to help.
## Practical details
- 📅 **Date:** Wednesday, March 4, 2026
-**Time:** 17:00
- 📍 **Place:** Coworking Space (Room 4.1.1), E.T.S. de Ingeniería Informática, UMA
It doesn't matter if you're an absolute newbie or if you've already broken *GRUB* a couple of times and need help fixing it. This event is for everyone! Bring your laptop, your eagerness to learn, and join us to celebrate and exercise your digital freedom.
See you there! 🐧

View File

@@ -13,6 +13,7 @@ We participated in a live episode to talk about cybersecurity and digital privac
You can see the announcement in the post: [Podcasteando con amigos](/posts/podcast/).
Podcast website: https://www.podcasteando.es
Instagram: https://www.instagram.com/podcasteandoconamigos
![First image](/assets/podcast/podcast1.jpg)

View File

@@ -10,7 +10,7 @@ title: Bienvenido
¿Te gustaría aprender, compartir conocimientos y participar en proyectos abiertos?
Bienvenido a Open Bokeron 👋
¡Bienvenido a Open Bokeron! 👋
Somos una asociación de estudiantes de la ETSI Informática de la Universidad de Málaga dedicada a promover el software libre y el código abierto, fomentando una tecnología más abierta, accesible y colaborativa.

View File

@@ -0,0 +1,42 @@
---
title: Actividades en marcha
---
Descubre lo que estamos preparando y en qué punto está cada propuesta. Todo esto se coordina en nuestro tablero público de Gitea.
<div class="activities-shell" data-activities-root>
<header class="activities-header">
<div class="activities-actions">
<a class="button" href="https://openbokeron.uma.es/gitea/OpenBokeron/-/projects/5" target="_blank" rel="noopener">Ver tablero</a>
<a class="button" href="https://openbokeron.uma.es/gitea/OpenBokeron/Actividades/issues" target="_blank" rel="noopener">Ver issues</a>
</div>
</header>
<section class="activities-section" data-activities-working>
<div class="activities-section-head">
<h3>En desarrollo</h3>
</div>
<div class="activities-grid" data-activities-grid>
<article class="activity-card skeleton">
<div class="activity-head">
<span class="activity-status">Cargando</span>
</div>
<h3>Cargando...</h3>
</article>
</div>
</section>
<section class="activities-section" data-activities-ideas>
<div class="activities-section-head">
<h3>En el tintero</h3>
</div>
<ul class="activities-ideas" data-activities-ideas-list>
<li class="activities-idea skeleton">Cargando...</li>
</ul>
</section>
<footer class="activities-footer">
<p> ¿Buscas las Actividades ya realizadas? Las tienes en la pestaña de Proyectos ;) </p>
<p>¿Quieres proponer algo nuevo? Pásate por la pestaña Contacto, no mordemos.</p>
</footer>
</div>

View File

@@ -0,0 +1,41 @@
+++
title="Linux Party 2026"
description="¿Harto de que Windows te imponga cosas que no has pedido y de que tu portátil se quede obsoleto por el fin de Windows 10? ¡Libera tu equipo con GNU/Linux!"
image="assets/linux-party26.jpg"
date="2026-03-04T17:00:00+01:00"
draft=false
place="Aula 4.1.1 (Sala Coworking)"
finished=false
+++
# ¡Libera tu portátil! Únete a la Linux Party de Open Bokeron en ETSII UMA
El fin de soporte de Windows 10 es una realidad, y la alternativa que nos ofrecen es un Windows 11 que consume recursos de forma desmedida, está plagado de *bugs* y te mete con calzador asistentes de IA como Copilot que nunca pediste (y que atentan contra tu privacidad). Si estás cansado de un sistema operativo que te trata como al producto, te impone actualizaciones en el peor momento y decide por ti: **¡Es hora de liberar tu portátil de toda esa basura!**
Desde **Open Bokeron**, la asociación estudiantil de software libre de la Universidad de Málaga, te invitamos el **miércoles 4 de marzo a las 17:00**, en la Sala de Coworking (Aula 4.1.1) de la ETS de Ingeniería Informática de la UMA, a nuestra **Linux Party**. Un evento pensado para rescatar tu ordenador, tomar el control de tu tecnología y aprender desde cero.
## ¿Qué vamos a hacer?
### 🌟 Presentación: El poder del Software Libre
¿Por qué conformarte con un sistema que te espía cuando puedes tener uno que respeta tu libertad? Te contaremos las bases de GNU/Linux, las enormes ventajas de privacidad, seguridad y rendimiento que ofrece, y por qué es la herramienta fundamental que todo informático (y ciudadano digital) debería dominar.
### 💻 Install Party: Despídete de Windows
¿Quieres instalar Linux pero te da vértigo hacerlo solo? ¡No te preocupes! **Contaremos con voluntarios expertos usuarios de distintas distribuciones** (Ubuntu, Fedora, Linux Mint, Debian, Arch, Gentoo, etc.). Te ayudaremos a elegir la "distro" que mejor se adapte a tu nivel y a tu portátil (¡ideal para revivir esos equipos que Windows ya no soporta!) y te guiaremos paso a paso en la instalación. **Tú solo trae tu portátil con una copia de seguridad de tus datos importantes**, y nosotros nos encargamos de ayudarte con el resto.
### 🛠️ Aprende y domina tu entorno
Linux no es solo un sistema operativo para "escapar" de Windows, es un ecosistema lleno de posibilidades profesionales y de aprendizaje. Te mostraremos herramientas libres para programación, ofimática y diseño. Además, perderemos el miedo a la terminal enseñándote tus primeros comandos básicos para que empieces a sentirte como un verdadero *sysadmin*.
## ¿Por qué deberías venir?
- **Salva tu PC del vertedero electrónico:** El EOL (End of Life) de Windows 10 no significa el fin de tu portátil. Linux es mucho más ligero y le dará una segunda (y mejor) vida.
- **Cero bloatware, cero IA forzada:** Descubre lo que es usar un ordenador que hace exactamente lo que tú le pides, sin anuncios en el menú de inicio ni telemetría oculta.
- **Aprenderás habilidades reales:** Entender y saber manejar Linux te dará una ventaja enorme en tus estudios y en tu futuro profesional.
- **Comunidad Open Bokeron:** Conoce a gente con tus mismos intereses, y resuelve tus dudas con compañeros dispuestos a ayudar.
## Detalles prácticos
- 📅 **Fecha:** Miércoles, 4 de marzo de 2026
-**Hora:** 17:00
- 📍 **Lugar:** Sala de Coworking (Aula 4.1.1), E.T.S. de Ingeniería Informática, UMA
No importa si eres un novato absoluto o si ya has roto el *GRUB* un par de veces y necesitas ayuda. ¡Este evento es para todos! Trae tu portátil, tus ganas de aprender y únete a nosotros para celebrar y ejercer tu libertad digital.
¡Te esperamos! 🐧

View File

@@ -1,9 +1,9 @@
---
title: 'Participacion en Podcasteando con amigos'
title: 'Participación en Podcasteando con amigos'
description: 'Participamos en un episodio en directo sobre ciberseguridad y privacidad digital.'
image: 'assets/podcast/cartel.jpg'
date: 2026-01-10T11:30:00+01:00
place: 'Libreria Luces (Malaga)'
place: 'Librería Luces (Málaga)'
finished: true
---
@@ -13,6 +13,7 @@ Participamos en un episodio en directo para hablar de ciberseguridad y privacida
Puedes ver el anuncio en el post: [Podcasteando con amigos](/posts/podcast/).
Web del podcast: https://www.podcasteando.es
Instagram: https://www.instagram.com/podcasteandoconamigos
![Primera imagen](/assets/podcast/podcast1.jpg)

View File

@@ -34,6 +34,12 @@ buildFuture = true
url = "/en/projects"
weight = 30
[[languages.en.menu.main]]
identifier = "activities"
name = "Activities"
url = "/en/activities"
weight = 35
[[languages.en.menu.main]]
identifier = "contact"
name = "Contact"
@@ -65,6 +71,12 @@ buildFuture = true
url = "/es/projects"
weight = 30
[[languages.es.menu.main]]
identifier = "activities"
name = "Actividades"
url = "/es/activities"
weight = 35
[[languages.es.menu.main]]
identifier = "contact"
name = "Contacto"
@@ -76,3 +88,8 @@ buildFuture = true
[params]
[params.social]
twitter = 'OpenBokeron'
[markup]
[markup.goldmark]
[markup.goldmark.renderer]
unsafe = true

View File

@@ -1,5 +1,6 @@
<!DOCTYPE html>
<html lang="{{ or site.Language.LanguageCode site.Language.Lang }}" dir="{{ or site.Language.LanguageDirection `ltr` }}">
<html lang="{{ or site.Language.LanguageCode site.Language.Lang }}"
dir="{{ or site.Language.LanguageDirection `ltr` }}">
<head>
{{ partial "head.html" . -}}
@@ -15,6 +16,9 @@
<footer>
{{ partial "footer.html" . -}}
</footer>
{{ if eq .Section "activities" }}
<script src="/assets/js/activities.js" defer></script>
{{ end }}
</body>
</html>

View File

@@ -0,0 +1,235 @@
const ACTIVITIES_CONFIG = {
apiBase: "https://openbokeron.uma.es/gitea/api/v1",
repo: "OpenBokeron/Actividades",
state: "open",
};
const ACTIVITY_LABELS = {
cooking: "cocinando",
};
const ACTIVITY_BADGES = {
es: {
cooking: "Cocinando",
},
en: {
cooking: "Cooking",
},
};
const ACTIVITY_BADGE_STYLE = {
cooking: "status-cooking",
};
const ACTIVITY_CTA = {
es: "Ver en Gitea",
en: "View on Gitea",
};
const ACTIVITY_EMPTY = {
es: "Ahora mismo no hay actividades abiertas. Vuelve pronto o mira el tablero completo.",
en: "There are no open activities right now. Come back soon or check the full board.",
};
const FALLBACK_TEXT = {
es: "Oops, la hemos liado al querer cargar el tablero. Puedes verlo directamente en Gitea:",
en: "Oops, we messed up while trying to load the board. You can still open it in Gitea:",
};
const FALLBACK_LINK = {
es: "Abrir tablero",
en: "Open board",
};
const LANGUAGE_LABELS = {
es: {
milestone: "Hito",
comments: "comentarios",
updated: "Actualizado",
noCooking: "No hay actividades en desarrollo. Mira el tablero completo.",
noIdeas: "No hay ideas nuevas ahora mismo.",
},
en: {
milestone: "Milestone",
comments: "comments",
updated: "Updated",
noCooking: "No activities in development. Check the full board.",
noIdeas: "There are no new ideas right now.",
},
};
const escapeHtml = (value) => {
if (value === null || value === undefined) {
return "";
}
return String(value).replace(/[&<>"']/g, (char) => {
const map = {
"&": "&amp;",
"<": "&lt;",
">": "&gt;",
'"': "&quot;",
"'": "&#39;",
};
return map[char] || char;
});
};
const container = document.querySelector("[data-activities-root]");
if (container) {
const grid = container.querySelector("[data-activities-grid]");
const lang = document.documentElement.lang.startsWith("es") ? "es" : "en";
const labels = LANGUAGE_LABELS[lang];
const fetchActivities = async () => {
const url = `${ACTIVITIES_CONFIG.apiBase}/repos/${ACTIVITIES_CONFIG.repo}/issues?state=${ACTIVITIES_CONFIG.state}`;
const response = await fetch(url, {
headers: {
Accept: "application/json",
},
});
if (!response.ok) {
throw new Error(`Request failed: ${response.status}`);
}
return response.json();
};
const formatDate = (value) => {
const date = new Date(value);
if (Number.isNaN(date.getTime())) {
return value;
}
return new Intl.DateTimeFormat(lang, {
year: "numeric",
month: "short",
day: "numeric",
}).format(date);
};
const getLabelNames = (issue) => (issue.labels || []).map((label) => label.name.toLowerCase());
const hasLabel = (issue, label) => getLabelNames(issue).includes(label);
const renderTags = (tags) => {
if (!tags || tags.length === 0) {
return "";
}
return tags
.filter((label) => label.name.toLowerCase() !== ACTIVITY_LABELS.cooking)
.slice(0, 3)
.map((label) => `<span class="activity-tag">${label.name}</span>`)
.join("");
};
const getBadge = (issue) => {
if (hasLabel(issue, ACTIVITY_LABELS.cooking)) {
return {
text: ACTIVITY_BADGES[lang].cooking,
className: ACTIVITY_BADGE_STYLE.cooking,
};
}
return null;
};
const renderActivity = (issue) => {
const tags = renderTags(issue.labels);
const milestone = issue.milestone?.title;
const updated = formatDate(issue.updated_at);
const badge = getBadge(issue);
const comments = issue.comments || 0;
return `
<article class="activity-card">
<div class="activity-head">
${badge ? `<span class="activity-status ${badge.className}">${badge.text}</span>` : ""}
</div>
<h3>${escapeHtml(issue.title)}</h3>
<p>${issue.body ? escapeHtml(issue.body.replace(/\s+/g, " ").slice(0, 140) + "...") : ""}</p>
<div class="activity-meta">
<span>${labels.updated} ${updated}</span>
<span>${comments} ${labels.comments}</span>
<span>#${issue.number}</span>
</div>
${milestone ? `<div class="activity-meta">${labels.milestone}: ${milestone}</div>` : ""}
${tags ? `<div class="activity-tags">${tags}</div>` : ""}
<a class="activity-link" href="${issue.html_url}" target="_blank" rel="noopener">${ACTIVITY_CTA[lang]}</a>
</article>
`;
};
const renderIdeas = (ideas) => {
const ideasList = container.querySelector("[data-activities-ideas-list]");
if (!ideasList) {
return;
}
if (!ideas || ideas.length === 0) {
ideasList.innerHTML = `<li class="activities-idea">${labels.noIdeas}</li>`;
return;
}
ideasList.innerHTML = ideas
.map(
(issue) => `
<li class="activities-idea">
<div>
<strong>${escapeHtml(issue.title)}</strong>
<span class="activity-meta">#${issue.number}</span>
</div>
<a href="${issue.html_url}" target="_blank" rel="noopener">${ACTIVITY_CTA[lang]}</a>
</li>
`
)
.join("");
};
const renderActivities = (issues) => {
if (!issues || issues.length === 0) {
grid.innerHTML = `<div class="activities-empty">${ACTIVITY_EMPTY[lang]}</div>`;
renderIdeas([]);
return;
}
const cooking = issues.filter((issue) => hasLabel(issue, ACTIVITY_LABELS.cooking));
const ideas = issues.filter((issue) => !hasLabel(issue, ACTIVITY_LABELS.cooking));
const cookingTitles = new Set(cooking.map((issue) => issue.title));
const filteredIdeas = ideas.filter((issue) => !cookingTitles.has(issue.title));
if (cooking.length === 0) {
grid.innerHTML = `<div class="activities-empty">${labels.noCooking}</div>`;
} else {
grid.innerHTML = cooking.map(renderActivity).join("");
}
renderIdeas(filteredIdeas);
};
const renderFallback = () => {
grid.innerHTML = `
<div class="activities-empty">
${FALLBACK_TEXT[lang]}
<a href="https://openbokeron.uma.es/gitea/OpenBokeron/-/projects/5" target="_blank" rel="noopener">${FALLBACK_LINK[lang]}</a>
</div>
`;
const ideasList = container.querySelector("[data-activities-ideas-list]");
if (ideasList) {
ideasList.innerHTML = `<li class="activities-idea">${labels.noIdeas}</li>`;
}
};
fetchActivities()
.then((issues) => {
const sorted = [...issues].sort((a, b) => new Date(b.updated_at) - new Date(a.updated_at));
renderActivities(sorted);
})
.catch(() => {
renderFallback();
});
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 684 KiB