- Fixed missing ref={previewFrameRef} on first PreviewFrame component (line 336)
* This was causing 'PreviewFrame API not available' errors during save operations
* Both fullscreen and normal mode PreviewFrame instances now have proper ref connection
- Fixed click handler attachment bug in setupInspectModeStyles function
* Click handler was being skipped when styles were already injected
* Now always attaches click handler when inspect mode is activated
* Added proper cleanup to prevent duplicate event listeners
- Fixed variable scope issues in PreviewFrame.fresh.js
* styleElement and cursorStyleElement now properly scoped for cleanup function
* Added references to existing elements when styles already present
- Removed unused variables and fixed eslint warnings
* Removed unused indentSize variable in BeautifierTool.js
* Removed unused onSave and onDomUpdate props in PreviewFrame.fresh.js
* Fixed unnecessary escape character in script tag
These fixes restore the Enhanced Option A DOM manipulation architecture:
- Inspector sidebar should now appear when clicking elements in inspect mode
- Save functionality should work without 'PreviewFrame ref not available' errors
- Live editing of element properties should work through PreviewFrame API
- Iframe refresh prevention during inspector operations maintained
185 lines
5.8 KiB
JavaScript
185 lines
5.8 KiB
JavaScript
import React, { useState } from 'react';
|
|
import { Hash, Upload } from 'lucide-react';
|
|
import ToolLayout from '../components/ToolLayout';
|
|
import CopyButton from '../components/CopyButton';
|
|
|
|
const Base64Tool = () => {
|
|
const [input, setInput] = useState('');
|
|
const [output, setOutput] = useState('');
|
|
const [mode, setMode] = useState('encode'); // 'encode' or 'decode'
|
|
|
|
const encodeBase64 = () => {
|
|
try {
|
|
const encoded = btoa(unescape(encodeURIComponent(input)));
|
|
setOutput(encoded);
|
|
} catch (err) {
|
|
setOutput(`Error: ${err.message}`);
|
|
}
|
|
};
|
|
|
|
const decodeBase64 = () => {
|
|
try {
|
|
const decoded = decodeURIComponent(escape(atob(input)));
|
|
setOutput(decoded);
|
|
} catch (err) {
|
|
setOutput(`Error: Invalid Base64 string`);
|
|
}
|
|
};
|
|
|
|
const handleProcess = () => {
|
|
if (mode === 'encode') {
|
|
encodeBase64();
|
|
} else {
|
|
decodeBase64();
|
|
}
|
|
};
|
|
|
|
const handleFileUpload = (event) => {
|
|
const file = event.target.files[0];
|
|
if (file) {
|
|
const reader = new FileReader();
|
|
reader.onload = (e) => {
|
|
if (mode === 'encode') {
|
|
setInput(e.target.result);
|
|
} else {
|
|
// For decode mode, read as text
|
|
const textReader = new FileReader();
|
|
textReader.onload = (textEvent) => {
|
|
setInput(textEvent.target.result);
|
|
};
|
|
textReader.readAsText(file);
|
|
}
|
|
};
|
|
|
|
if (mode === 'encode') {
|
|
reader.readAsText(file);
|
|
} else {
|
|
reader.readAsText(file);
|
|
}
|
|
}
|
|
};
|
|
|
|
const clearAll = () => {
|
|
setInput('');
|
|
setOutput('');
|
|
};
|
|
|
|
const loadSample = () => {
|
|
if (mode === 'encode') {
|
|
setInput('Hello, World! This is a sample text for Base64 encoding.');
|
|
} else {
|
|
setInput('SGVsbG8sIFdvcmxkISBUaGlzIGlzIGEgc2FtcGxlIHRleHQgZm9yIEJhc2U2NCBlbmNvZGluZy4=');
|
|
}
|
|
};
|
|
|
|
return (
|
|
<ToolLayout
|
|
title="Base64 Encoder/Decoder"
|
|
description="Convert text to Base64 and back with support for files"
|
|
icon={Hash}
|
|
>
|
|
{/* Mode Toggle */}
|
|
<div className="flex bg-gray-100 dark:bg-gray-800 rounded-lg p-1 mb-6 w-fit">
|
|
<button
|
|
onClick={() => setMode('encode')}
|
|
className={`px-4 py-2 rounded-md font-medium transition-colors ${
|
|
mode === 'encode'
|
|
? 'bg-white dark:bg-gray-700 text-primary-600 shadow-sm'
|
|
: 'text-gray-600 dark:text-gray-400'
|
|
}`}
|
|
>
|
|
Encode
|
|
</button>
|
|
<button
|
|
onClick={() => setMode('decode')}
|
|
className={`px-4 py-2 rounded-md font-medium transition-colors ${
|
|
mode === 'decode'
|
|
? 'bg-white dark:bg-gray-700 text-primary-600 shadow-sm'
|
|
: 'text-gray-600 dark:text-gray-400'
|
|
}`}
|
|
>
|
|
Decode
|
|
</button>
|
|
</div>
|
|
|
|
{/* Controls */}
|
|
<div className="flex flex-wrap gap-3 mb-6">
|
|
<button onClick={handleProcess} className="tool-button">
|
|
{mode === 'encode' ? 'Encode to Base64' : 'Decode from Base64'}
|
|
</button>
|
|
<label className="tool-button-secondary cursor-pointer flex items-center space-x-2">
|
|
<Upload className="h-4 w-4" />
|
|
<span>Upload File</span>
|
|
<input
|
|
type="file"
|
|
onChange={handleFileUpload}
|
|
className="hidden"
|
|
accept=".txt,.json,.xml,.csv"
|
|
/>
|
|
</label>
|
|
<button onClick={loadSample} className="tool-button-secondary">
|
|
Load Sample
|
|
</button>
|
|
<button onClick={clearAll} className="tool-button-secondary">
|
|
Clear All
|
|
</button>
|
|
</div>
|
|
|
|
{/* Input/Output Grid */}
|
|
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
|
|
{/* Input */}
|
|
<div className="space-y-2">
|
|
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300">
|
|
{mode === 'encode' ? 'Text to Encode' : 'Base64 to Decode'}
|
|
</label>
|
|
<div className="relative">
|
|
<textarea
|
|
value={input}
|
|
onChange={(e) => setInput(e.target.value)}
|
|
placeholder={
|
|
mode === 'encode'
|
|
? 'Enter text to encode to Base64...'
|
|
: 'Enter Base64 string to decode...'
|
|
}
|
|
className="tool-input h-96"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Output */}
|
|
<div className="space-y-2">
|
|
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300">
|
|
{mode === 'encode' ? 'Base64 Output' : 'Decoded Text'}
|
|
</label>
|
|
<div className="relative">
|
|
<textarea
|
|
value={output}
|
|
readOnly
|
|
placeholder={
|
|
mode === 'encode'
|
|
? 'Base64 encoded text will appear here...'
|
|
: 'Decoded text will appear here...'
|
|
}
|
|
className="tool-input h-96 bg-gray-50 dark:bg-gray-800"
|
|
/>
|
|
{output && <CopyButton text={output} />}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Usage Tips */}
|
|
<div className="bg-blue-50 dark:bg-blue-900/20 border border-blue-200 dark:border-blue-800 rounded-md p-4 mt-6">
|
|
<h4 className="text-blue-800 dark:text-blue-200 font-medium mb-2">Usage Tips</h4>
|
|
<ul className="text-blue-700 dark:text-blue-300 text-sm space-y-1">
|
|
<li>• Base64 encoding is commonly used for data transmission and storage</li>
|
|
<li>• Upload text files to encode/decode their contents</li>
|
|
<li>• Encoded Base64 strings are safe for URLs and email transmission</li>
|
|
<li>• Use the toggle to switch between encode and decode modes</li>
|
|
</ul>
|
|
</div>
|
|
</ToolLayout>
|
|
);
|
|
};
|
|
|
|
export default Base64Tool;
|