Files
seedpgp-web/src/components/Header.tsx
LC mac 747e298cb2 refine: Update network button labels and tooltips with honest security messaging
- Change button labels: 'Extra secure' / 'Normal' (better reflects defense-in-depth)
- Update tooltips to acknowledge CSP already blocks connections:
  - 'Extra secure: Added manual blocking layer (CSP already blocks connections)'
  - 'Normal: Relying on CSP to block connections'
- Update comment: Clarify button adds extra manual layer, not primary control
- More transparent about how security actually works (CSP does the real work)
2026-02-12 23:22:02 +08:00

167 lines
6.8 KiB
TypeScript

import React from 'react';
import { Shield, RefreshCw } from 'lucide-react';
import SecurityBadge from './badges/SecurityBadge';
import StorageBadge from './badges/StorageBadge';
import ClipboardBadge from './badges/ClipboardBadge';
interface StorageItem {
key: string;
value: string;
size: number;
isSensitive: boolean;
}
interface ClipboardEvent {
timestamp: Date;
field: string;
length: number;
}
interface HeaderProps {
onOpenSecurityModal: () => void;
onOpenStorageModal: () => void;
localItems: StorageItem[];
sessionItems: StorageItem[];
events: ClipboardEvent[];
onOpenClipboardModal: () => void;
activeTab: 'create' | 'backup' | 'restore' | 'seedblender';
onRequestTabChange: (tab: 'create' | 'backup' | 'restore' | 'seedblender') => void;
appVersion: string;
isNetworkBlocked: boolean;
onToggleNetwork: () => void;
onResetAll: () => void; // NEW
}
const Header: React.FC<HeaderProps> = ({
onOpenSecurityModal,
onOpenStorageModal,
localItems,
sessionItems,
events,
onOpenClipboardModal,
activeTab,
onRequestTabChange,
appVersion,
isNetworkBlocked,
onToggleNetwork,
onResetAll
}) => {
return (
<header className="sticky top-0 z-[100] bg-[#0a0a0f] border-b border-[#00f0ff30] backdrop-blur-sm">
<div className="w-full px-4 py-3 space-y-3">
{/* ROW 1: Logo + App Info (LEFT) | Reset (RIGHT) */}
<div className="flex items-center justify-between">
<div className="flex items-center gap-3">
<div className="w-10 h-10 bg-[#00f0ff] rounded-lg flex items-center justify-center shadow-[0_0_15px_rgba(0,240,255,0.5)]">
<Shield className="w-6 h-6 text-[#0a0a0f]" />
</div>
<div>
<h1 className="text-lg font-semibold text-[#00f0ff]" style={{ textShadow: '0 0 10px rgba(0,240,255,0.7)' }}>
SeedPGP <span className="text-[#ff006e]">{appVersion}</span>
</h1>
<p className="text-xs text-[#6ef3f7]">OpenPGP-secured BIP39 backup</p>
</div>
</div>
{/* Reset button - top right */}
<button
onClick={onResetAll}
className="flex items-center gap-1.5 px-3 py-1.5 text-xs bg-[#16213e] border border-[#ff006e] text-[#ff006e] rounded-lg font-medium hover:bg-[#ff006e20] transition-all"
title="Reset all data"
>
<RefreshCw size={12} />
<span className="hidden sm:inline">Reset</span>
</button>
</div>
{/* ROW 2: Badges (LEFT) | Action Buttons (RIGHT) */}
<div className="flex items-center gap-2 pb-2 border-b border-[#00f0ff20]">
{/* Left: Monitoring Badges */}
<div className="flex items-center gap-2">
<SecurityBadge onClick={onOpenSecurityModal} />
<div onClick={onOpenStorageModal} className="cursor-pointer">
<StorageBadge localItems={localItems} sessionItems={sessionItems} />
</div>
<div onClick={onOpenClipboardModal} className="cursor-pointer">
<ClipboardBadge events={events} onOpenClipboardModal={onOpenClipboardModal} />
</div>
</div>
{/* Spacer - pushes right content to the right */}
<div className="flex-1"></div>
{/* Right: Action Buttons */}
<div className="flex items-center gap-2">
{/* Defense-in-depth toggle: Add extra manual blocking layer on top of CSP */}
<button
onClick={onToggleNetwork}
className={`flex items-center gap-1 px-2.5 py-1.5 text-xs rounded-lg font-medium transition-all whitespace-nowrap ${isNetworkBlocked
? 'bg-[#16213e] border border-[#ff006e] text-[#ff006e] hover:bg-[#ff006e20]'
: 'bg-[#16213e] border border-[#39ff14] text-[#39ff14] hover:bg-[#39ff1420]'
}`}
title={isNetworkBlocked
? 'Extra secure: Added manual blocking layer (CSP already blocks connections)'
: 'Normal: Relying on CSP to block connections'}
>
<span className="text-sm">{isNetworkBlocked ? '🚫' : '🌐'}</span>
<span className="hidden sm:inline text-[10px]">
{isNetworkBlocked ? 'Extra secure' : 'Normal'}
</span>
</button>
</div>
</div>
{/* ROW 3: Navigation Tabs */}
<div className="grid grid-cols-4 gap-2">
<button
className={`py-2 rounded-lg font-medium text-xs whitespace-nowrap transition-all ${activeTab === 'create'
? 'bg-[#1a1a2e] text-[#00f0ff] border-2 border-[#ff006e] shadow-[0_0_15px_rgba(255,0,110,0.5)]'
: 'bg-[#0a0a0f] text-[#9d84b7] border-2 border-[#00f0ff30] hover:text-[#6ef3f7] hover:border-[#00f0ff50]'
}`}
style={activeTab === 'create' ? { textShadow: '0 0 10px rgba(0,240,255,0.8)' } : undefined}
onClick={() => onRequestTabChange('create')}
>
Create
</button>
<button
className={`py-2 rounded-lg font-medium text-xs whitespace-nowrap transition-all ${activeTab === 'backup'
? 'bg-[#1a1a2e] text-[#00f0ff] border-2 border-[#ff006e] shadow-[0_0_15px_rgba(255,0,110,0.5)]'
: 'bg-[#0a0a0f] text-[#9d84b7] border-2 border-[#00f0ff30] hover:text-[#6ef3f7] hover:border-[#00f0ff50]'
}`}
style={activeTab === 'backup' ? { textShadow: '0 0 10px rgba(0,240,255,0.8)' } : undefined}
onClick={() => onRequestTabChange('backup')}
>
Backup
</button>
<button
className={`py-2 rounded-lg font-medium text-xs whitespace-nowrap transition-all ${activeTab === 'restore'
? 'bg-[#1a1a2e] text-[#00f0ff] border-2 border-[#ff006e] shadow-[0_0_15px_rgba(255,0,110,0.5)]'
: 'bg-[#0a0a0f] text-[#9d84b7] border-2 border-[#00f0ff30] hover:text-[#6ef3f7] hover:border-[#00f0ff50]'
}`}
style={activeTab === 'restore' ? { textShadow: '0 0 10px rgba(0,240,255,0.8)' } : undefined}
onClick={() => onRequestTabChange('restore')}
>
Restore
</button>
<button
className={`py-2 rounded-lg font-medium text-xs whitespace-nowrap transition-all ${activeTab === 'seedblender'
? 'bg-[#1a1a2e] text-[#00f0ff] border-2 border-[#ff006e] shadow-[0_0_15px_rgba(255,0,110,0.5)]'
: 'bg-[#0a0a0f] text-[#9d84b7] border-2 border-[#00f0ff30] hover:text-[#6ef3f7] hover:border-[#00f0ff50]'
}`}
style={activeTab === 'seedblender' ? { textShadow: '0 0 10px rgba(0,240,255,0.8)' } : undefined}
onClick={() => onRequestTabChange('seedblender')}
>
Blender
</button>
</div>
</div>
</header>
);
};
export default Header;