|
| 1 | +<!DOCTYPE html> |
| 2 | +<html lang="en"> |
| 3 | +<head> |
| 4 | +<meta charset="UTF-8"> |
| 5 | +<title>JSON Explorer</title> |
| 6 | +<meta name="viewport" content="width=device-width, initial-scale=1"> |
| 7 | + |
| 8 | +<style> |
| 9 | + |
| 10 | +:root{ |
| 11 | + --bg:#0f172a; |
| 12 | + --panel:#1e293b; |
| 13 | + --border:#334155; |
| 14 | + --text:#e2e8f0; |
| 15 | + --accent:#38bdf8; |
| 16 | + --key:#f59e0b; |
| 17 | + --string:#22c55e; |
| 18 | + --number:#a78bfa; |
| 19 | +} |
| 20 | + |
| 21 | +body{ |
| 22 | + margin:0; |
| 23 | + background:var(--bg); |
| 24 | + color:var(--text); |
| 25 | + font-family:system-ui; |
| 26 | +} |
| 27 | + |
| 28 | +header{ |
| 29 | + padding:16px; |
| 30 | + border-bottom:1px solid var(--border); |
| 31 | + font-size:20px; |
| 32 | + font-weight:600; |
| 33 | +} |
| 34 | + |
| 35 | +.container{ |
| 36 | + padding:16px; |
| 37 | +} |
| 38 | + |
| 39 | +textarea{ |
| 40 | + width:100%; |
| 41 | + height:180px; |
| 42 | + background:var(--panel); |
| 43 | + color:var(--text); |
| 44 | + border:1px solid var(--border); |
| 45 | + padding:12px; |
| 46 | + border-radius:8px; |
| 47 | + font-family:monospace; |
| 48 | +} |
| 49 | + |
| 50 | +button{ |
| 51 | + margin-top:10px; |
| 52 | + padding:8px 16px; |
| 53 | + background:var(--accent); |
| 54 | + border:none; |
| 55 | + border-radius:6px; |
| 56 | + cursor:pointer; |
| 57 | +} |
| 58 | + |
| 59 | +.tabs{ |
| 60 | + margin-top:20px; |
| 61 | +} |
| 62 | + |
| 63 | +.tab-buttons{ |
| 64 | + display:flex; |
| 65 | + gap:10px; |
| 66 | + margin-bottom:12px; |
| 67 | +} |
| 68 | + |
| 69 | +.tab{ |
| 70 | + padding:6px 12px; |
| 71 | + border:1px solid var(--border); |
| 72 | + cursor:pointer; |
| 73 | +} |
| 74 | + |
| 75 | +.active{ |
| 76 | + background:var(--accent); |
| 77 | + color:black; |
| 78 | +} |
| 79 | + |
| 80 | +.panel{ |
| 81 | + background:var(--panel); |
| 82 | + border:1px solid var(--border); |
| 83 | + padding:16px; |
| 84 | + border-radius:8px; |
| 85 | +} |
| 86 | + |
| 87 | +.node{ |
| 88 | + margin-left:18px; |
| 89 | + font-family:monospace; |
| 90 | +} |
| 91 | + |
| 92 | +.key{ |
| 93 | + color:var(--key); |
| 94 | +} |
| 95 | + |
| 96 | +.string{ |
| 97 | + color:var(--string); |
| 98 | +} |
| 99 | + |
| 100 | +.number{ |
| 101 | + color:var(--number); |
| 102 | +} |
| 103 | + |
| 104 | +.toggle{ |
| 105 | + cursor:pointer; |
| 106 | + margin-right:6px; |
| 107 | +} |
| 108 | + |
| 109 | +table{ |
| 110 | + width:100%; |
| 111 | + border-collapse:collapse; |
| 112 | +} |
| 113 | + |
| 114 | +th,td{ |
| 115 | + border:1px solid var(--border); |
| 116 | + padding:8px; |
| 117 | +} |
| 118 | + |
| 119 | +th{ |
| 120 | + background:#020617; |
| 121 | +} |
| 122 | + |
| 123 | +.path{ |
| 124 | + font-family:monospace; |
| 125 | +} |
| 126 | + |
| 127 | +</style> |
| 128 | +</head> |
| 129 | + |
| 130 | + |
| 131 | +<body> |
| 132 | + |
| 133 | +<header> |
| 134 | +JSON Explorer |
| 135 | +</header> |
| 136 | + |
| 137 | +<div class="container"> |
| 138 | + |
| 139 | +<textarea id="jsonInput" placeholder="Paste JSON here"></textarea> |
| 140 | + |
| 141 | +<br> |
| 142 | + |
| 143 | +<button onclick="renderJSON()">View JSON</button> |
| 144 | +<button onclick="generateSchema()">Generate Schema</button> |
| 145 | + |
| 146 | +<div class="tabs"> |
| 147 | + |
| 148 | +<div class="tab-buttons"> |
| 149 | +<div class="tab active" onclick="switchTab('viewer')">JSON Viewer</div> |
| 150 | +<div class="tab" onclick="switchTab('schema')">Schema</div> |
| 151 | +</div> |
| 152 | + |
| 153 | +<div id="viewer" class="panel"></div> |
| 154 | + |
| 155 | +<div id="schema" class="panel" style="display:none"></div> |
| 156 | + |
| 157 | +</div> |
| 158 | + |
| 159 | +</div> |
| 160 | + |
| 161 | + |
| 162 | +<script> |
| 163 | + |
| 164 | +function switchTab(tab){ |
| 165 | + |
| 166 | +document.querySelectorAll(".tab").forEach(t=>t.classList.remove("active")) |
| 167 | +event.target.classList.add("active") |
| 168 | + |
| 169 | +document.getElementById("viewer").style.display = tab==="viewer" ? "block":"none" |
| 170 | +document.getElementById("schema").style.display = tab==="schema" ? "block":"none" |
| 171 | + |
| 172 | +} |
| 173 | + |
| 174 | + |
| 175 | + |
| 176 | +function getType(val){ |
| 177 | + |
| 178 | +if(Array.isArray(val)) return "array" |
| 179 | +if(val===null) return "null" |
| 180 | +return typeof val |
| 181 | + |
| 182 | +} |
| 183 | + |
| 184 | + |
| 185 | + |
| 186 | +function createNode(key,val,path){ |
| 187 | + |
| 188 | +let type=getType(val) |
| 189 | + |
| 190 | +let container=document.createElement("div") |
| 191 | +container.className="node" |
| 192 | + |
| 193 | +let label=document.createElement("span") |
| 194 | +label.innerHTML=`<span class="key">${key}</span>: ` |
| 195 | + |
| 196 | +container.appendChild(label) |
| 197 | + |
| 198 | + |
| 199 | +if(type==="object"||type==="array"){ |
| 200 | + |
| 201 | +let toggle=document.createElement("span") |
| 202 | +toggle.className="toggle" |
| 203 | +toggle.innerHTML="▶" |
| 204 | + |
| 205 | +label.prepend(toggle) |
| 206 | + |
| 207 | +let child=document.createElement("div") |
| 208 | +child.style.display="none" |
| 209 | + |
| 210 | +toggle.onclick=()=>{ |
| 211 | +child.style.display=child.style.display==="none"?"block":"none" |
| 212 | +toggle.innerHTML=child.style.display==="none"?"▶":"▼" |
| 213 | +} |
| 214 | + |
| 215 | +let entries= type==="array"?val:Object.entries(val) |
| 216 | + |
| 217 | +if(type==="array"){ |
| 218 | +val.forEach((v,i)=>{ |
| 219 | +child.appendChild(createNode(i,v,path+"."+i)) |
| 220 | +}) |
| 221 | +} |
| 222 | +else{ |
| 223 | +entries.forEach(([k,v])=>{ |
| 224 | +child.appendChild(createNode(k,v,path+"."+k)) |
| 225 | +}) |
| 226 | +} |
| 227 | + |
| 228 | +container.appendChild(child) |
| 229 | + |
| 230 | +}else{ |
| 231 | + |
| 232 | +let value=document.createElement("span") |
| 233 | + |
| 234 | +value.className=type |
| 235 | + |
| 236 | +value.textContent=JSON.stringify(val) |
| 237 | + |
| 238 | +container.appendChild(value) |
| 239 | + |
| 240 | +} |
| 241 | + |
| 242 | +return container |
| 243 | + |
| 244 | +} |
| 245 | + |
| 246 | + |
| 247 | + |
| 248 | +function renderJSON(){ |
| 249 | + |
| 250 | +let input=document.getElementById("jsonInput").value |
| 251 | + |
| 252 | +try{ |
| 253 | + |
| 254 | +let json=JSON.parse(input) |
| 255 | + |
| 256 | +let viewer=document.getElementById("viewer") |
| 257 | + |
| 258 | +viewer.innerHTML="" |
| 259 | + |
| 260 | +viewer.appendChild(createNode("root",json,"root")) |
| 261 | + |
| 262 | +}catch(e){ |
| 263 | + |
| 264 | +alert("Invalid JSON") |
| 265 | + |
| 266 | +} |
| 267 | + |
| 268 | +} |
| 269 | + |
| 270 | + |
| 271 | + |
| 272 | +function generateSchema(){ |
| 273 | + |
| 274 | +let input=document.getElementById("jsonInput").value |
| 275 | + |
| 276 | +let json |
| 277 | + |
| 278 | +try{ |
| 279 | + |
| 280 | +json=JSON.parse(input) |
| 281 | + |
| 282 | +}catch{ |
| 283 | + |
| 284 | +alert("Invalid JSON") |
| 285 | + |
| 286 | +return |
| 287 | + |
| 288 | +} |
| 289 | + |
| 290 | +let rows=[] |
| 291 | + |
| 292 | +function walk(obj,path){ |
| 293 | + |
| 294 | +let type=getType(obj) |
| 295 | + |
| 296 | +rows.push({ |
| 297 | +path:path, |
| 298 | +type:type |
| 299 | +}) |
| 300 | + |
| 301 | +if(type==="object"){ |
| 302 | + |
| 303 | +Object.entries(obj).forEach(([k,v])=>{ |
| 304 | +walk(v,path+"."+k) |
| 305 | +}) |
| 306 | + |
| 307 | +} |
| 308 | + |
| 309 | +if(type==="array" && obj.length>0){ |
| 310 | + |
| 311 | +walk(obj[0],path+"[]") |
| 312 | + |
| 313 | +} |
| 314 | + |
| 315 | +} |
| 316 | + |
| 317 | +walk(json,"root") |
| 318 | + |
| 319 | +let html=`<table> |
| 320 | +<tr> |
| 321 | +<th>Path</th> |
| 322 | +<th>Type</th> |
| 323 | +</tr>` |
| 324 | + |
| 325 | +rows.forEach(r=>{ |
| 326 | +html+=`<tr> |
| 327 | +<td class="path">${r.path}</td> |
| 328 | +<td>${r.type}</td> |
| 329 | +</tr>` |
| 330 | +}) |
| 331 | + |
| 332 | +html+="</table>" |
| 333 | + |
| 334 | +document.getElementById("schema").innerHTML=html |
| 335 | + |
| 336 | +} |
| 337 | + |
| 338 | +</script> |
| 339 | + |
| 340 | +</body> |
| 341 | +</html> |
0 commit comments