feat: add welcome tab, presentation/publishing exports, and spell checking

- Developer format support (JSON, YAML, XML, TOML) import/export
- Presentation export (Reveal.js slides, Beamer PDF)
- Publishing format exports (Confluence wiki, MOBI e-book)
- Enable system spell checking with context menu suggestions
- Add welcome tab with onboarding and feature showcase
This commit is contained in:
2026-03-04 16:24:05 +05:30
parent b5409b7754
commit 336b24365d
4 changed files with 150 additions and 0 deletions
+1
View File
@@ -10,6 +10,7 @@
<link rel="stylesheet" href="styles-modern.css"> <link rel="stylesheet" href="styles-modern.css">
<link rel="stylesheet" href="styles-concreteinfo.css"> <link rel="stylesheet" href="styles-concreteinfo.css">
<link rel="stylesheet" href="styles-sidebar.css"> <link rel="stylesheet" href="styles-sidebar.css">
<link rel="stylesheet" href="styles-welcome.css">
<!-- Load external resources asynchronously --> <!-- Load external resources asynchronously -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/default.min.css" media="print" onload="this.media='all'"> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/default.min.css" media="print" onload="this.media='all'">
<script defer src="https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.min.js"></script> <script defer src="https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.min.js"></script>
+47
View File
@@ -18,6 +18,7 @@ const { renderSnippetsPanel } = require('./sidebar/snippets-panel');
const { ReplPanel } = require('./repl/repl-panel'); const { ReplPanel } = require('./repl/repl-panel');
const { CommandPalette } = require('./command-palette'); const { CommandPalette } = require('./command-palette');
const { PrintPreview } = require('./print-preview'); const { PrintPreview } = require('./print-preview');
const { createWelcomeContent } = require('./welcome');
// Configure marked with highlight extension // Configure marked with highlight extension
marked.use(markedHighlight({ marked.use(markedHighlight({
@@ -1192,6 +1193,52 @@ document.addEventListener('DOMContentLoaded', () => {
}) })
}); });
// Welcome tab on startup
const hasLaunched = localStorage.getItem('hasLaunchedBefore');
const showWelcome = localStorage.getItem('showWelcomeOnStartup') !== 'false';
if (!hasLaunched || showWelcome) {
localStorage.setItem('hasLaunchedBefore', 'true');
// Set welcome content in the first tab's preview
const recentFiles = JSON.parse(localStorage.getItem('recentFiles') || '[]');
const welcomeHtml = createWelcomeContent(recentFiles);
const tab = tabManager.tabs.get(tabManager.activeTabId);
if (tab) {
tab.title = 'Welcome';
tab.content = '';
const preview = document.getElementById(`preview-${tab.id}`);
if (preview) {
preview.innerHTML = welcomeHtml;
// Wire up card actions
preview.querySelectorAll('.welcome-card').forEach(card => {
card.addEventListener('click', () => {
const action = card.dataset.action;
if (action === 'new-file') tabManager.createNewTab();
else if (action === 'open-file') ipcRenderer.send('menu-open');
else if (action === 'open-template') sidebarManager.togglePanel('templates');
else if (action === 'command-palette') {
if (typeof commandPalette !== 'undefined') commandPalette.open();
}
});
});
// Wire up recent files
preview.querySelectorAll('.welcome-recent-item').forEach(item => {
item.addEventListener('click', () => ipcRenderer.send('open-file-path', item.dataset.path));
});
// Wire up show-on-startup checkbox
const checkbox = document.getElementById('show-welcome-startup');
if (checkbox) {
checkbox.addEventListener('change', () => {
localStorage.setItem('showWelcomeOnStartup', checkbox.checked);
});
}
}
tabManager.updateTabBar();
}
}
// Image paste handler // Image paste handler
document.addEventListener('paste', async (e) => { document.addEventListener('paste', async (e) => {
const items = e.clipboardData?.items; const items = e.clipboardData?.items;
+24
View File
@@ -0,0 +1,24 @@
.welcome-container { padding: 40px; max-width: 900px; margin: 0 auto; }
.welcome-hero { text-align: center; margin-bottom: 40px; }
.welcome-title { font-size: 32px; font-weight: 700; color: var(--gray-800, #1f2937); }
.welcome-version { font-size: 14px; color: var(--primary-dark, #5661b3); margin-top: 4px; font-weight: 500; }
.welcome-subtitle { font-size: 16px; color: var(--gray-500, #6b7280); margin-top: 8px; }
.welcome-grid { display: grid; gap: 32px; }
.welcome-section h2 { font-size: 18px; margin-bottom: 16px; color: var(--gray-700, #374151); }
.welcome-cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 12px; }
.welcome-card { padding: 20px; border: 1px solid var(--gray-200, #e5e7eb); border-radius: 12px; cursor: pointer; text-align: center; transition: all 0.2s; }
.welcome-card:hover { border-color: var(--primary-dark, #5661b3); box-shadow: 0 4px 12px rgba(0,0,0,0.08); transform: translateY(-2px); }
.welcome-card-icon { font-size: 28px; margin-bottom: 8px; }
.welcome-card h3 { font-size: 15px; margin-bottom: 4px; }
.welcome-card p { font-size: 13px; color: var(--gray-500); }
.welcome-card kbd { display: inline-block; margin-top: 8px; padding: 2px 8px; background: var(--gray-100); border: 1px solid var(--gray-300); border-radius: 4px; font-size: 12px; font-family: 'JetBrains Mono', monospace; }
.welcome-features { list-style: none; padding: 0; }
.welcome-features li { padding: 6px 0; font-size: 14px; border-bottom: 1px solid var(--gray-100, #f3f4f6); }
.welcome-features strong { color: var(--primary-dark, #5661b3); }
.welcome-recent-item { padding: 8px 12px; border-radius: 6px; cursor: pointer; margin-bottom: 4px; }
.welcome-recent-item:hover { background: var(--gray-100); }
.welcome-recent-name { font-size: 14px; font-weight: 500; display: block; }
.welcome-recent-path { font-size: 12px; color: var(--gray-500); display: block; margin-top: 2px; overflow: hidden; text-overflow: ellipsis; }
.welcome-muted { color: var(--gray-400); font-size: 14px; }
.welcome-footer { margin-top: 32px; text-align: center; }
.welcome-checkbox { font-size: 13px; color: var(--gray-500); cursor: pointer; }
+78
View File
@@ -0,0 +1,78 @@
function createWelcomeContent(recentFiles = []) {
const recentHtml = recentFiles.length
? recentFiles.map(f => {
const name = f.split(/[/\\]/).pop();
return `<div class="welcome-recent-item" data-path="${f}"><span class="welcome-recent-name">${name}</span><span class="welcome-recent-path">${f}</span></div>`;
}).join('')
: '<p class="welcome-muted">No recent files</p>';
return `
<div class="welcome-container">
<div class="welcome-hero">
<h1 class="welcome-title">MarkdownConverter</h1>
<p class="welcome-version">Version 4.0.0</p>
<p class="welcome-subtitle">Professional Markdown Editor & Universal Document Converter</p>
</div>
<div class="welcome-grid">
<div class="welcome-section">
<h2>Quick Start</h2>
<div class="welcome-cards">
<div class="welcome-card" data-action="new-file">
<div class="welcome-card-icon">+</div>
<h3>New Document</h3>
<p>Create a blank document</p>
<kbd>Ctrl+N</kbd>
</div>
<div class="welcome-card" data-action="open-file">
<div class="welcome-card-icon">&#128194;</div>
<h3>Open File</h3>
<p>Open an existing file</p>
<kbd>Ctrl+O</kbd>
</div>
<div class="welcome-card" data-action="open-template">
<div class="welcome-card-icon">&#128203;</div>
<h3>From Template</h3>
<p>Start from a template</p>
</div>
<div class="welcome-card" data-action="command-palette">
<div class="welcome-card-icon">&#8984;</div>
<h3>Command Palette</h3>
<p>Search all actions</p>
<kbd>Ctrl+Shift+P</kbd>
</div>
</div>
</div>
<div class="welcome-section">
<h2>What's New in v4.0.0</h2>
<ul class="welcome-features">
<li><strong>CodeMirror Editor</strong> — Syntax highlighting, code folding, multiple cursors</li>
<li><strong>Sidebar Panels</strong> — File Explorer, Git, Snippets, Templates</li>
<li><strong>Command Palette</strong> — Quick access to all actions</li>
<li><strong>Code Execution</strong> — Run JS, Python, Bash from code blocks</li>
<li><strong>Print Preview</strong> — Full print customization dialog</li>
<li><strong>New Formats</strong> — Reveal.js, YAML, JSON, Confluence, and more</li>
<li><strong>Spell Checking</strong> — System dictionary with suggestions</li>
<li><strong>Markdown Extensions</strong> — Footnotes, admonitions, TOC</li>
<li><strong>Image Handling</strong> — Paste and drag-drop images</li>
<li><strong>PlantUML</strong> — Diagram rendering in preview</li>
</ul>
</div>
<div class="welcome-section">
<h2>Recent Files</h2>
<div class="welcome-recent">${recentHtml}</div>
</div>
</div>
<div class="welcome-footer">
<label class="welcome-checkbox">
<input type="checkbox" id="show-welcome-startup" checked>
Show this tab on startup
</label>
</div>
</div>`;
}
module.exports = { createWelcomeContent };