feat: version 2.16.1 -- barra superior reducida, barra inferior fija y contador de Contraseñas en ella
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,5 +1,13 @@
|
|||||||
# Changelog - project.linkedcorp.net
|
# Changelog - project.linkedcorp.net
|
||||||
|
|
||||||
|
## [2.16.1] - 2026-10-20
|
||||||
|
### Changed
|
||||||
|
- Barra superior (topbar) a la mitad de alto (84 px → 42 px).
|
||||||
|
- Nueva barra inferior fija en la columna de contenido (nunca queda contenido detrás; el sidebar no
|
||||||
|
se toca). Muestra © año + nombre y tiene un hueco a la derecha para indicadores de cada página.
|
||||||
|
- Contraseñas: la cuenta regresiva del cierre automático pasa a la barra inferior (derecha); solo
|
||||||
|
se ve con el menú desbloqueado y desaparece al pedir el PIN o cambiar de menú.
|
||||||
|
|
||||||
## [2.16.0] - 2026-10-20
|
## [2.16.0] - 2026-10-20
|
||||||
### Added
|
### Added
|
||||||
- Equipos → Agentes: "Instalador para Windows": descarga un `.bat` (generado en el navegador, con
|
- Equipos → Agentes: "Instalador para Windows": descarga un `.bat` (generado en el navegador, con
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "project-linkedcorp-backend",
|
"name": "project-linkedcorp-backend",
|
||||||
"version": "2.16.0",
|
"version": "2.16.1",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "src/server.js",
|
"main": "src/server.js",
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "project-linkedcorp-frontend",
|
"name": "project-linkedcorp-frontend",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "2.16.0",
|
"version": "2.16.1",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
|
|||||||
@@ -168,6 +168,11 @@ export default function AppShell() {
|
|||||||
<div className="content-area">
|
<div className="content-area">
|
||||||
<Outlet />
|
<Outlet />
|
||||||
</div>
|
</div>
|
||||||
|
<div className="footbar">
|
||||||
|
<span>© {new Date().getFullYear()} {t('appName')}</span>
|
||||||
|
{/* Hueco de la derecha: las paginas ponen aqui su indicador via portal (ej. cuenta regresiva de Contraseñas). */}
|
||||||
|
<span id="footbar-slot" />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<DetailPopup open={changingPassword} title={t('change_password_title')} onClose={() => setChangingPassword(false)} width={420} height={380}>
|
<DetailPopup open={changingPassword} title={t('change_password_title')} onClose={() => setChangingPassword(false)} width={420} height={380}>
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
|
import { createPortal } from 'react-dom';
|
||||||
import {
|
import {
|
||||||
Plus, ChevronUp, ChevronLeft, Trash2, Eye, EyeOff, Copy, Pencil, Save, X, RefreshCw, ShieldAlert,
|
Plus, ChevronUp, ChevronLeft, Trash2, Eye, EyeOff, Copy, Pencil, Save, X, RefreshCw, ShieldAlert,
|
||||||
MoreVertical, Mail, Globe, Server, Database, Cloud, Shield, Lock, Wifi, CreditCard, Building2, Printer,
|
MoreVertical, Mail, Globe, Server, Database, Cloud, Shield, Lock, Wifi, CreditCard, Building2, Printer,
|
||||||
@@ -76,6 +77,9 @@ export default function ContrasenasPage() {
|
|||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
|
||||||
const [locked, setLocked] = useState(true);
|
const [locked, setLocked] = useState(true);
|
||||||
|
// Hueco de la barra inferior donde se muestra la cuenta regresiva (solo mientras esta desbloqueado).
|
||||||
|
const [footSlot, setFootSlot] = useState(null);
|
||||||
|
useEffect(() => { setFootSlot(document.getElementById('footbar-slot')); }, []);
|
||||||
const [checking, setChecking] = useState(true);
|
const [checking, setChecking] = useState(true);
|
||||||
const [hasPinSet, setHasPinSet] = useState(null);
|
const [hasPinSet, setHasPinSet] = useState(null);
|
||||||
const [entries, setEntries] = useState(null);
|
const [entries, setEntries] = useState(null);
|
||||||
@@ -152,8 +156,8 @@ export default function ContrasenasPage() {
|
|||||||
useEffect(() => () => setVaultToken(null), []);
|
useEffect(() => () => setVaultToken(null), []);
|
||||||
|
|
||||||
// Cierre por inactividad (3 min sin teclado/clic/toque/rueda): lo cuenta <AutoLockCountdown>, que
|
// Cierre por inactividad (3 min sin teclado/clic/toque/rueda): lo cuenta <AutoLockCountdown>, que
|
||||||
// muestra el tiempo restante junto al titulo y reinicia con cada accion del usuario, asi que
|
// se muestra en la barra inferior (a la derecha) mientras esta desbloqueado y se reinicia con cada
|
||||||
// nunca lo saca en medio de escribir/editar una credencial.
|
// accion del usuario, asi que nunca lo saca en medio de escribir/editar una credencial.
|
||||||
function autoLockExit() {
|
function autoLockExit() {
|
||||||
pushToast({ tone: 'warning', message: t('vault_auto_lock_notice') });
|
pushToast({ tone: 'warning', message: t('vault_auto_lock_notice') });
|
||||||
navigate('/');
|
navigate('/');
|
||||||
@@ -430,9 +434,9 @@ export default function ContrasenasPage() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
|
{footSlot && createPortal(<AutoLockCountdown ms={AUTO_LOCK_MS} onExpire={autoLockExit} title={t('vault_countdown_hint')} />, footSlot)}
|
||||||
<div className="toolbar">
|
<div className="toolbar">
|
||||||
<h2 className="page-title mt-0" style={{ marginBottom: 0 }}>{t('nav_passwords')}</h2>
|
<h2 className="page-title mt-0" style={{ marginBottom: 0 }}>{t('nav_passwords')}</h2>
|
||||||
<AutoLockCountdown ms={AUTO_LOCK_MS} onExpire={autoLockExit} title={t('vault_countdown_hint')} />
|
|
||||||
<SearchInput value={search} onChange={setSearch} />
|
<SearchInput value={search} onChange={setSearch} />
|
||||||
<div style={{ flex: 1 }} />
|
<div style={{ flex: 1 }} />
|
||||||
<Button variant="standard" icon={RefreshCw} onClick={() => setChangingPin(true)}>{t('vault_change_pin')}</Button>
|
<Button variant="standard" icon={RefreshCw} onClick={() => setChangingPin(true)}>{t('vault_change_pin')}</Button>
|
||||||
|
|||||||
@@ -104,12 +104,19 @@ button { font-family: inherit; }
|
|||||||
|
|
||||||
.content-column { flex: 1; display: flex; flex-direction: column; min-width: 0; }
|
.content-column { flex: 1; display: flex; flex-direction: column; min-width: 0; }
|
||||||
.topbar {
|
.topbar {
|
||||||
height: 84px; flex: none; display: flex; align-items: center; justify-content: space-between;
|
height: 42px; flex: none; display: flex; align-items: center; justify-content: space-between;
|
||||||
padding: 0 16px; border-bottom: 1px solid rgb(var(--line)); background: rgb(var(--surface));
|
padding: 0 16px; border-bottom: 1px solid rgb(var(--line)); background: rgb(var(--surface));
|
||||||
gap: 12px;
|
gap: 12px;
|
||||||
}
|
}
|
||||||
.topbar-left { display: flex; align-items: center; gap: 10px; }
|
.topbar-left { display: flex; align-items: center; gap: 10px; }
|
||||||
.topbar-right { display: flex; align-items: center; gap: 10px; }
|
.topbar-right { display: flex; align-items: center; gap: 10px; }
|
||||||
|
/* Barra inferior fija: hermana del .content-area dentro de la columna flex (no flota encima), asi el
|
||||||
|
contenido hace scroll SOLO en el espacio que queda y nunca queda detras de ella. No toca el sidebar. */
|
||||||
|
.footbar {
|
||||||
|
height: 28px; flex: none; display: flex; align-items: center; justify-content: space-between;
|
||||||
|
padding: 0 16px; border-top: 1px solid rgb(var(--line)); background: rgb(var(--surface));
|
||||||
|
font-size: .72rem; color: rgb(var(--muted));
|
||||||
|
}
|
||||||
.page-title { font-size: 1.05rem; font-weight: 700; }
|
.page-title { font-size: 1.05rem; font-weight: 700; }
|
||||||
.content-area { flex: 1; overflow-y: auto; padding: 20px; }
|
.content-area { flex: 1; overflow-y: auto; padding: 20px; }
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user