diff --git a/simple-markdown-render/index.html b/simple-markdown-render/index.html index 38c11b7..20b37bf 100644 --- a/simple-markdown-render/index.html +++ b/simple-markdown-render/index.html @@ -3,7 +3,7 @@ - Markdown Renderer + Markdown Render
-

Markdown Renderer

+

Markdown Render + +

Enter a URL or drop a markdown file

+
+
+

Render History

+
+ +
+
+
+
+
@@ -372,8 +512,14 @@ const copyMdBtn = document.getElementById('copyMdBtn'); const rawBtn = document.getElementById('rawBtn'); const toast = document.getElementById('toast'); + const historyToggle = document.getElementById('historyToggle'); + const historyPanel = document.getElementById('historyPanel'); + const historyList = document.getElementById('historyList'); + const clearHistory = document.getElementById('clearHistory'); let currentRawText = ''; + const HISTORY_KEY = 'markdown_render_history'; + const MAX_HISTORY = 50; // Extension system: loaders registry // Loaders are functions that take a URL/source and return text content. @@ -426,6 +572,7 @@ renderedContent.innerHTML = html; sourceLabel.textContent = source || 'Dropped file'; renderOutput.classList.add('visible'); + addToHistory(source || 'Dropped file', text); } function showToast(message) { @@ -517,6 +664,106 @@ window.open(url, '_blank'); }); + // --- History --- + function getHistory() { + try { + return JSON.parse(localStorage.getItem(HISTORY_KEY) || '[]'); + } catch { + return []; + } + } + + function saveHistory(items) { + localStorage.setItem(HISTORY_KEY, JSON.stringify(items)); + } + + function addToHistory(source, text) { + const items = getHistory(); + // Remove existing entry with same source to avoid duplicates + const existing = items.findIndex(i => i.source === source); + if (existing !== -1) items.splice(existing, 1); + items.unshift({ + source, + text, + time: new Date().toISOString() + }); + if (items.length > MAX_HISTORY) items.length = MAX_HISTORY; + saveHistory(items); + renderHistory(); + } + + function deleteHistoryItem(index) { + const items = getHistory(); + items.splice(index, 1); + saveHistory(items); + renderHistory(); + } + + function clearAllHistory() { + localStorage.removeItem(HISTORY_KEY); + renderHistory(); + } + + function formatTime(iso) { + const d = new Date(iso); + const now = new Date(); + const diff = now - d; + if (diff < 60000) return 'Just now'; + if (diff < 3600000) return Math.floor(diff / 60000) + 'm ago'; + if (diff < 86400000) return Math.floor(diff / 3600000) + 'h ago'; + return d.toLocaleDateString(); + } + + function renderHistory() { + const items = getHistory(); + if (items.length === 0) { + historyList.innerHTML = '
No render history yet
'; + return; + } + historyList.innerHTML = items.map((item, i) => ` +
+
+
${escapeHtml(item.source)}
+
${formatTime(item.time)}
+
+ +
+ `).join(''); + } + + function escapeHtml(str) { + return str.replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"'); + } + + historyList.addEventListener('click', (e) => { + const deleteBtn = e.target.closest('.history-item-delete'); + if (deleteBtn) { + e.stopPropagation(); + deleteHistoryItem(parseInt(deleteBtn.dataset.index)); + return; + } + const item = e.target.closest('.history-item'); + if (item) { + const idx = parseInt(item.dataset.index); + const entry = getHistory()[idx]; + if (entry) { + hideError(); + renderMarkdown(entry.text, entry.source); + } + } + }); + + historyToggle.addEventListener('click', () => { + historyPanel.classList.toggle('visible'); + renderHistory(); + }); + + clearHistory.addEventListener('click', () => { + clearAllHistory(); + }); + + renderHistory(); + // Handle URL parameter: ?url=... const params = new URLSearchParams(window.location.search); const urlParam = params.get('url');