mirror of
https://github.com/kccleoc/seedpgp-web.git
synced 2026-03-07 09:57:50 +08:00
feat(entropy): Enhance entropy generation UX and fix resets
This commit introduces several improvements to the entropy generation and application state management:
1. **Implement Dice Entropy Stats Panel:**
- After generating entropy from dice rolls, a detailed statistics panel is now displayed for user review.
- This panel includes roll distribution, chi-square analysis, and a preview of the generated seed.
- Users can now choose to "Continue with this Seed" or "Roll Again" to discard and restart, improving user control and confidence in the entropy quality.
2. **Fix UI Layering and Overflow:**
- Increased the header's `z-index` to `z-[100]` to ensure it always remains on top of other components, fixing an issue where the "Reset All" button was inaccessible.
- Made the main content area for entropy components scrollable to prevent the new stats panels from overflowing the viewport on smaller screens.
3. **Improve "Reset All" Functionality:**
- The "Reset All" button now correctly resets the internal state of the `DiceEntropy` and `CameraEntropy` components.
- This is achieved by adding a `resetCounter` to the `App` state and passing it into the `key` prop of the entropy components, forcing a full remount on reset.
This commit is contained in:
50
src/App.tsx
50
src/App.tsx
@@ -76,6 +76,7 @@ function App() {
|
||||
const [sessionItems, setSessionItems] = useState<StorageItem[]>([]);
|
||||
const [clipboardEvents, setClipboardEvents] = useState<ClipboardEvent[]>([]);
|
||||
const [showLockConfirm, setShowLockConfirm] = useState(false);
|
||||
const [resetCounter, setResetCounter] = useState(0);
|
||||
|
||||
// Krux integration state
|
||||
const [encryptionMode, setEncryptionMode] = useState<'pgp' | 'krux' | 'seedqr'>('pgp');
|
||||
@@ -467,17 +468,17 @@ function App() {
|
||||
|
||||
const handleToggleNetwork = () => {
|
||||
setIsNetworkBlocked(!isNetworkBlocked);
|
||||
|
||||
|
||||
if (!isNetworkBlocked) {
|
||||
// Block network
|
||||
console.log('🚫 Network BLOCKED - No external requests allowed');
|
||||
// Optional: Override fetch/XMLHttpRequest
|
||||
if (typeof window !== 'undefined') {
|
||||
(window as any).__originalFetch = window.fetch;
|
||||
// Create a mock fetch function with proper type assertion
|
||||
const mockFetch = (async () => Promise.reject(new Error('Network blocked by user'))) as unknown as typeof window.fetch;
|
||||
window.fetch = mockFetch;
|
||||
}
|
||||
// Block network
|
||||
console.log('🚫 Network BLOCKED - No external requests allowed');
|
||||
// Optional: Override fetch/XMLHttpRequest
|
||||
if (typeof window !== 'undefined') {
|
||||
(window as any).__originalFetch = window.fetch;
|
||||
// Create a mock fetch function with proper type assertion
|
||||
const mockFetch = (async () => Promise.reject(new Error('Network blocked by user'))) as unknown as typeof window.fetch;
|
||||
window.fetch = mockFetch;
|
||||
}
|
||||
} else {
|
||||
// Unblock network
|
||||
console.log('🌐 Network ACTIVE');
|
||||
@@ -494,8 +495,8 @@ function App() {
|
||||
};
|
||||
|
||||
const handleResetAll = () => {
|
||||
if (window.confirm("Reset entire app? This will clear all seeds, passwords, and generated data.")) {
|
||||
// Clear all state
|
||||
if (window.confirm('⚠️ Reset ALL data? This will clear everything including any displayed entropy analysis.')) {
|
||||
// Clear component state
|
||||
setMnemonic('');
|
||||
setGeneratedSeed('');
|
||||
setBackupMessagePassword('');
|
||||
@@ -508,15 +509,23 @@ function App() {
|
||||
setRestoreInput('');
|
||||
setDecryptedRestoredMnemonic(null);
|
||||
setError('');
|
||||
setEntropySource(null);
|
||||
setEntropyStats(null);
|
||||
setSeedForBlender('');
|
||||
// Clear session
|
||||
|
||||
// Clear storage and session
|
||||
localStorage.clear();
|
||||
sessionStorage.clear();
|
||||
destroySessionKey();
|
||||
_setEncryptedMnemonicCache(null);
|
||||
// Go to Create tab (fresh start)
|
||||
// Force SeedBlender to remount (resets its internal state)
|
||||
|
||||
// Force remount of key-driven components
|
||||
setResetCounter(prev => prev + 1);
|
||||
setBlenderResetKey(prev => prev + 1);
|
||||
|
||||
// Go to Create tab (fresh start)
|
||||
setActiveTab('create');
|
||||
console.log('✅ All data reset');
|
||||
}
|
||||
};
|
||||
|
||||
@@ -698,6 +707,7 @@ function App() {
|
||||
{/* Camera Entropy Component */}
|
||||
{entropySource === 'camera' && !generatedSeed && (
|
||||
<CameraEntropy
|
||||
key={`camera-${resetCounter}`} // Force remount on reset
|
||||
wordCount={seedWordCount}
|
||||
onEntropyGenerated={handleEntropyGenerated}
|
||||
onCancel={() => setEntropySource(null)}
|
||||
@@ -708,6 +718,7 @@ function App() {
|
||||
{/* Dice Entropy Component */}
|
||||
{entropySource === 'dice' && !generatedSeed && (
|
||||
<DiceEntropy
|
||||
key={`dice-${resetCounter}`} // Force remount on reset
|
||||
wordCount={seedWordCount}
|
||||
onEntropyGenerated={handleEntropyGenerated}
|
||||
onCancel={() => setEntropySource(null)}
|
||||
@@ -735,7 +746,7 @@ function App() {
|
||||
</span>
|
||||
</div>
|
||||
<div className="relative">
|
||||
<p
|
||||
<p
|
||||
className="font-mono text-xs text-[#39ff14] break-words leading-relaxed blur-sensitive"
|
||||
title="Hover to reveal seed"
|
||||
style={{ textShadow: '0 0 5px rgba(57,255,20,0.5)' }}
|
||||
@@ -793,9 +804,8 @@ function App() {
|
||||
onFocus={(e) => e.target.classList.remove('blur-sensitive')}
|
||||
onBlur={(e) => mnemonic && e.target.classList.add('blur-sensitive')}
|
||||
placeholder="Enter your 12 or 24 word seed phrase..."
|
||||
className={`w-full h-32 p-3 bg-[#16213e] border-2 border-[#00f0ff]/50 rounded-lg font-mono text-sm text-[#00f0ff] placeholder-[#9d84b7] focus:outline-none focus:border-[#ff006e] focus:shadow-[0_0_20px_rgba(255,0,110,0.5)] transition-all relative overflow-hidden ${
|
||||
mnemonic ? 'blur-sensitive' : ''
|
||||
}`}
|
||||
className={`w-full h-32 p-3 bg-[#16213e] border-2 border-[#00f0ff]/50 rounded-lg font-mono text-sm text-[#00f0ff] placeholder-[#9d84b7] focus:outline-none focus:border-[#ff006e] focus:shadow-[0_0_20px_rgba(255,0,110,0.5)] transition-all relative overflow-hidden ${mnemonic ? 'blur-sensitive' : ''
|
||||
}`}
|
||||
style={{
|
||||
backgroundImage: 'repeating-linear-gradient(0deg, rgba(0,240,255,0.03) 0px, transparent 1px, transparent 2px, rgba(0,240,255,0.03) 3px)',
|
||||
textShadow: '0 0 5px rgba(0,240,255,0.5)'
|
||||
@@ -1123,7 +1133,7 @@ function App() {
|
||||
|
||||
<div className="p-4 bg-[#0a0a0f] rounded-xl border-2 border-[#39ff14] shadow-[0_0_20px_rgba(57,255,20,0.3)]">
|
||||
<div className="relative">
|
||||
<p
|
||||
<p
|
||||
className="font-mono text-center text-base break-words text-[#39ff14] blur-sensitive"
|
||||
title="Hover to reveal"
|
||||
style={{ textShadow: '0 0 8px rgba(57,255,20,0.8)' }}
|
||||
|
||||
Reference in New Issue
Block a user