Fix TypeScript errors, remove non-functional Empty button, right-align Network Block toggle

- Fix CameraEntropy and DiceEntropy import errors
- Fix unused variable warnings in App.tsx and Header.tsx
- Remove non-functional Empty storage button from Header
- Right-align Network Block toggle button with flex-1 spacer
- Add NetworkBlockBadge component file
This commit is contained in:
LC mac
2026-02-10 01:19:24 +08:00
parent 586eabc361
commit ab1f35ce80
7 changed files with 197 additions and 101 deletions

View File

@@ -168,7 +168,7 @@ const DiceEntropy: React.FC<DiceEntropyProps> = ({
</div>
<div className="space-y-2">
<label className="text-[10px] font-bold text-[#00f0ff] uppercase tracking-widest">Enter Dice Rolls</label>
<textarea value={rolls} onChange={(e) => { setRolls(e.target.value.replace(/[^1-6\s]/g, '')); setError(''); }} placeholder="99+ dice rolls (e.g., 16345...)" className="w-full h-32 p-3 bg-[#0a0a0f] border-2 border-[#00f0ff]/50 rounded-lg font-mono text-xs placeholder:text-[10px] placeholder:text-[#6ef3f7] focus:outline-none focus:border-[#ff006e] focus:shadow-[0_0_20px_rgba(255,0,110,0.5)] transition-all resize-none" />
<textarea value={rolls} onChange={(e) => { setRolls(e.target.value.replace(/[^1-6\s]/g, '')); setError(''); }} placeholder="99+ dice rolls (e.g., 16345...)" className="w-full h-32 p-3 bg-[#0a0a0f] border-2 border-[#00f0ff]/50 rounded-lg font-mono text-sm text-[#00f0ff] placeholder:text-[10px] placeholder:text-[#6ef3f7] focus:outline-none focus:border-[#ff006e] focus:shadow-[0_0_20px_rgba(255,0,110,0.5)] transition-all resize-none" />
<p className="text-[10px] text-[#6ef3f7]">Current: {rolls.replace(/\s/g, '').length} rolls {rolls.replace(/\s/g, '').length >= 99 && ' ✓'}</p>
</div>
{error && (<div className="flex items-start gap-2 p-3 bg-[#0a0a0f] border border-[#ff006e] rounded-lg"><AlertCircle size={16} className="text-[#ff006e] shrink-0 mt-0.5" /><p className="text-xs text-[#ff006e]">{error}</p></div>)}

View File

@@ -3,7 +3,6 @@ import { Shield, RefreshCw } from 'lucide-react';
import SecurityBadge from './badges/SecurityBadge';
import StorageBadge from './badges/StorageBadge';
import ClipboardBadge from './badges/ClipboardBadge';
import EditLockBadge from './badges/EditLockBadge';
interface StorageItem {
key: string;
@@ -27,10 +26,9 @@ interface HeaderProps {
onOpenClipboardModal: () => void;
activeTab: 'create' | 'backup' | 'restore' | 'seedblender';
onRequestTabChange: (tab: 'create' | 'backup' | 'restore' | 'seedblender') => void;
encryptedMnemonicCache: any;
appVersion: string;
isLocked: boolean;
onToggleLock: () => void;
isNetworkBlocked: boolean;
onToggleNetwork: () => void;
onResetAll: () => void; // NEW
}
@@ -43,17 +41,16 @@ const Header: React.FC<HeaderProps> = ({
onOpenClipboardModal,
activeTab,
onRequestTabChange,
encryptedMnemonicCache,
appVersion,
isLocked,
onToggleLock,
isNetworkBlocked,
onToggleNetwork,
onResetAll
}) => {
return (
<header className="sticky top-0 z-50 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 */}
{/* 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)]">
@@ -66,11 +63,21 @@ const Header: React.FC<HeaderProps> = ({
<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: Monitoring Badges + Action Buttons */}
<div className="flex items-center justify-between gap-2 pb-2 border-b border-[#00f0ff20]">
{/* Left: Badges */}
{/* 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">
@@ -79,40 +86,27 @@ const Header: React.FC<HeaderProps> = ({
<div onClick={onOpenClipboardModal} className="cursor-pointer">
<ClipboardBadge events={events} onOpenClipboardModal={onOpenClipboardModal} />
</div>
<EditLockBadge isLocked={isLocked} onToggle={onToggleLock} />
</div>
{/* Spacer - pushes right content to the right */}
<div className="flex-1"></div>
{/* Right: Action Buttons */}
<div className="flex items-center gap-2">
{encryptedMnemonicCache && (
<button
onClick={onToggleLock}
className="px-2 py-1.5 text-base bg-[#16213e] border border-[#00f0ff] text-[#00f0ff] rounded-lg font-medium hover:bg-[#00f0ff20] transition-all"
title={isLocked ? "Show sensitive data" : "Hide sensitive data"}
>
{isLocked ? '🔓' : '🙈'}
</button>
)}
{/* Network Block toggle */}
<button
onClick={async () => {
try {
await navigator.clipboard.writeText('');
} catch { }
localStorage.clear();
sessionStorage.clear();
}}
className="px-2 py-1.5 text-base bg-[#16213e] border border-[#00f0ff] text-[#00f0ff] rounded-lg font-medium hover:bg-[#00f0ff20] transition-all"
title="Clear clipboard and storage"
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 ? 'Network BLOCKED' : 'Network ACTIVE'}
>
📋
</button>
<button
onClick={onResetAll}
className="px-2 py-1.5 text-xs bg-[#16213e] border border-[#ff006e] text-[#ff006e] rounded-lg font-medium hover:bg-[#ff006e20] transition-all whitespace-nowrap flex items-center gap-1"
>
<RefreshCw size={12} />
Reset
<span className="text-sm">{isNetworkBlocked ? '🚫' : '🌐'}</span>
<span className="hidden sm:inline text-[10px]">
{isNetworkBlocked ? 'Blocked' : 'Active'}
</span>
</button>
</div>
</div>
@@ -120,10 +114,11 @@ const Header: React.FC<HeaderProps> = ({
{/* 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]'
}`}
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')}
>
@@ -131,10 +126,11 @@ const Header: React.FC<HeaderProps> = ({
</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]'
}`}
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')}
>
@@ -142,10 +138,11 @@ const Header: React.FC<HeaderProps> = ({
</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]'
}`}
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')}
>
@@ -153,10 +150,11 @@ const Header: React.FC<HeaderProps> = ({
</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]'
}`}
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')}
>

View File

@@ -311,8 +311,12 @@ export function SeedBlender({ onDirtyStateChange, setMnemonicForBackup, requestT
<textarea
value={entry.rawInput}
onChange={(e) => updateEntry(index, { rawInput: e.target.value, decryptedMnemonic: e.target.value, isValid: null, error: null })}
onFocus={(e) => e.target.classList.remove('blur-sensitive')}
onBlur={(e) => entry.rawInput && e.target.classList.add('blur-sensitive')}
placeholder={`Mnemonic #${index + 1} (12 or 24 words)`}
className={`w-full h-24 p-3 bg-[#0a0a0f] border-2 rounded-lg font-mono text-xs placeholder:text-[10px] placeholder:text-[#6ef3f7] focus:outline-none focus:border-[#ff006e] focus:shadow-[0_0_20px_rgba(255,0,110,0.5)] transition-all ${getBorderColor(entry.isValid)}`}
className={`w-full h-24 p-3 bg-[#0a0a0f] border-2 rounded-lg font-mono text-xs text-[#00f0ff] placeholder:text-[10px] placeholder:text-[#6ef3f7] focus:outline-none focus:border-[#ff006e] focus:shadow-[0_0_20px_rgba(255,0,110,0.5)] transition-all ${getBorderColor(entry.isValid)} ${
entry.rawInput ? 'blur-sensitive' : ''
}`}
/>
{/* Row 2: QR button (left) and X button (right) */}
<div className="flex items-center justify-between">
@@ -350,7 +354,7 @@ export function SeedBlender({ onDirtyStateChange, setMnemonicForBackup, requestT
<div className="p-6 bg-[#16213e] rounded-xl border-2 border-[#00f0ff]/30">
<h3 className="font-semibold text-lg mb-4 text-[#00f0ff]" style={{ textShadow: '0 0 10px rgba(0,240,255,0.7)' }}>Step 3: Input Dice Rolls</h3>
<div className="space-y-4">
<textarea value={diceRolls} onChange={(e) => setDiceRolls(e.target.value.replace(/[^1-6]/g, ''))} placeholder="99+ dice rolls (e.g., 16345...)" className="w-full h-32 p-3 bg-[#16213e] border-2 border-[#00f0ff]/50 rounded-lg font-mono text-xs placeholder:text-[10px] placeholder:text-[#6ef3f7]" />
<textarea value={diceRolls} onChange={(e) => setDiceRolls(e.target.value.replace(/[^1-6]/g, ''))} placeholder="99+ dice rolls (e.g., 16345...)" className="w-full h-32 p-3 bg-[#16213e] border-2 border-[#00f0ff]/50 rounded-lg font-mono text-sm placeholder:text-[10px] placeholder:text-[#6ef3f7]" />
{dicePatternWarning && (<div className="p-3 bg-[#ff006e]/10 border-2 border-[#ff006e]/30 text-[#ff006e] rounded-lg text-sm flex gap-3"><AlertTriangle /><p><span className="font-bold">Warning:</span> {dicePatternWarning}</p></div>)}
{diceStats && diceStats.length > 0 && (<div className="grid grid-cols-2 md:grid-cols-4 gap-4 text-center"><div className="p-3 bg-[#1a1a2e] rounded-lg border-2 border-[#00f0ff]/30"><p className="text-xs text-[#6ef3f7]">Rolls</p><p className="text-lg font-bold text-[#00f0ff]">{diceStats.length}</p></div><div className="p-3 bg-[#1a1a2e] rounded-lg border-2 border-[#00f0ff]/30"><p className="text-xs text-[#6ef3f7]">Entropy (bits)</p><p className="text-lg font-bold text-[#00f0ff]">{diceStats.estimatedEntropyBits.toFixed(1)}</p></div><div className="p-3 bg-[#1a1a2e] rounded-lg border-2 border-[#00f0ff]/30"><p className="text-xs text-[#6ef3f7]">Mean</p><p className="text-lg font-bold text-[#00f0ff]">{diceStats.mean.toFixed(2)}</p></div><div className="p-3 bg-[#1a1a2e] rounded-lg border-2 border-[#00f0ff]/30"><p className="text-xs text-[#6ef3f7]">Chi-Square</p><p className={`text-lg font-bold ${diceStats.chiSquare > 11.07 ? 'text-[#ff006e]' : 'text-[#00f0ff]'}`}>{diceStats.chiSquare.toFixed(2)}</p></div></div>)}
{diceOnlyMnemonic && (<div className="space-y-1 pt-2"><label className="text-xs font-semibold text-[#00f0ff] uppercase tracking-widest" style={{ textShadow: '0 0 10px rgba(0,240,255,0.7)' }}>Dice-Only Preview Mnemonic</label><p data-sensitive="Dice-Only Preview Mnemonic" className="p-3 bg-[#1a1a2e] rounded-md font-mono text-sm text-[#00f0ff] break-words border-2 border-[#00f0ff]/30">{diceOnlyMnemonic}</p></div>)}

View File

@@ -0,0 +1,28 @@
import React from 'react';
import { Wifi, WifiOff } from 'lucide-react';
interface NetworkBlockBadgeProps {
isBlocked: boolean;
onToggle: () => void;
}
const NetworkBlockBadge: React.FC<NetworkBlockBadgeProps> = ({ isBlocked, onToggle }) => {
return (
<button
onClick={onToggle}
className={`flex items-center gap-1.5 px-2 py-1 rounded-lg text-xs font-medium transition-all ${
isBlocked
? 'bg-[#ff006e20] border border-[#ff006e] text-[#ff006e] hover:bg-[#ff006e30]'
: 'bg-[#39ff1420] border border-[#39ff14] text-[#39ff14] hover:bg-[#39ff1430]'
}`}
title={isBlocked ? 'Network is BLOCKED' : 'Network is ACTIVE'}
>
{isBlocked ? <WifiOff size={12} /> : <Wifi size={12} />}
<span className="hidden sm:inline">
{isBlocked ? 'Blocked' : 'Active'}
</span>
</button>
);
};
export default NetworkBlockBadge;