feat: version 2.8.1 -- catalogo de logos de marca en Contraseñas (simple-icons, CC0)
Amplia el selector de icono de una credencial con ~70 logos reales de marcas conocidas (Google, GitHub, Cloudflare, cPanel, MikroTik, WordPress, etc.), empaquetados localmente desde el paquete simple-icons (dominio publico) y tree-shakeados por Vite. Se mantiene el criterio de privacidad ya establecido: ninguna consulta externa de favicon por entrada. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -18,25 +18,36 @@ import { PasswordInput } from '../../components/PasswordInput.jsx';
|
||||
import { DetailPopup } from '../../components/DetailPopup.jsx';
|
||||
import { Flyout, FlyoutItem } from '../../components/Flyout.jsx';
|
||||
import { SearchInput } from '../../components/SearchInput.jsx';
|
||||
import { BRAND_ICONS } from '../../data/brandIcons.js';
|
||||
|
||||
const EMPTY_FORM = { title: '', url: '', username: '', password: '', notes: '', iconKey: '' };
|
||||
const AUTO_LOCK_MS = 3 * 60 * 1000; // 3 minutos: salir solo del menu si queda abierto sin atencion
|
||||
|
||||
// Catalogo fijo de iconos (debe coincidir con backend/src/modules/vault/service.js#ICON_KEYS) --
|
||||
// Catalogo fijo de iconos genericos (debe coincidir con backend/src/modules/vault/service.js#ICON_KEYS) --
|
||||
// a proposito NO se usa ningun servicio externo de favicon (ej. google/s2/favicons): revelaria a
|
||||
// terceros que urls internas tiene guardadas cada usuario, inaceptable para un repositorio de
|
||||
// credenciales. El usuario elige uno de esta lista, o se deja "Auto" (inicial del nombre).
|
||||
// credenciales. El usuario elige uno de esta lista, o uno de marca (BRAND_ICONS), o se deja
|
||||
// "Auto" (inicial del nombre).
|
||||
const ICONS = {
|
||||
mail: Mail, globe: Globe, server: Server, database: Database, cloud: Cloud, shield: Shield,
|
||||
lock: Lock, wifi: Wifi, card: CreditCard, building: Building2, printer: Printer,
|
||||
phone: Smartphone, key: KeyRound, disk: HardDrive, router: Router, user: UserCog,
|
||||
};
|
||||
|
||||
function BrandSvg({ icon, size = 22 }) {
|
||||
return (
|
||||
<svg viewBox="0 0 24 24" width={size} height={size} fill={`#${icon.hex}`}>
|
||||
<path d={icon.path} />
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
||||
function EntryIcon({ iconKey, title, size = 22 }) {
|
||||
const Icon = ICONS[iconKey];
|
||||
const brand = BRAND_ICONS[iconKey];
|
||||
return (
|
||||
<div className="vault-card-icon">
|
||||
{Icon ? <Icon size={size} /> : <span>{(title || '?').trim().charAt(0).toUpperCase()}</span>}
|
||||
<div className={`vault-card-icon ${brand ? 'brand' : ''}`}>
|
||||
{Icon ? <Icon size={size} /> : brand ? <BrandSvg icon={brand} size={size} /> : <span>{(title || '?').trim().charAt(0).toUpperCase()}</span>}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -344,6 +355,19 @@ export default function ContrasenasPage() {
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
<div className="vault-icon-picker vault-icon-picker-brands">
|
||||
{Object.entries(BRAND_ICONS).map(([key, icon]) => (
|
||||
<button
|
||||
type="button"
|
||||
key={key}
|
||||
className={`vault-icon-option brand ${form.iconKey === key ? 'selected' : ''}`}
|
||||
title={icon.title}
|
||||
onClick={() => setForm((f) => ({ ...f, iconKey: key }))}
|
||||
>
|
||||
<BrandSvg icon={icon} size={16} />
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</Field>
|
||||
)}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user