Spaces:
Running
Running
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Visual JSON Editor</title> | |
| <script src="https://cdn.tailwindcss.com"></script> | |
| <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> | |
| <link rel="stylesheet" href="style.css"> | |
| <script> | |
| tailwind.config = { | |
| theme: { | |
| extend: { | |
| colors: { | |
| primary: '#3b82f6', | |
| secondary: '#1e40af', | |
| dark: '#0f172a', | |
| light: '#f8fafc' | |
| } | |
| } | |
| } | |
| } | |
| </script> | |
| </head> | |
| <body class="bg-slate-900 h-screen overflow-hidden p-0"> | |
| <div class="w-full h-screen flex flex-col"> | |
| <header class="flex-shrink-0 mb-1 text-center py-1"> | |
| <h1 class="text-2xl font-bold text-slate-100">Visual JSON Editor</h1> | |
| <p class="text-slate-400 text-sm">The way JSON should <i class="italic font-semibold">ALWAYS</i> been editored!</p> | |
| </header> | |
| <!-- Menu Bar --> | |
| <div class="menu-bar flex flex-wrap py-1 px-2 flex-shrink-0"> | |
| <div class="dropdown"> | |
| <div class="menu-item px-2 py-1">File</div> | |
| <div class="dropdown-content"> | |
| <a href="#" id="newBtn"><i class="fas fa-plus mr-2"></i>New</a> | |
| <a href="#" id="openBtn"><i class="fas fa-folder-open mr-2"></i>Open</a> | |
| <a href="#" id="saveBtn"><i class="fas fa-save mr-2"></i>Save</a> | |
| </div> | |
| </div> | |
| <div class="dropdown"> | |
| <div class="menu-item px-2 py-1">Edit</div> | |
| <div class="dropdown-content"> | |
| <a href="#" id="undoBtn"><i class="fas fa-undo mr-2"></i>Undo</a> | |
| <a href="#" id="redoBtn"><i class="fas fa-redo mr-2"></i>Redo</a> | |
| <a href="#" id="copyBtnMenu"><i class="fas fa-copy mr-2"></i>Copy</a> | |
| <a href="#" id="cutBtnMenu"><i class="fas fa-cut mr-2"></i>Cut</a> | |
| <a href="#" id="pasteBtnMenu"><i class="fas fa-paste mr-2"></i>Paste</a> | |
| <a href="#" id="preferencesBtn"><i class="fas fa-cog mr-2"></i>Preferences</a> | |
| </div> | |
| </div> | |
| <div class="dropdown"> | |
| <div class="menu-item px-2 py-1">Tools</div> | |
| <div class="dropdown-content"> | |
| <a href="#" id="formatBtn"><i class="fas fa-indent mr-2"></i>Format</a> | |
| <a href="#" id="validateBtn"><i class="fas fa-check-circle mr-2"></i>Validate</a> | |
| </div> | |
| </div> | |
| <div class="dropdown"> | |
| <div class="menu-item px-2 py-1">Help</div> | |
| <div class="dropdown-content"> | |
| <a href="#" id="instructionsBtn"><i class="fas fa-info-circle mr-2"></i>Instructions</a> | |
| <a href="#" id="sampleBtn"><i class="fas fa-code mr-2"></i>Sample JSON</a> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="bg-slate-800 rounded-lg overflow-hidden mb-1 border border-slate-700 flex-1 flex flex-col overflow-hidden"> | |
| <div class="p-2 bg-slate-700 border-b border-slate-600 flex flex-wrap items-center justify-between gap-2"> | |
| <div class="flex flex-wrap gap-1"> | |
| <button id="newBtn2" class="btn bg-primary hover:bg-secondary text-white px-3 py-1.5 rounded flex items-center gap-1 text-sm"> | |
| <i class="fas fa-plus text-xs"></i> New | |
| </button> | |
| <button id="openBtn2" class="btn bg-slate-600 hover:bg-slate-500 px-3 py-1.5 rounded flex items-center gap-1 text-sm"> | |
| <i class="fas fa-folder-open text-xs"></i> Open | |
| </button> | |
| <button id="saveBtn2" class="btn bg-slate-600 hover:bg-slate-500 px-3 py-1.5 rounded flex items-center gap-1 text-sm"> | |
| <i class="fas fa-save text-xs"></i> Save | |
| </button> | |
| </div> | |
| <div class="flex flex-wrap gap-1"> | |
| <button id="undoBtn2" class="btn bg-slate-600 hover:bg-slate-500 px-2 py-1.5 rounded text-sm"> | |
| <i class="fas fa-undo text-xs"></i> | |
| </button> | |
| <button id="redoBtn2" class="btn bg-slate-600 hover:bg-slate-500 px-2 py-1.5 rounded text-sm"> | |
| <i class="fas fa-redo text-xs"></i> | |
| </button> | |
| <button id="formatBtn2" class="btn bg-slate-600 hover:bg-slate-500 px-2 py-1.5 rounded text-sm"> | |
| <i class="fas fa-indent text-xs"></i> | |
| </button> | |
| <button id="validateBtn2" class="btn bg-slate-600 hover:bg-slate-500 px-2 py-1.5 rounded text-sm"> | |
| <i class="fas fa-check-circle text-xs"></i> | |
| </button> | |
| </div> | |
| </div> | |
| <div class="flex flex-col lg:flex-row gap-0.5"> | |
| <!-- Left Panel - Visual JSON Editor --> | |
| <div class="w-full lg:w-1/2"> | |
| <div class="bg-slate-700 h-full flex flex-col" style="height: calc(100vh - 120px);"> | |
| <div class="flex justify-between items-center px-2 py-1 border-b border-slate-600"> | |
| <h2 class="text-sm font-semibold text-slate-200">Visual Editor</h2> | |
| <span class="text-xs text-slate-400">Click to edit • Tab nav • Ctrl+Tab indent</span> | |
| </div> | |
| <div class="relative json-editor border-none overflow-auto flex-1" style="min-height: 100%;"> | |
| <!-- Left line numbers --> | |
| <div id="lineNumbersLeft" class="absolute left-0 top-0 bottom-0 w-8 bg-slate-800 text-slate-500 text-xs font-mono text-right pr-2 select-none overflow-hidden z-10 pt-1 border-r border-slate-700"></div> | |
| <!-- Right line numbers --> | |
| <div id="lineNumbersRight" class="absolute right-0 top-0 bottom-0 w-8 bg-slate-800 text-slate-500 text-xs font-mono text-left pl-2 select-none overflow-hidden z-10 pt-1 border-l border-slate-700"></div> | |
| <!-- JSON content --> | |
| <div id="jsonEditor" class="pl-9 pr-9 py-1 font-mono text-sm"> | |
| <!-- JSON content will be rendered here --> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Right Panel - JSON Code Editor --> | |
| <div class="w-full lg:w-1/2"> | |
| <div class="bg-gray-50 h-full flex flex-col" style="height: calc(100vh - 120px);"> | |
| <div class="flex justify-between items-center px-2 py-1 border-b border-gray-300 bg-gray-100"> | |
| <h2 class="text-sm font-semibold text-gray-700">Code Editor</h2> | |
| <div class="flex gap-1 items-center"> | |
| <span id="autoSaveStatus" class="text-xs text-green-600 hidden"><i class="fas fa-check-circle mr-1"></i>Auto-saved</span> | |
| <button id="applyCodeBtn" class="btn bg-green-500 hover:bg-green-600 text-white px-2 py-1 rounded text-xs"> | |
| <i class="fas fa-check mr-1"></i> Apply | |
| </button> | |
| </div> | |
| </div> | |
| <textarea id="jsonOutput" class="w-full flex-1 font-mono text-sm p-1 border-none bg-white focus:outline-none resize-none" style="min-height: 100%;"></textarea> | |
| <div class="px-2 py-1 border-t border-gray-300 flex flex-wrap gap-1 justify-between items-center bg-gray-100"> | |
| <div class="flex gap-1"> | |
| <button id="copyBtn" class="btn bg-gray-200 hover:bg-gray-300 px-2 py-1 rounded text-xs"> | |
| <i class="fas fa-copy mr-1"></i> Copy | |
| </button> | |
| <button id="downloadBtn" class="btn bg-primary hover:bg-secondary text-white px-2 py-1 rounded text-xs"> | |
| <i class="fas fa-download mr-1"></i> Download | |
| </button> | |
| </div> | |
| <div id="validationStatus" class="flex items-center gap-1 text-xs"> | |
| <i class="fas fa-check-circle text-green-500"></i> | |
| <span class="text-green-600">Valid</span> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <div id="notification" class="notification fixed bottom-4 right-4 bg-white shadow-lg rounded-lg p-4 border-l-4 border-green-500 max-w-md z-50"> | |
| <div class="flex items-start"> | |
| <i class="fas fa-check-circle text-green-500 text-xl mt-0.5 mr-3"></i> | |
| <div> | |
| <h4 class="font-bold text-gray-800">Success!</h4> | |
| <p class="text-gray-600 mt-1">Your JSON has been updated successfully.</p> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Coordinates display - fixed position --> | |
| <div id="coordinates" class="fixed top-16 right-2 bg-slate-800 text-slate-300 px-2 py-1 rounded text-xs font-mono shadow-lg z-50 opacity-80 hover:opacity-100 transition-opacity border border-slate-600"> | |
| <span id="coordLine">L:0</span> <span id="coordChar">C:0</span> <span id="coordDepth">D:0</span> | |
| </div> | |
| <!-- Context menu --> | |
| <div id="contextMenu" class="context-menu"> | |
| <div class="context-menu-item" id="ctxInsertAfter"> | |
| <i class="fas fa-plus"></i> Insert Line After | |
| </div> | |
| <div class="context-menu-item" id="ctxInsertBefore"> | |
| <i class="fas fa-arrow-up"></i> Insert Line Before | |
| </div> | |
| <div class="context-menu-divider"></div> | |
| <div class="context-menu-item" id="ctxCopyKey"> | |
| <i class="fas fa-copy"></i> Copy Key | |
| </div> | |
| <div class="context-menu-item" id="ctxCopyValue"> | |
| <i class="fas fa-copy"></i> Copy Value | |
| </div> | |
| <div class="context-menu-item" id="ctxDelete"> | |
| <i class="fas fa-trash"></i> Delete | |
| </div> | |
| </div> | |
| </div> | |
| <script src="script.js"></script> | |
| </body> |