Comparar commits

..

4 Commits

Autor SHA1 Mensaje Fecha
Munka
5a6f6c918f v1.18.0: F5 recarga, como en cualquier navegador
WebView2 tiene apagados sus propios atajos de navegador, así que F5 no hacía
nada dentro de la app: el único que recargaba era Ctrl+R. Ahora F5 (y
Ctrl+F5, Shift+F5) recarga la pestaña. Va antes del filtro de modificadores
de los atajos, porque F5 no lleva ninguno y ese filtro lo descartaba.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-22 17:54:57 -05:00
Jonathan David Florez Salomón
7b0c031a41 v1.17.0: la esquina rota, la profundidad de las pestañas y la activa en negrilla
Tres cambios en la barra, todos de la misma idea: que se vea de un vistazo cuál
manda.

· LA ESQUINA. Se retiran los dos pseudo-elementos de 8px que imitaban la curva
  cóncava de Chrome. El truco funciona allí porque NO hay línea bajo la barra;
  aquí sí la hay, y esas piezas blancas la partían en dos a los costados de la
  pestaña activa. La activa ya se funde con el contenido por su propio fondo.

· LA PROFUNDIDAD. Las inactivas se hunden con un velo tenue y sombra interior, y
  al pasar el ratón el gesto se invierte: la sombra sale y el fondo tira hacia el
  blanco de la activa. Sombra y no relleno sólido — un bloque gris pesa tanto
  como la activa y compite con ella. La activa gana sombra HACIA ARRIBA: abajo
  está fundida con el contenido.

· LA NEGRILLA. El título de la activa a 600. Va en el título y no en la pestaña
  entera para que el aspa de cerrar no engorde con él.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-20 15:37:36 -05:00
Jonathan David Florez Salomón
641c9660cc La pestaña activa, en negrilla
El relieve dice dónde está el plano de delante; el peso de la letra es lo que se
lee sin mirar. Va en el TÍTULO y no en la pestaña entera, para que el aspa de
cerrar no engorde con él, y a 600 y no a 700: a 12,5 px el bold entero emborrona,
y lo que hace falta es que destaque, no que grite.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-20 15:22:28 -05:00
Jonathan David Florez Salomón
73486aa3fe La esquina de la pestaña activa deja de romperse, y las que esperan se hunden
DOS COSAS EN LA BARRA DE PESTAÑAS.

1) LA ESQUINA. La activa llevaba dos pseudo-elementos de 8px a los lados con un
   degradado radial: la curva cóncava de Chrome. El truco funciona en Chrome
   porque allí NO hay línea bajo la barra; aquí sí la hay, y esas dos piezas
   blancas la partían en dos justo a los costados de la pestaña — la fluctuación
   que se veía en la esquina. Se retiran: la activa ya se funde con el contenido
   por su propio fondo, que tapa la línea exactamente por su ancho, y sin las
   piezas no asoma nada.

2) LA PROFUNDIDAD. La inactiva no era nada: texto suelto sobre la franja, al
   mismo plano que la activa, separado por un filete de 1px. Ahora se HUNDE —velo
   muy tenue y sombra interior— y al pasar el ratón el gesto se invierte: la
   sombra sale hacia fuera y el fondo tira hacia el blanco de la activa, así que
   la pestaña sube hacia ti. Es sombra y no relleno sólido a propósito: un bloque
   gris pesa tanto como la activa y acaba compitiendo con ella.

   La activa gana su propia sombra, HACIA ARRIBA: abajo está fundida con el
   contenido y una sombra ahí dibujaría una línea donde no debe haberla.

   Con fondo propio el separador vertical sobra y se retira. `--sep` se queda:
   lo sigue usando el aro del favicon mientras carga.

Sin cambio de versión: queda listo para la próxima que se saque.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-20 15:20:30 -05:00
Se han modificado 6 ficheros con 66 adiciones y 43 borrados

97
dist/index.html vendido
Ver fichero

@@ -35,7 +35,16 @@
/* Sobre una franja casi blanca, un hover blanco no se vería: aquí oscurece. */ /* Sobre una franja casi blanca, un hover blanco no se vería: aquí oscurece. */
--hover: rgba(0, 0, 0, 0.06); --hover: rgba(0, 0, 0, 0.06);
--btn-hover: rgba(0, 0, 0, 0.08); --btn-hover: rgba(0, 0, 0, 0.08);
--sep: rgba(0, 0, 0, 0.22); /* separador fino entre pestañas inactivas */ --sep: rgba(0, 0, 0, 0.22); /* aro del favicon mientras carga */
/* PROFUNDIDAD. La inactiva no lleva un relleno gris —un bloque sólido pesa y compite
con la activa— sino un velo casi imperceptible y una sombra INTERIOR: parece estar un
plano por debajo. Al pasar el ratón cambia de signo, la sombra sale hacia fuera y la
pestaña sube: por eso el hover va hacia el BLANCO de la activa y no hacia el gris. */
--tab-atras: rgba(0, 0, 0, 0.035);
--tab-atras-sombra: inset 0 1px 1.5px rgba(0, 0, 0, 0.055);
--tab-hover-bg: rgba(255, 255, 255, 0.85);
--tab-hover-sombra: 0 1px 3px rgba(0, 0, 0, 0.10);
--tab-activa-sombra: 0 -1px 4px rgba(0, 0, 0, 0.07);
} }
/* ── Quién decide el tema ── /* ── Quién decide el tema ──
La APP, no Windows: la web elige su modo con su propio botón (clase `dark` en su La APP, no Windows: la web elige su modo con su propio botón (clase `dark` en su
@@ -57,6 +66,13 @@
--hover: rgba(255, 255, 255, 0.08); --hover: rgba(255, 255, 255, 0.08);
--btn-hover: rgba(255, 255, 255, 0.1); --btn-hover: rgba(255, 255, 255, 0.1);
--sep: rgba(255, 255, 255, 0.25); --sep: rgba(255, 255, 255, 0.25);
/* En oscuro el movimiento es el mismo pero con luz: la inactiva se hunde con un velo
blanco muy tenue y una sombra negra dentro; al pasar el ratón sube hacia la luz. */
--tab-atras: rgba(255, 255, 255, 0.035);
--tab-atras-sombra: inset 0 1px 1.5px rgba(0, 0, 0, 0.35);
--tab-hover-bg: rgba(255, 255, 255, 0.10);
--tab-hover-sombra: 0 1px 3px rgba(0, 0, 0, 0.45);
--tab-activa-sombra: 0 -1px 4px rgba(0, 0, 0, 0.35);
} }
} }
:root.oscuro { :root.oscuro {
@@ -69,6 +85,13 @@
--hover: rgba(255, 255, 255, 0.08); --hover: rgba(255, 255, 255, 0.08);
--btn-hover: rgba(255, 255, 255, 0.1); --btn-hover: rgba(255, 255, 255, 0.1);
--sep: rgba(255, 255, 255, 0.25); --sep: rgba(255, 255, 255, 0.25);
/* En oscuro el movimiento es el mismo pero con luz: la inactiva se hunde con un velo
blanco muy tenue y una sombra negra dentro; al pasar el ratón sube hacia la luz. */
--tab-atras: rgba(255, 255, 255, 0.035);
--tab-atras-sombra: inset 0 1px 1.5px rgba(0, 0, 0, 0.35);
--tab-hover-bg: rgba(255, 255, 255, 0.10);
--tab-hover-sombra: 0 1px 3px rgba(0, 0, 0, 0.45);
--tab-activa-sombra: 0 -1px 4px rgba(0, 0, 0, 0.35);
} }
* { box-sizing: border-box; } * { box-sizing: border-box; }
html, body { html, body {
@@ -119,53 +142,46 @@
height: 30px; height: 30px;
margin-bottom: 5px; margin-bottom: 5px;
padding: 0 6px 0 10px; padding: 0 6px 0 10px;
border-radius: 9px; /* inactiva: píldora redondeada (hover) */ border-radius: 9px; /* inactiva: píldora redondeada */
position: relative; position: relative;
overflow: visible; /* deja asomar las curvas de la base de la activa */ overflow: visible; /* las sombras viven fuera de la caja */
transition: background 140ms ease, box-shadow 140ms ease, color 140ms ease;
} }
.tab:not(.active):hover { background: var(--hover); } /* ── PROFUNDIDAD: las que no mandan están detrás ──────────────────────────────────
/* Separador fino a la IZQUIERDA de cada inactiva; se oculta pegado a la activa, Antes la inactiva no era nada: texto suelto sobre la franja, al mismo plano que la
al hover y en la primera (igual que Chrome). */ activa, y lo único que las separaba era un filete de 1px. Ahora la inactiva se HUNDE
.tab:not(.active)::before { —velo tenue y sombra interior— y al pasar el ratón el gesto se invierte: la sombra sale
content: ""; hacia fuera y el fondo tira hacia el blanco de la activa, así que la pestaña sube hacia
position: absolute; ti. Es sombra y no relleno a propósito: un bloque gris sólido pesa tanto como la activa
left: -1px; y acaba compitiendo con ella.
top: 50%; Con fondo propio el separador vertical entre pestañas sobra —ya se ve dónde acaba cada
transform: translateY(-50%); una—, así que se retiró. */
width: 1px; .tab:not(.active) {
height: 16px; background: var(--tab-atras);
background: var(--sep); box-shadow: var(--tab-atras-sombra);
}
.tab:not(.active):hover {
background: var(--tab-hover-bg);
box-shadow: var(--tab-hover-sombra);
color: var(--tab-active-fg);
} }
.tab:first-child::before,
.tab:hover::before,
.tab.active + .tab::before,
.tab:hover + .tab::before { display: none; }
.tab.active { .tab.active {
background: var(--tab-active-bg); background: var(--tab-active-bg);
color: var(--tab-active-fg); color: var(--tab-active-fg);
height: 35px; height: 35px;
margin-bottom: 0; /* su base cae 1px SOBRE el borde de la barra y lo tapa */ margin-bottom: 0; /* su base cae 1px SOBRE el borde de la barra y lo tapa */
border-radius: 10px 10px 0 0; border-radius: 10px 10px 0 0;
/* Levantada, apenas: la sombra va HACIA ARRIBA porque abajo la pestaña está fundida con
el contenido y una sombra ahí dibujaría una línea donde justamente no debe haberla. */
box-shadow: var(--tab-activa-sombra);
z-index: 1; z-index: 1;
} }
/* Curvas cóncavas de Chrome en la base de la pestaña activa: dos piezas de 8px con /* AQUÍ ESTABAN LAS CURVAS CÓNCAVAS DE CHROME: dos piezas de 8px a los lados de la activa
un cuarto de círculo transparente que "derrama" el fondo hacia los lados. */ con un cuarto de círculo transparente que derramaba su fondo hacia fuera. El truco de
.tab.active::before, Chrome funciona porque allí NO hay línea bajo la barra; aquí sí la hay, y esas dos
.tab.active::after { piezas blancas la partían en dos justo a los costados de la pestaña — la «fluctuación»
content: ""; de la esquina. La activa ya se funde con el contenido por su propio fondo, que tapa la
position: absolute; línea exactamente por su ancho; sin las piezas no asoma nada. */
bottom: 0;
width: 8px;
height: 8px;
}
.tab.active::before {
left: -8px;
background: radial-gradient(circle at 0 0, transparent 8px, var(--tab-active-bg) 8.5px);
}
.tab.active::after {
right: -8px;
background: radial-gradient(circle at 8px 0, transparent 8px, var(--tab-active-bg) 8.5px);
}
/* ── Color de pestaña ──────────────────────────────────────────────────────────── /* ── Color de pestaña ────────────────────────────────────────────────────────────
Misma idea que los grupos de Chrome: teñir para agrupar de un vistazo («todo lo de Misma idea que los grupos de Chrome: teñir para agrupar de un vistazo («todo lo de
este cliente, en verde»). El color se elige con clic derecho sobre la pestaña ▸ Color, este cliente, en verde»). El color se elige con clic derecho sobre la pestaña ▸ Color,
@@ -185,8 +201,6 @@
.tab[data-color="naranja"] { --tc: 250, 144, 62; } .tab[data-color="naranja"] { --tc: 250, 144, 62; }
.tab[data-color]:not(.active) { background: rgba(var(--tc), 0.18); } .tab[data-color]:not(.active) { background: rgba(var(--tc), 0.18); }
.tab[data-color]:not(.active):hover { background: rgba(var(--tc), 0.32); } .tab[data-color]:not(.active):hover { background: rgba(var(--tc), 0.32); }
/* Con fondo propio el separador vertical sobra: ya se ve dónde acaba cada pestaña. */
.tab[data-color]:not(.active)::before { display: none; }
.tab[data-color].active { box-shadow: inset 0 3px 0 rgb(var(--tc)); } .tab[data-color].active { box-shadow: inset 0 3px 0 rgb(var(--tc)); }
@media (prefers-color-scheme: dark) { @media (prefers-color-scheme: dark) {
:root:not(.claro) .tab[data-color]:not(.active) { background: rgba(var(--tc), 0.36); } :root:not(.claro) .tab[data-color]:not(.active) { background: rgba(var(--tc), 0.36); }
@@ -227,6 +241,11 @@
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
} }
/* La ACTIVA en negrilla: el relieve dice dónde está el plano de delante, pero el peso de
la letra es lo que se lee sin mirar. Va en el título y no en la pestaña entera para que
el aspa de cerrar no engorde con él. 600 y no 700: a este tamaño el bold entero
emborrona, y lo que hace falta es que destaque, no que grite. */
.tab.active .titulo { font-weight: 600; }
.tab .cerrar { .tab .cerrar {
flex: 0 0 auto; flex: 0 0 auto;
width: 18px; width: 18px;

Ver fichero

@@ -1,6 +1,6 @@
{ {
"name": "labstream-desktop", "name": "labstream-desktop",
"version": "1.16.0", "version": "1.18.0",
"private": true, "private": true,
"description": "App de escritorio (Windows) que envuelve Labstream OS — cliente del servidor del NAS.", "description": "App de escritorio (Windows) que envuelve Labstream OS — cliente del servidor del NAS.",
"scripts": { "scripts": {

Ver fichero

@@ -2366,7 +2366,7 @@ dependencies = [
[[package]] [[package]]
name = "labstream-desktop" name = "labstream-desktop"
version = "1.16.0" version = "1.18.0"
dependencies = [ dependencies = [
"active-win-pos-rs", "active-win-pos-rs",
"device_query", "device_query",

Ver fichero

@@ -1,6 +1,6 @@
[package] [package]
name = "labstream-desktop" name = "labstream-desktop"
version = "1.16.0" version = "1.18.0"
description = "Cliente de escritorio de Labstream OS" description = "Cliente de escritorio de Labstream OS"
authors = ["Labstream SAS"] authors = ["Labstream SAS"]
edition = "2021" edition = "2021"

Ver fichero

@@ -381,6 +381,10 @@ const INIT_JS_TPL: &str = r#"
// nota y en cualquier campo de la app. En macOS no aplica (Option no toca ctrlKey). // nota y en cualquier campo de la app. En macOS no aplica (Option no toca ctrlKey).
if (e.altKey) return; if (e.altKey) return;
var mod = e.metaKey || e.ctrlKey; var mod = e.metaKey || e.ctrlKey;
// F5 recarga, como en cualquier navegador de Windows (y Ctrl+F5 / Shift+F5 también). WebView2
// tiene apagados sus propios atajos, así que F5 no hacía NADA: el único que recargaba era
// Ctrl+R, y va antes del filtro de abajo porque F5 no lleva modificador.
if (e.key === 'F5') { e.preventDefault(); location.reload(); return; }
if (!mod) return; if (!mod) return;
var k = e.key; var k = e.key;
if (k === 't' || k === 'T') { if (k === 't' || k === 'T') {

Ver fichero

@@ -1,7 +1,7 @@
{ {
"$schema": "https://schema.tauri.app/config/2", "$schema": "https://schema.tauri.app/config/2",
"productName": "Labstream OS", "productName": "Labstream OS",
"version": "1.16.0", "version": "1.18.0",
"identifier": "co.labstream.os", "identifier": "co.labstream.os",
"build": { "build": {
"frontendDist": "../dist" "frontendDist": "../dist"