forks

Creation chat

ClarkZhang
please create a json formatter for me
02-25 08:25

登录 后可以评论

Assistant
(HTML code has been generated and updated; see above for the current version.) This JSON Formatter tool includes: 1. **Modern UI with Dark Mode Support** - Uses the Modern Blue color palette with responsive design 2. **Core Features**: - Format JSON with proper indentation - Minify JSON to compact form - Validate JSON structure - Copy formatted JSON to clipboard - Download formatted JSON as a file - Clear input and load sample data 3. **User Experience Features**: - Responsive layout that works on mobile and desktop - Local storage persistence for input data - Custom modal notifications - Theme toggle button (light/dark mode) - Clear instructions - Error handling with user-friendly messages 4. **Technical Implementation**: - Pure client-side processing (no server required) - Uses modern ES6 JavaScript - Proper error handling for invalid JSON - Clipboard API for copy functionality - Blob API for file downloads - Responsive Tailwind classes The tool works completely offline in the browser and preserves your input data between sessions using localStorage. You can access the console in the preview to see any debugging information.
▼ Code
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>JSON Formatter</title>
    <script src="https://cdn.tailwindcss.com"></script>
    <script>tailwind.config = { darkMode: 'class' }</script>
</head>
<body class="min-h-screen bg-slate-50 dark:bg-slate-900 text-slate-900 dark:text-slate-100">
    <!-- Theme toggle -->
    <button id="theme-toggle-btn" class="fixed top-4 right-4 z-10 p-2 rounded-md hover:bg-gray-200 dark:hover:bg-gray-700 text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-gray-100 transition-colors flex items-center justify-center" aria-label="Toggle theme" onclick="toggleTheme()">
        <svg id="icon-moon" class="w-5 h-5" fill="currentColor" viewBox="0 0 24 24" aria-hidden="true"><path d="M21.752 15.002A9.72 9.72 0 0 1 18 15.75c-5.385 0-9.75-4.365-9.75-9.75 0-1.33.266-2.597.748-3.752A9.753 9.753 0 0 0 3 11.25C3 16.635 7.365 21 12.75 21a9.753 9.753 0 0 0 9.002-5.998z"/></svg>
        <svg id="icon-sun" class="w-5 h-5" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" viewBox="0 0 24 24" aria-hidden="true" style="display:none"><circle cx="12" cy="12" r="4"></circle><path d="M12 2v2M12 20v2M4.93 4.93l1.41 1.41M17.66 17.66l1.41 1.41M2 12h2M20 12h2M6.34 17.66l-1.41 1.41M19.07 4.93l-1.41 1.41"></path></svg>
    </button>
    <script>
    function toggleTheme(){ var el=document.documentElement; var isDark=!el.classList.contains('dark'); el.classList.toggle('dark',isDark); localStorage.setItem('theme',isDark?'dark':'light'); applyTheme(isDark); }
    function applyTheme(isDark){ document.getElementById('icon-moon').style.display=isDark?'none':'block'; document.getElementById('icon-sun').style.display=isDark?'block':'none'; }
    document.addEventListener('DOMContentLoaded',function(){ var saved=localStorage.getItem('theme'); var isDark=saved==='dark'||(!saved&&window.matchMedia('(prefers-color-scheme: dark)').matches); document.documentElement.classList.toggle('dark',isDark); applyTheme(isDark); });
    </script>

    <!-- Custom modal -->
    <div id="custom-modal" class="fixed inset-0 z-50 flex items-center justify-center bg-black/50 p-4 hidden" aria-hidden="true">
        <div class="rounded-xl bg-white dark:bg-slate-800 p-6 shadow-xl max-w-sm w-full border border-slate-200 dark:border-slate-700">
            <p id="custom-modal-msg" class="text-slate-700 dark:text-slate-200 mb-4"></p>
            <button type="button" onclick="hideModal()" class="w-full rounded-lg bg-blue-600 px-4 py-2 text-white hover:bg-blue-700 dark:bg-blue-500 dark:hover:bg-blue-600">OK</button>
        </div>
    </div>
    <script>
    function showModal(msg){ var el=document.getElementById('custom-modal'); document.getElementById('custom-modal-msg').textContent=msg||''; el.classList.remove('hidden'); }
    function hideModal(){ document.getElementById('custom-modal').classList.add('hidden'); }
    </script>

    <div class="container mx-auto px-4 py-8 max-w-4xl">
        <header class="text-center mb-10">
            <h1 class="text-3xl md:text-4xl font-bold mb-2 text-slate-900 dark:text-slate-100">JSON Formatter</h1>
            <p class="text-slate-700 dark:text-slate-300">Format, validate, and minify your JSON data</p>
        </header>

        <main>
            <div class="grid grid-cols-1 md:grid-cols-2 gap-6 mb-6">
                <div class="bg-white dark:bg-slate-800 rounded-xl shadow-lg p-4 border border-slate-200 dark:border-slate-700">
                    <div class="flex justify-between items-center mb-3">
                        <h2 class="text-lg font-semibold text-slate-900 dark:text-slate-100">Input JSON</h2>
                        <div class="flex space-x-2">
                            <button id="clear-input" class="text-sm px-3 py-1 bg-slate-100 dark:bg-slate-700 rounded-lg hover:bg-slate-200 dark:hover:bg-slate-600 transition-colors">Clear</button>
                            <button id="load-sample" class="text-sm px-3 py-1 bg-blue-600 text-white rounded-lg hover:bg-blue-700 dark:bg-blue-500 dark:hover:bg-blue-600 transition-colors">Sample</button>
                        </div>
                    </div>
                    <textarea 
                        id="input-json" 
                        class="w-full h-64 p-3 text-slate-700 dark:text-slate-200 bg-slate-50 dark:bg-slate-900 rounded-lg border border-slate-300 dark:border-slate-600 focus:ring-2 focus:ring-blue-500 focus:border-blue-500 dark:focus:ring-blue-500 dark:focus:border-blue-500"
                        placeholder='Enter your JSON here...'
                    ></textarea>
                </div>

                <div class="bg-white dark:bg-slate-800 rounded-xl shadow-lg p-4 border border-slate-200 dark:border-slate-700">
                    <div class="flex justify-between items-center mb-3">
                        <h2 class="text-lg font-semibold text-slate-900 dark:text-slate-100">Formatted JSON</h2>
                        <div class="flex space-x-2">
                            <button id="copy-output" class="text-sm px-3 py-1 bg-slate-100 dark:bg-slate-700 rounded-lg hover:bg-slate-200 dark:hover:bg-slate-600 transition-colors">Copy</button>
                            <button id="download-output" class="text-sm px-3 py-1 bg-blue-600 text-white rounded-lg hover:bg-blue-700 dark:bg-blue-500 dark:hover:bg-blue-600 transition-colors">Download</button>
                        </div>
                    </div>
                    <pre id="output-json" class="w-full h-64 p-3 text-slate-700 dark:text-slate-200 bg-slate-50 dark:bg-slate-900 rounded-lg border border-slate-300 dark:border-slate-600 overflow-auto whitespace-pre-wrap break-all text-sm">Formatted JSON will appear here...</pre>
                </div>
            </div>

            <div class="flex flex-wrap gap-3 justify-center mb-6">
                <button id="format-btn" class="px-5 py-2.5 bg-blue-600 text-white rounded-lg hover:bg-blue-700 dark:bg-blue-500 dark:hover:bg-blue-600 transition-colors font-medium">Format JSON</button>
                <button id="minify-btn" class="px-5 py-2.5 bg-emerald-600 text-white rounded-lg hover:bg-emerald-700 dark:bg-emerald-500 dark:hover:bg-emerald-600 transition-colors font-medium">Minify JSON</button>
                <button id="validate-btn" class="px-5 py-2.5 bg-amber-600 text-white rounded-lg hover:bg-amber-700 dark:bg-amber-500 dark:hover:bg-amber-600 transition-colors font-medium">Validate JSON</button>
            </div>

            <div class="bg-white dark:bg-slate-800 rounded-xl shadow-lg p-5 border border-slate-200 dark:border-slate-700">
                <h2 class="text-lg font-semibold mb-3 text-slate-900 dark:text-slate-100">How to Use</h2>
                <ul class="list-disc pl-5 space-y-2 text-slate-700 dark:text-slate-300">
                    <li>Paste your JSON into the input box</li>
                    <li>Click "Format JSON" to prettify your JSON</li>
                    <li>Use "Minify JSON" to compress your JSON</li>
                    <li>Validate your JSON structure with "Validate JSON"</li>
                    <li>Copy or download the formatted result</li>
                </ul>
            </div>
        </main>

        <footer class="mt-10 text-center text-slate-600 dark:text-slate-400 text-sm">
            <p>JSON Formatter Tool • Works offline in your browser</p>
        </footer>
    </div>

    <script>
        document.addEventListener('DOMContentLoaded', function() {
            // DOM Elements
            const inputJson = document.getElementById('input-json');
            const outputJson = document.getElementById('output-json');
            const formatBtn = document.getElementById('format-btn');
            const minifyBtn = document.getElementById('minify-btn');
            const validateBtn = document.getElementById('validate-btn');
            const clearInputBtn = document.getElementById('clear-input');
            const loadSampleBtn = document.getElementById('load-sample');
            const copyOutputBtn = document.getElementById('copy-output');
            const downloadOutputBtn = document.getElementById('download-output');

            // Sample JSON data
            const sampleJson = {
                "name": "John Doe",
                "age": 35,
                "isEmployed": true,
                "address": {
                    "street": "123 Main St",
                    "city": "Anytown",
                    "zipcode": "12345"
                },
                "hobbies": ["reading", "swimming", "coding"],
                "spouse": null
            };

            // Load data from localStorage if available
            const savedInput = localStorage.getItem('jsonFormatterInput');
            if (savedInput) {
                inputJson.value = savedInput;
            }

            // Save input to localStorage on change
            inputJson.addEventListener('input', function() {
                localStorage.setItem('jsonFormatterInput', inputJson.value);
            });

            // Format JSON
            formatBtn.addEventListener('click', function() {
                try {
                    const jsonObj = JSON.parse(inputJson.value);
                    const formatted = JSON.stringify(jsonObj, null, 2);
                    outputJson.textContent = formatted;
                    outputJson.classList.remove('text-red-500', 'dark:text-red-400');
                    showModal('JSON formatted successfully!');
                } catch (e) {
                    outputJson.textContent = `Error: ${e.message}`;
                    outputJson.classList.add('text-red-500', 'dark:text-red-400');
                    showModal(`Invalid JSON: ${e.message}`);
                }
            });

            // Minify JSON
            minifyBtn.addEventListener('click', function() {
                try {
                    const jsonObj = JSON.parse(inputJson.value);
                    const minified = JSON.stringify(jsonObj);
                    outputJson.textContent = minified;
                    outputJson.classList.remove('text-red-500', 'dark:text-red-400');
                    showModal('JSON minified successfully!');
                } catch (e) {
                    outputJson.textContent = `Error: ${e.message}`;
                    outputJson.classList.add('text-red-500', 'dark:text-red-400');
                    showModal(`Invalid JSON: ${e.message}`);
                }
            });

            // Validate JSON
            validateBtn.addEventListener('click', function() {
                try {
                    JSON.parse(inputJson.value);
                    showModal('Valid JSON!');
                } catch (e) {
                    showModal(`Invalid JSON: ${e.message}`);
                }
            });

            // Clear input
            clearInputBtn.addEventListener('click', function() {
                inputJson.value = '';
                localStorage.removeItem('jsonFormatterInput');
            });

            // Load sample JSON
            loadSampleBtn.addEventListener('click', function() {
                inputJson.value = JSON.stringify(sampleJson, null, 2);
                localStorage.setItem('jsonFormatterInput', inputJson.value);
            });

            // Copy output to clipboard
            copyOutputBtn.addEventListener('click', function() {
                if (outputJson.textContent === 'Formatted JSON will appear here...') {
                    showModal('Nothing to copy!');
                    return;
                }

                navigator.clipboard.writeText(outputJson.textContent)
                    .then(() => {
                        showModal('Copied to clipboard!');
                    })
                    .catch(err => {
                        showModal('Failed to copy: ' + err);
                    });
            });

            // Download JSON file
            downloadOutputBtn.addEventListener('click', function() {
                if (outputJson.textContent === 'Formatted JSON will appear here...') {
                    showModal('Nothing to download!');
                    return;
                }

                try {
                    const blob = new Blob([outputJson.textContent], { type: 'application/json' });
                    const url = URL.createObjectURL(blob);
                    const a = document.createElement('a');
                    a.href = url;
                    a.download = 'formatted.json';
                    document.body.appendChild(a);
                    a.click();
                    document.body.removeChild(a);
                    URL.revokeObjectURL(url);
                    showModal('File downloaded!');
                } catch (e) {
                    showModal('Download failed: ' + e.message);
                }
            });
        });
    </script>
</body>
</html>
02-25 08:27

登录 后可以评论

Comments

登录 后可以评论