|
| 1 | +<!DOCTYPE html> |
| 2 | +<html lang="en"> |
| 3 | +<head> |
| 4 | + <script>fetch('https://api.countapi.xyz/hit/rmkr-dev.github.io/transform');</script> |
| 5 | + <meta charset="UTF-8"> |
| 6 | + <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| 7 | + <title>Payload Knife | RMKR Dev</title> |
| 8 | + |
| 9 | + <script src="https://cdn.tailwindcss.com"></script> |
| 10 | + <link href="https://fonts.googleapis.com/css2?family=Inter:wght@100..900&family=Fira+Code:wght@300..700&display=swap" rel="stylesheet"> |
| 11 | + <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/css/all.min.css" /> |
| 12 | + |
| 13 | + <style> |
| 14 | + :root { |
| 15 | + --color-bg: #0C1524; --color-card: #18233C; |
| 16 | + --color-accent: #FFC300; --color-text: #F0F4F8; |
| 17 | + --color-muted: #A0AEC0; --color-line: #2D3748; |
| 18 | + } |
| 19 | + body { font-family: 'Inter', sans-serif; background-color: var(--color-bg); color: var(--color-text); } |
| 20 | + .wrap { max-width: 1200px; margin: 0 auto; padding: 2rem; } |
| 21 | + |
| 22 | + textarea { |
| 23 | + font-family: 'Fira Code', monospace; |
| 24 | + background: #080E1A !important; |
| 25 | + color: #4ade80 !important; |
| 26 | + border: 1px solid var(--color-line); |
| 27 | + resize: none; outline: none; |
| 28 | + } |
| 29 | + |
| 30 | + .action-btn { |
| 31 | + background: var(--color-card); |
| 32 | + border: 1px solid var(--color-line); |
| 33 | + padding: 8px 12px; |
| 34 | + border-radius: 8px; |
| 35 | + font-size: 0.7rem; |
| 36 | + font-weight: 800; |
| 37 | + color: var(--color-muted); |
| 38 | + transition: all 0.2s; |
| 39 | + text-transform: uppercase; |
| 40 | + } |
| 41 | + .action-btn:hover { border-color: var(--color-accent); color: var(--color-accent); } |
| 42 | + .action-btn.active { background: var(--color-accent); color: var(--color-bg); border-color: var(--color-accent); } |
| 43 | + </style> |
| 44 | +</head> |
| 45 | +<body> |
| 46 | + |
| 47 | +<div class="wrap"> |
| 48 | + <header class="flex justify-between items-center mb-8 border-b border-[--color-line] pb-4"> |
| 49 | + <div> |
| 50 | + <h1 class="text-2xl font-bold italic tracking-tighter">PAYLOAD<span class="text-[--color-accent] not-italic">KNIFE</span></h1> |
| 51 | + <p class="text-xs text-[--color-muted] font-bold uppercase tracking-widest mt-1">Data Transformation Suite</p> |
| 52 | + </div> |
| 53 | + <a href="../" class="bg-[--color-card] p-3 rounded-xl border border-[--color-line] hover:border-[--color-accent] transition"> |
| 54 | + <i class="fa-solid fa-house-user"></i> |
| 55 | + </a> |
| 56 | + </header> |
| 57 | + |
| 58 | + <div class="flex flex-wrap gap-2 mb-6 bg-[--color-card] p-3 rounded-xl border border-[--color-line]"> |
| 59 | + <button onclick="transform('prettify')" class="action-btn">Prettify JSON</button> |
| 60 | + <button onclick="transform('minify')" class="action-btn">Minify JSON</button> |
| 61 | + <button onclick="transform('csv')" class="action-btn">JSON to CSV</button> |
| 62 | + <button onclick="transform('curl')" class="action-btn">CURL to Fetch</button> |
| 63 | + <div class="ml-auto flex gap-2"> |
| 64 | + <button onclick="copyOutput()" class="text-[--color-accent] text-xs font-bold uppercase px-3">Copy Result</button> |
| 65 | + <button onclick="clearAll()" class="text-red-400 text-xs font-bold uppercase px-3">Clear</button> |
| 66 | + </div> |
| 67 | + </div> |
| 68 | + |
| 69 | + <div class="grid grid-cols-1 lg:grid-cols-2 gap-6 h-[60vh]"> |
| 70 | + <div class="flex flex-col"> |
| 71 | + <label class="text-[10px] font-black text-[--color-muted] uppercase mb-2 ml-1">Input Raw Data</label> |
| 72 | + <textarea id="input" class="w-full h-full p-4 rounded-xl text-xs leading-relaxed" placeholder='Paste JSON, CURL, or CSV here...'></textarea> |
| 73 | + </div> |
| 74 | + <div class="flex flex-col"> |
| 75 | + <label class="text-[10px] font-black text-[--color-muted] uppercase mb-2 ml-1">Processed Output</label> |
| 76 | + <textarea id="output" class="w-full h-full p-4 rounded-xl text-xs leading-relaxed" readonly placeholder="Result will appear here..."></textarea> |
| 77 | + </div> |
| 78 | + </div> |
| 79 | +</div> |
| 80 | + |
| 81 | +<script> |
| 82 | + const inputArea = document.getElementById('input'); |
| 83 | + const outputArea = document.getElementById('output'); |
| 84 | + |
| 85 | + function transform(type) { |
| 86 | + const val = inputArea.value.trim(); |
| 87 | + if (!val) return; |
| 88 | + |
| 89 | + try { |
| 90 | + if (type === 'prettify') { |
| 91 | + outputArea.value = JSON.stringify(JSON.parse(val), null, 4); |
| 92 | + } |
| 93 | + else if (type === 'minify') { |
| 94 | + outputArea.value = JSON.stringify(JSON.parse(val)); |
| 95 | + } |
| 96 | + else if (type === 'csv') { |
| 97 | + const arr = JSON.parse(val); |
| 98 | + const items = Array.isArray(arr) ? arr : [arr]; |
| 99 | + const replacer = (key, value) => value === null ? '' : value; |
| 100 | + const header = Object.keys(items[0]); |
| 101 | + const csv = [ |
| 102 | + header.join(','), |
| 103 | + ...items.map(row => header.map(fieldName => JSON.stringify(row[fieldName], replacer)).join(',')) |
| 104 | + ].join('\r\n'); |
| 105 | + outputArea.value = csv; |
| 106 | + } |
| 107 | + else if (type === 'curl') { |
| 108 | + outputArea.value = curlToFetch(val); |
| 109 | + } |
| 110 | + } catch (e) { |
| 111 | + outputArea.value = "ERROR: " + e.message; |
| 112 | + } |
| 113 | + } |
| 114 | + |
| 115 | + function curlToFetch(curl) { |
| 116 | + const urlMatch = curl.match(/curl\s+'?([^'\s]+)'?/); |
| 117 | + if (!urlMatch) return "Invalid CURL command"; |
| 118 | + |
| 119 | + let url = urlMatch[1]; |
| 120 | + let headers = {}; |
| 121 | + let method = 'GET'; |
| 122 | + let body = null; |
| 123 | + |
| 124 | + if (curl.includes('-X POST')) method = 'POST'; |
| 125 | + if (curl.includes('-X PUT')) method = 'PUT'; |
| 126 | + |
| 127 | + const headerMatches = curl.matchAll(/-H\s+'([^']+)'/g); |
| 128 | + for (const match of headerMatches) { |
| 129 | + const [key, value] = match[1].split(': '); |
| 130 | + headers[key] = value; |
| 131 | + } |
| 132 | + |
| 133 | + const dataMatch = curl.match(/--data(-raw)?\s+'([^']+)'/); |
| 134 | + if (dataMatch) body = dataMatch[2]; |
| 135 | + |
| 136 | + return `fetch("${url}", { |
| 137 | + method: "${method}", |
| 138 | + headers: ${JSON.stringify(headers, null, 8)}, |
| 139 | + ${body ? `body: JSON.stringify(${body})` : ''} |
| 140 | +}) |
| 141 | +.then(res => res.json()) |
| 142 | +.then(console.log);`; |
| 143 | + } |
| 144 | + |
| 145 | + function copyOutput() { |
| 146 | + outputArea.select(); |
| 147 | + document.execCommand('copy'); |
| 148 | + } |
| 149 | + |
| 150 | + function clearAll() { |
| 151 | + inputArea.value = ''; |
| 152 | + outputArea.value = ''; |
| 153 | + } |
| 154 | +</script> |
| 155 | +</body> |
| 156 | +</html> |
0 commit comments