Compare commits

...

4 Commits

Author SHA1 Message Date
jose-rZM
2948743625 Change layout and texts 2025-12-15 19:11:03 +01:00
jose-rZM
9bc96e6f41 Change style 2025-12-15 18:59:45 +01:00
jose-rZM
2ae617797c Add OB spam 2025-12-15 18:46:35 +01:00
jose-rZM
d036b2119a Disable polling in build history 2025-12-15 18:34:05 +01:00
3 changed files with 234 additions and 27 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

View File

@@ -80,12 +80,10 @@
const pricesInterval = setInterval(fetchPrices, 8000);
const ciInterval = setInterval(fetchCiStatus, 10000);
const historyInterval = setInterval(fetchBuildHistory, 15000);
return () => {
clearInterval(pricesInterval);
clearInterval(ciInterval);
clearInterval(historyInterval);
};
});
</script>
@@ -101,8 +99,8 @@
está inspirada en la de nuestra querida escuela.
</p>
<div class="actions">
<button on:click={() => fetchMenu()} class="ghost">Refrescar menú</button>
<button on:click={() => fetchPrices()}>Recalcular desayunos</button>
<button on:click={() => fetchMenu()}>Refrescar menú</button>
<button on:click={() => fetchPrices()} class="ghost">Recalcular desayunos</button>
</div>
<p class="meta">
Backend: {API_BASE} · Endpoints: /menu · /prices · /prices/:item · /health
@@ -257,11 +255,42 @@
{/if}
</article>
<article class="card">
<div class="card-head">
<div class="label">Desayunos</div>
{#if loadingPrices}
<span class="tag">cargando...</span>
{/if}
</div>
{#if prices.length}
<div class="price-grid">
{#each prices as price}
<div class="price-card">
<p class="item">{prettify(price.item)}</p>
<p class="value">{price.price}</p>
<p class="timestamp">{price.generated_at}</p>
</div>
{/each}
</div>
<p class="meta">
Dependiendo de si vas por la mañana o por la tarde los precios cambian. No sé,
como no ponen los precios al público... :p
</p>
{:else if !loadingPrices}
<p>No hay precios que mostrar.</p>
{/if}
</article>
<article class="card ci-card">
<div class="card-head">
<div>
<p class="label">Estado del sistema</p>
<p class="sub">Información de build y backend</p>
<p class="sub">
Información de build y backend. Tanto el Build, Commit y Autor lo
recuperamos gracias a Jenkins, inyectando ciertas variables a la hora de
hacer despliegue del backend.
</p>
</div>
{#if loadingCiStatus}
<span class="tag">comprobando...</span>
@@ -311,7 +340,11 @@
<div class="card-head">
<div>
<p class="label">Historial</p>
<p class="sub">Builds recientes en Jenkins</p>
<p class="sub">
Builds recientes en Jenkins. Esto lo conseguimos gracias a que Jenkins nos
expone una API REST muy maja para consultar información de los jobs y
builds.
</p>
</div>
{#if loadingHistory}
<span class="tag">actualizando...</span>
@@ -365,31 +398,60 @@
{/if}
</article>
<article class="card">
<article class="card openbokeron-card">
<div class="card-head">
<div class="label">Desayunos</div>
{#if loadingPrices}
<span class="tag">cargando...</span>
{/if}
<div>
<p class="label">Open Bokeron</p>
<p class="sub">Quiénes estamos detrás del taller</p>
</div>
<a
class="tag link-tag"
href="https://openbokeron.org"
target="_blank"
rel="noreferrer"
>
openbokeron.org
</a>
</div>
{#if prices.length}
<div class="price-grid">
{#each prices as price}
<div class="price-card">
<p class="item">{prettify(price.item)}</p>
<p class="value">{price.price}</p>
<p class="timestamp">{price.generated_at}</p>
</div>
{/each}
</div>
<p class="meta">
Dependiendo de si vas por la mañana o por la tarde los precios cambian. No sé,
como no ponen los precios al público... :p
<div class="openbokeron-body">
<div class="openbokeron-copy">
<p class="openbokeron-text">
Somos Open Bokeron, la asociación de software libre de la ETSII.
</p>
{:else if !loadingPrices}
<p>No hay precios que mostrar.</p>
{/if}
<p class="openbokeron-text subtle">
Este tinglado lo hemos montado nosotros, así que sí: esta tarjeta se queda
todo el taller
</p>
<ul class="openbokeron-list">
<li>Usamos Linux y te juzgamos severamente si vienes con Windows.</li>
<li>A veces hacemos cosas. #HazCosas dicen por aquí en la ETSII.</li>
</ul>
<div class="openbokeron-actions">
<a
class="button-link subtle"
href="https://openbokeron.org"
target="_blank"
rel="noreferrer"
>
Conócenos
</a>
</div>
</div>
<div class="openbokeron-logo">
<div class="logo-bubble">
<img
src="/open-bokeron-logo.png"
alt="Logo de Open Bokeron"
loading="lazy"
/>
</div>
</div>
</div>
</article>
</section>
</main>

View File

@@ -184,6 +184,23 @@ button.outline {
border: 1px solid rgba(255, 255, 255, 0.05);
}
.openbokeron-card {
background:
radial-gradient(circle at 12% 18%, rgba(34, 211, 238, 0.22), transparent 26%),
radial-gradient(circle at 85% -5%, rgba(124, 58, 237, 0.2), transparent 28%),
linear-gradient(180deg, #0b1224, #0e1530);
position: relative;
overflow: hidden;
}
.openbokeron-card::after {
content: '';
position: absolute;
inset: 0;
background: linear-gradient(135deg, rgba(255, 255, 255, 0.02), transparent 55%);
pointer-events: none;
}
.card-head {
display: flex;
justify-content: space-between;
@@ -211,6 +228,21 @@ button.outline {
font-size: 0.85rem;
}
.tag.link-tag {
text-decoration: none;
border: 1px solid rgba(165, 180, 252, 0.4);
transition:
border-color 120ms ease,
color 120ms ease,
background 120ms ease;
}
.tag.link-tag:hover {
border-color: rgba(165, 180, 252, 0.8);
background: rgba(165, 180, 252, 0.16);
color: #c7d2fe;
}
.menu-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
@@ -368,6 +400,109 @@ li {
align-items: flex-end;
}
.openbokeron-body {
display: grid;
grid-template-columns: minmax(0, 1.4fr) minmax(180px, 0.6fr);
gap: 1rem;
align-items: flex-start;
}
.openbokeron-copy {
display: flex;
flex-direction: column;
gap: 0.4rem;
}
.openbokeron-copy > * + * {
margin-top: 0.3rem;
}
.openbokeron-text {
margin: 0;
color: #e2e8f0;
line-height: 1.5;
font-size: 0.95rem;
}
.openbokeron-text.subtle {
opacity: 0.75;
font-size: 0.9rem;
}
.openbokeron-list {
margin: 0.2rem 0 0;
padding-left: 1.1rem;
color: #cbd5f5;
font-size: 0.88rem;
opacity: 0.85;
display: flex;
flex-direction: column;
gap: 0.3rem;
}
.openbokeron-actions {
display: flex;
gap: 0.6rem;
align-items: center;
flex-wrap: wrap;
}
.button-link {
display: inline-flex;
align-items: center;
gap: 0.35rem;
background: linear-gradient(120deg, #22d3ee, #38bdf8);
color: #0b1224;
text-decoration: none;
font-weight: 800;
padding: 0.65rem 1rem;
border-radius: 12px;
box-shadow: 0 12px 26px rgba(34, 211, 238, 0.25);
transition:
transform 120ms ease,
box-shadow 120ms ease;
}
.button-link:hover {
transform: translateY(-1px);
box-shadow: 0 14px 28px rgba(56, 189, 248, 0.3);
}
.button-link.subtle {
background: rgba(255, 255, 255, 0.08);
color: #e2e8f0;
box-shadow: none;
font-weight: 700;
}
.button-link.subtle:hover {
background: rgba(255, 255, 255, 0.14);
}
.openbokeron-logo {
display: flex;
align-items: center;
justify-content: center;
}
.logo-bubble {
min-height: 120px;
border-radius: 14px;
border: 1px dashed rgba(148, 163, 184, 0.35);
background: rgba(255, 255, 255, 0.04);
display: flex;
align-items: center;
justify-content: center;
padding: 0.8rem;
}
.logo-bubble img {
max-width: 120px;
width: 100%;
height: auto;
opacity: 0.9;
}
.price-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
@@ -455,6 +590,16 @@ li {
}
}
@media (max-width: 780px) {
.openbokeron-body {
grid-template-columns: 1fr;
}
.openbokeron-actions {
justify-content: flex-start;
}
}
@media (min-width: 980px) {
.menu-card {
grid-column: span 2;