Spaces:
Running
Running
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>JSON Markdown Renderer</title> | |
| <script src="https://cdn.tailwindcss.com"></script> | |
| <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/styles/github.min.css"> | |
| <script src="https://unpkg.com/highlight.js@11.7.0/lib/core.min.js"></script> | |
| <script src="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/js/all.min.js"></script> | |
| <script src="https://cdnjs.cloudflare.com/ajax/libs/showdown/2.1.0/showdown.min.js"></script> | |
| <style> | |
| .markdown-body { | |
| box-sizing: border-box; | |
| min-width: 200px; | |
| max-width: 980px; | |
| margin: 0 auto; | |
| padding: 45px; | |
| } | |
| @media (max-width: 767px) { | |
| .markdown-body { | |
| padding: 15px; | |
| } | |
| } | |
| .hidden { | |
| display: none; | |
| } | |
| .dropzone { | |
| border: 2px dashed #6b7280; | |
| transition: all 0.3s ease; | |
| } | |
| .dropzone.active { | |
| border-color: #3b82f6; | |
| background-color: rgba(59, 130, 246, 0.05); | |
| } | |
| pre { | |
| border-radius: 6px; | |
| overflow-x: auto; | |
| padding: 16px; | |
| background-color: #f6f8fa; | |
| } | |
| code { | |
| font-family: ui-monospace, SFMono-Regular, SF Mono, Menlo, Consolas, Liberation Mono, monospace; | |
| } | |
| </style> | |
| </head> | |
| <body class="bg-gray-50 min-h-screen"> | |
| <div class="container mx-auto px-4 py-8"> | |
| <div class="max-w-4xl mx-auto"> | |
| <header class="text-center mb-10"> | |
| <h1 class="text-3xl font-bold text-gray-800 mb-2">JSON Markdown Renderer</h1> | |
| <p class="text-gray-600">Upload a JSON file containing markdown content and see it rendered beautifully</p> | |
| </header> | |
| <div class="bg-white rounded-xl shadow-md overflow-hidden mb-8 transition-all duration-300"> | |
| <div id="upload-container" class="p-8"> | |
| <div id="dropzone" class="dropzone rounded-lg p-12 text-center cursor-pointer mb-6"> | |
| <div class="mx-auto w-16 h-16 text-blue-500 mb-4"> | |
| <i class="fas fa-cloud-upload-alt text-5xl"></i> | |
| </div> | |
| <h3 class="text-lg font-medium text-gray-700 mb-1">Drag & drop your JSON file here</h3> | |
| <p class="text-sm text-gray-500 mb-4">or</p> | |
| <label for="file-upload" class="px-4 py-2 bg-blue-500 text-white rounded-md hover:bg-blue-600 transition-colors cursor-pointer"> | |
| <span class="font-medium">Browse Files</span> | |
| <input id="file-upload" type="file" accept=".json,application/json" class="hidden"> | |
| </label> | |
| <p class="text-xs text-gray-500 mt-4">Supports single JSON file with markdown content</p> | |
| </div> | |
| <div class="text-center"> | |
| <p class="text-gray-500 mb-2">Don't have a JSON file? Try with our sample:</p> | |
| <button id="sample-btn" class="px-4 py-2 bg-gray-200 text-gray-700 rounded-md hover:bg-gray-300 transition-colors"> | |
| <i class="fas fa-file-alt mr-2"></i> Load Sample JSON | |
| </button> | |
| </div> | |
| </div> | |
| <div id="error-container" class="hidden p-4 bg-red-50 text-red-700 rounded-md mb-4"> | |
| <div class="flex items-center"> | |
| <i class="fas fa-exclamation-circle mr-2"></i> | |
| <span id="error-message"></span> | |
| </div> | |
| </div> | |
| </div> | |
| <div id="result-container" class="hidden bg-white rounded-xl shadow-md overflow-hidden transition-all duration-300"> | |
| <div class="border-b border-gray-200 px-6 py-4 flex justify-between items-center bg-gray-50"> | |
| <h2 class="text-lg font-medium text-gray-800">Rendered Markdown</h2> | |
| <button id="back-btn" class="px-3 py-1 bg-gray-200 text-gray-700 rounded-md text-sm hover:bg-gray-300 transition-colors"> | |
| <i class="fas fa-arrow-left mr-1"></i> Back | |
| </button> | |
| </div> | |
| <div id="markdown-content" class="markdown-body p-6"> | |
| <!-- Markdown content will be rendered here --> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <script> | |
| document.addEventListener('DOMContentLoaded', function() { | |
| // Get DOM elements | |
| const dropzone = document.getElementById('dropzone'); | |
| const fileUpload = document.getElementById('file-upload'); | |
| const uploadContainer = document.getElementById('upload-container'); | |
| const resultContainer = document.getElementById('result-container'); | |
| const markdownContent = document.getElementById('markdown-content'); | |
| const backBtn = document.getElementById('back-btn'); | |
| const sampleBtn = document.getElementById('sample-btn'); | |
| const errorContainer = document.getElementById('error-container'); | |
| const errorMessage = document.getElementById('error-message'); | |
| // Handle drag and drop events | |
| ['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => { | |
| dropzone.addEventListener(eventName, preventDefaults, false); | |
| }); | |
| function preventDefaults(e) { | |
| e.preventDefault(); | |
| e.stopPropagation(); | |
| } | |
| ['dragenter', 'dragover'].forEach(eventName => { | |
| dropzone.addEventListener(eventName, highlight, false); | |
| }); | |
| ['dragleave', 'drop'].forEach(eventName => { | |
| dropzone.addEventListener(eventName, unhighlight, false); | |
| }); | |
| function highlight() { | |
| dropzone.classList.add('active'); | |
| } | |
| function unhighlight() { | |
| dropzone.classList.remove('active'); | |
| } | |
| // Handle file drop | |
| dropzone.addEventListener('drop', handleDrop, false); | |
| function handleDrop(e) { | |
| const dt = e.dataTransfer; | |
| const files = dt.files; | |
| if (files.length > 0) { | |
| handleFiles(files); | |
| } | |
| } | |
| // Handle file selection via input | |
| fileUpload.addEventListener('change', function() { | |
| if (this.files.length > 0) { | |
| handleFiles(this.files); | |
| } | |
| }); | |
| // Handle back button | |
| backBtn.addEventListener('click', function() { | |
| resultContainer.classList.add('hidden'); | |
| uploadContainer.classList.remove('hidden'); | |
| markdownContent.innerHTML = ''; | |
| fileUpload.value = ''; | |
| }); | |
| // Handle sample button | |
| sampleBtn.addEventListener('click', renderSample); | |
| // Process uploaded files | |
| function handleFiles(files) { | |
| const file = files[0]; | |
| if (file.type !== 'application/json' && !file.name.endsWith('.json')) { | |
| showError('Please upload a valid JSON file.'); | |
| return; | |
| } | |
| const reader = new FileReader(); | |
| reader.onload = function(e) { | |
| try { | |
| const jsonData = JSON.parse(e.target.result); | |
| processJsonData(jsonData); | |
| } catch (error) { | |
| showError('Invalid JSON content: ' + error.message); | |
| } | |
| }; | |
| reader.onerror = function() { | |
| showError('Error reading the file.'); | |
| }; | |
| reader.readAsText(file); | |
| } | |
| // Process JSON data and render markdown | |
| function processJsonData(jsonData) { | |
| hideError(); | |
| // Find the first markdown string in the JSON | |
| let markdownText = findFirstMarkdownString(jsonData); | |
| if (!markdownText) { | |
| showError('No markdown content found in the JSON file.'); | |
| return; | |
| } | |
| // Show loading state | |
| markdownContent.innerHTML = '<div class="text-center py-8"><i class="fas fa-spinner fa-spin text-3xl text-blue-500"></i><p class="mt-4 text-gray-600">Rendering markdown...</p></div>'; | |
| // Process markdown with Showdown.js | |
| const converter = new showdown.Converter(); | |
| const html = converter.makeHtml(markdownText); | |
| markdownContent.innerHTML = html; | |
| // Switch to result view | |
| uploadContainer.classList.add('hidden'); | |
| resultContainer.classList.remove('hidden'); | |
| } | |
| // Recursively find the first string that looks like markdown | |
| function findFirstMarkdownString(obj) { | |
| if (typeof obj === 'string') { | |
| // Check if this looks like markdown | |
| if (obj.includes('##') || obj.includes('*') || obj.includes('`') || obj.includes('![')) { | |
| return obj; | |
| } | |
| } else if (Array.isArray(obj)) { | |
| for (let item of obj) { | |
| const result = findFirstMarkdownString(item); | |
| if (result) return result; | |
| } | |
| } else if (typeof obj === 'object' && obj !== null) { | |
| for (let key in obj) { | |
| const result = findFirstMarkdownString(obj[key]); | |
| if (result) return result; | |
| } | |
| } | |
| return null; | |
| } | |
| // Display sample markdown | |
| function renderSample() { | |
| const sampleJson = { | |
| "document": { | |
| "title": "Sample Markdown", | |
| "content": `# Welcome to JSON Markdown Renderer | |
| This is a **sample markdown** content rendered from JSON. | |
| ## Features | |
| - Render markdown from JSON files | |
| - Drag and drop interface | |
| - Syntax highlighting for code blocks | |
| - Mobile responsive design | |
| ### Code Example | |
| \`\`\`javascript | |
| function greet(name) { | |
| return 'Hello, ' + name + '!'; | |
| } | |
| console.log(greet('World')); | |
| \`\`\` | |
| ## Usage | |
| 1. Upload a JSON file containing markdown content | |
| 2. The system will extract and render the markdown | |
| 3. Enjoy beautifully formatted content! | |
| [Learn more about Markdown](https://www.markdownguide.org)`, | |
| "metadata": { | |
| "author": "John Doe", | |
| "created": "2023-06-01" | |
| } | |
| } | |
| }; | |
| processJsonData(sampleJson); | |
| } | |
| // Show error message | |
| function showError(message) { | |
| errorMessage.textContent = message; | |
| errorContainer.classList.remove('hidden'); | |
| } | |
| // Hide error message | |
| function hideError() { | |
| errorContainer.classList.add('hidden'); | |
| } | |
| }); | |
| </script> | |
| <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=tatht/render-markdown" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body> | |
| </html> |