Compare commits
4 Commits
a96fa20ac0
...
2948743625
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2948743625 | ||
|
|
9bc96e6f41 | ||
|
|
2ae617797c | ||
|
|
d036b2119a |
BIN
frontend/public/open-bokeron-logo.png
Normal file
BIN
frontend/public/open-bokeron-logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 32 KiB |
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user