mirror of
https://github.com/amitwh/markdown-converter.git
synced 2026-08-02 18:10:18 +05:30
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a44b13d2fb | ||
|
|
015446bff3 | ||
|
|
9f15a02511 | ||
|
|
9799b95cea | ||
|
|
83150eea88 |
@@ -4,7 +4,7 @@
|
||||
|
||||
**PanConverter** is a cross-platform Markdown editor and converter powered by Pandoc, built with Electron. It provides professional-grade editing capabilities with comprehensive export options.
|
||||
|
||||
**Current Version**: v1.6.1
|
||||
**Current Version**: v1.7.2
|
||||
**Author**: Amit Haridas (amit.wh@gmail.com)
|
||||
**License**: MIT
|
||||
**Repository**: https://github.com/amitwh/pan-converter
|
||||
@@ -23,10 +23,11 @@
|
||||
### Application Structure
|
||||
```
|
||||
src/
|
||||
├── main.js # Electron main process, menu system, IPC handlers
|
||||
├── renderer.js # TabManager class, multi-file editing, event handling
|
||||
├── index.html # Application layout with tabbed interface
|
||||
└── styles.css # Comprehensive styling with multi-theme support
|
||||
├── main.js # Electron main process, menu system, IPC handlers
|
||||
├── renderer.js # TabManager class, multi-file editing, event handling
|
||||
├── index.html # Application layout with tabbed interface
|
||||
├── styles.css # Base styling with multi-theme support
|
||||
└── styles-modern.css # Modern glassmorphism UI design system (v1.7.1)
|
||||
|
||||
assets/
|
||||
└── icon.png # Application icon
|
||||
@@ -110,7 +111,73 @@ gh release create v1.2.1 --title "Title" --notes "Release notes" \
|
||||
|
||||
## Feature Implementation Guide
|
||||
|
||||
### v1.7.0 PDF Editor & Universal Converter (Latest)
|
||||
### v1.7.2 Enhanced Themes & Bug Fixes (Latest)
|
||||
|
||||
#### 🎨 14 New Beautiful Themes
|
||||
**Expanded Theme Collection** (`src/main.js:242-266`, `src/styles.css:1590-2555`)
|
||||
- **Added 14 new professionally-designed themes** bringing the total to 19 themes
|
||||
- **New Themes Include**:
|
||||
- **Dracula** - Popular purple and pink dark theme
|
||||
- **Nord** - Arctic-inspired blue theme
|
||||
- **One Dark** - Atom's iconic dark theme
|
||||
- **Atom One Light** - Clean, bright light theme
|
||||
- **Material** - Google Material Design inspired
|
||||
- **Gruvbox Dark** - Warm retro groove colors (dark)
|
||||
- **Gruvbox Light** - Warm retro groove colors (light)
|
||||
- **Tokyo Night** - Modern Japanese-inspired dark theme
|
||||
- **Palenight** - Soft purple Material Design variant
|
||||
- **Ayu Dark** - Simple, elegant dark theme
|
||||
- **Ayu Light** - Minimalist light theme
|
||||
- **Ayu Mirage** - Balanced dark-light hybrid
|
||||
- **Oceanic Next** - Ocean-inspired teal and blue
|
||||
- **Cobalt2** - Deep blue with yellow accents
|
||||
|
||||
**Technical Implementation:**
|
||||
- Complete CSS styling for all UI elements per theme
|
||||
- Consistent theming across tabs, toolbar, editor, preview, and status bar
|
||||
- Theme-aware color schemes for syntax highlighting
|
||||
- All themes support glassmorphism effects from v1.7.1
|
||||
|
||||
#### 🐛 Undo/Redo Fix
|
||||
**Fixed Menu Integration** (`src/renderer.js:1107-1118`)
|
||||
- Fixed undo/redo menu items not connecting to custom undo/redo functionality
|
||||
- Added IPC event listeners in renderer to receive 'undo' and 'redo' messages
|
||||
- Connected Edit menu commands to TabManager's undo() and redo() methods
|
||||
- Keyboard shortcuts (Ctrl+Z, Ctrl+Shift+Z) now work correctly with custom undo stack
|
||||
|
||||
### v1.7.1 Modern UI Design
|
||||
|
||||
#### 🎨 Glassmorphism & Gradient UI
|
||||
**Modern Design System** (`src/styles-modern.css`, `src/index.html:7-11`)
|
||||
- **Glassmorphism Effects** - Translucent backgrounds with backdrop-filter blur
|
||||
- **Animated Gradient Background** - Purple-blue gradient that shifts colors dynamically
|
||||
- **CSS Custom Properties** - Centralized theming with CSS variables
|
||||
- **Modern Typography** - Inter font family for UI, JetBrains Mono for code
|
||||
- **Smooth Animations** - CSS transitions with cubic-bezier easing
|
||||
- **Enhanced Hover Effects** - Interactive elements with scale and transform effects
|
||||
- **Custom Scrollbars** - Styled scrollbars matching the modern aesthetic
|
||||
- **Progress Bars** - Shimmer animations and gradient fills
|
||||
|
||||
**Design Features:**
|
||||
- Animated gradient background (15-second color shift loop)
|
||||
- Glass-effect tabs with blur and semi-transparency
|
||||
- Gradient-based buttons with hover/active states
|
||||
- Modern card-based dialogs with rounded corners
|
||||
- Enhanced typography with gradient text for headings
|
||||
- Ripple-like hover effects on interactive elements
|
||||
- Theme variables for consistent colors and spacing
|
||||
- Shadow effects with proper depth perception
|
||||
|
||||
**Technical Implementation:**
|
||||
- Created comprehensive `styles-modern.css` file (780+ lines)
|
||||
- Google Fonts integration (Inter, JetBrains Mono)
|
||||
- CSS Grid and Flexbox for modern layouts
|
||||
- backdrop-filter for glassmorphism (with fallbacks)
|
||||
- CSS animations with @keyframes
|
||||
- RGB/RGBA color system with opacity control
|
||||
- CSS custom properties for easy theming
|
||||
|
||||
### v1.7.0 PDF Editor & Universal Converter
|
||||
|
||||
#### 📄 Comprehensive PDF Editor
|
||||
**Complete PDF Manipulation Suite** (`src/main.js:1566-2068`, `src/index.html:552-921`, `src/renderer.js:1951-2429`)
|
||||
@@ -532,5 +599,5 @@ gh release create v1.2.1 --title "Title" --notes "Release notes" \
|
||||
|
||||
---
|
||||
|
||||
**Last Updated**: September 15, 2025
|
||||
**Claude Assistant**: Development completed for v1.5.0 with optional advanced export options, removed proprietary dependencies for open-source compatibility, enhanced auto-save functionality, comprehensive document statistics, recent files management, and mathematical expression support using KaTeX.
|
||||
**Last Updated**: October 11, 2025
|
||||
**Claude Assistant**: Development completed for v1.7.2 with 14 new professionally-designed themes (Dracula, Nord, Tokyo Night, Gruvbox, Ayu, Material, Oceanic Next, Palenight, Cobalt2, and more) bringing total to 19 themes, plus fixed undo/redo menu integration for proper keyboard shortcut support.
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "pan-converter",
|
||||
"version": "1.7.0",
|
||||
"version": "1.7.3",
|
||||
"description": "Cross-platform Markdown editor and converter using Pandoc",
|
||||
"main": "src/main.js",
|
||||
"scripts": {
|
||||
|
||||
@@ -4,7 +4,11 @@
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>PanConverter - Markdown Editor</title>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=JetBrains+Mono:wght@400;500;600&display=swap" rel="stylesheet">
|
||||
<link rel="stylesheet" href="styles.css">
|
||||
<link rel="stylesheet" href="styles-modern.css">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/6.65.7/codemirror.min.css">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/default.min.css">
|
||||
</head>
|
||||
|
||||
+49
-16
@@ -83,7 +83,12 @@ function createWindow() {
|
||||
mainWindow = null;
|
||||
});
|
||||
|
||||
// Handle pending file from file association will be handled by renderer-ready event
|
||||
// Wait for the page to fully load before sending file data
|
||||
mainWindow.webContents.on('did-finish-load', () => {
|
||||
console.log('Window finished loading');
|
||||
// Don't open file here - wait for renderer-ready signal
|
||||
// The renderer will send renderer-ready when TabManager is initialized
|
||||
});
|
||||
}
|
||||
|
||||
function buildRecentFilesMenu() {
|
||||
@@ -197,18 +202,26 @@ function createMenu() {
|
||||
{
|
||||
label: 'Edit',
|
||||
submenu: [
|
||||
{ label: 'Undo', accelerator: 'CmdOrCtrl+Z', role: 'undo' },
|
||||
{ label: 'Redo', accelerator: 'CmdOrCtrl+Shift+Z', role: 'redo' },
|
||||
{
|
||||
label: 'Undo',
|
||||
accelerator: 'CmdOrCtrl+Z',
|
||||
click: () => mainWindow.webContents.send('undo')
|
||||
},
|
||||
{
|
||||
label: 'Redo',
|
||||
accelerator: 'CmdOrCtrl+Shift+Z',
|
||||
click: () => mainWindow.webContents.send('redo')
|
||||
},
|
||||
{ type: 'separator' },
|
||||
{ label: 'Cut', accelerator: 'CmdOrCtrl+X', role: 'cut' },
|
||||
{ label: 'Copy', accelerator: 'CmdOrCtrl+C', role: 'copy' },
|
||||
{ label: 'Paste', accelerator: 'CmdOrCtrl+V', role: 'paste' },
|
||||
{ label: 'Select All', accelerator: 'CmdOrCtrl+A', role: 'selectAll' },
|
||||
{ type: 'separator' },
|
||||
{
|
||||
label: 'Find & Replace',
|
||||
accelerator: 'CmdOrCtrl+F',
|
||||
click: () => mainWindow.webContents.send('toggle-find')
|
||||
{
|
||||
label: 'Find & Replace',
|
||||
accelerator: 'CmdOrCtrl+F',
|
||||
click: () => mainWindow.webContents.send('toggle-find')
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -227,7 +240,26 @@ function createMenu() {
|
||||
{ label: 'Dark', click: () => setTheme('dark') },
|
||||
{ label: 'Solarized', click: () => setTheme('solarized') },
|
||||
{ label: 'Monokai', click: () => setTheme('monokai') },
|
||||
{ label: 'GitHub', click: () => setTheme('github') }
|
||||
{ label: 'GitHub', click: () => setTheme('github') },
|
||||
{ type: 'separator' },
|
||||
{ label: 'Dracula', click: () => setTheme('dracula') },
|
||||
{ label: 'Nord', click: () => setTheme('nord') },
|
||||
{ label: 'One Dark', click: () => setTheme('onedark') },
|
||||
{ label: 'Atom One Light', click: () => setTheme('atomonelight') },
|
||||
{ label: 'Material', click: () => setTheme('material') },
|
||||
{ label: 'Gruvbox Dark', click: () => setTheme('gruvbox-dark') },
|
||||
{ label: 'Gruvbox Light', click: () => setTheme('gruvbox-light') },
|
||||
{ label: 'Tokyo Night', click: () => setTheme('tokyonight') },
|
||||
{ label: 'Palenight', click: () => setTheme('palenight') },
|
||||
{ label: 'Ayu Dark', click: () => setTheme('ayu-dark') },
|
||||
{ label: 'Ayu Light', click: () => setTheme('ayu-light') },
|
||||
{ label: 'Ayu Mirage', click: () => setTheme('ayu-mirage') },
|
||||
{ label: 'Oceanic Next', click: () => setTheme('oceanic-next') },
|
||||
{ label: 'Cobalt2', click: () => setTheme('cobalt2') },
|
||||
{ type: 'separator' },
|
||||
{ label: 'Concrete Dark', click: () => setTheme('concrete-dark') },
|
||||
{ label: 'Concrete Light', click: () => setTheme('concrete-light') },
|
||||
{ label: 'Concrete Warm', click: () => setTheme('concrete-warm') }
|
||||
]
|
||||
},
|
||||
{ type: 'separator' },
|
||||
@@ -378,7 +410,7 @@ function createMenu() {
|
||||
type: 'info',
|
||||
title: 'About PanConverter',
|
||||
message: 'PanConverter',
|
||||
detail: 'A cross-platform Markdown editor and converter using Pandoc.\n\nVersion: 1.7.0\nAuthor: Amit Haridas\nEmail: amit.wh@gmail.com\nLicense: MIT\n\nFeatures:\n• Comprehensive PDF Editor (merge, split, compress, rotate, watermark, encrypt)\n• Universal File Converter (LibreOffice, ImageMagick, FFmpeg, Pandoc)\n• Windows Explorer context menu integration\n• Tabbed interface for multiple files\n• Advanced markdown editing with live preview\n• Real-time preview updates while typing\n• Full toolbar markdown editing functions\n• Enhanced PDF export with built-in Electron fallback\n• File association support for .md files\n• Command-line interface for batch conversion\n• Advanced export options with templates and metadata\n• Batch file conversion with progress tracking\n• Improved preview typography and spacing\n• Adjustable font sizes via menu (Ctrl+Shift+Plus/Minus)\n• Complete theme support including Monokai fixes\n• Find & replace with match highlighting\n• Line numbers and auto-indentation\n• Export to multiple formats via Pandoc\n• PowerPoint & presentation export\n• Export tables to Excel/ODS spreadsheets\n• Document import & conversion\n• Table creation helper\n• Multiple themes support\n• Undo/redo functionality\n• Live word count and statistics',
|
||||
detail: 'A cross-platform Markdown editor and converter using Pandoc.\n\nVersion: 1.7.3\nAuthor: Amit Haridas\nEmail: amit.wh@gmail.com\nLicense: MIT\n\nFeatures:\n• Modern glassmorphism UI with gradient backgrounds\n• Comprehensive PDF Editor (merge, split, compress, rotate, watermark, encrypt)\n• Universal File Converter (LibreOffice, ImageMagick, FFmpeg, Pandoc)\n• Windows Explorer context menu integration\n• Tabbed interface for multiple files\n• Advanced markdown editing with live preview\n• Real-time preview updates while typing\n• Full toolbar markdown editing functions\n• Enhanced PDF export with built-in Electron fallback\n• File association support for .md files\n• Command-line interface for batch conversion\n• Advanced export options with templates and metadata\n• Batch file conversion with progress tracking\n• Improved preview typography and spacing\n• Adjustable font sizes via menu (Ctrl+Shift+Plus/Minus)\n• Complete theme support including Monokai fixes\n• Find & replace with match highlighting\n• Line numbers and auto-indentation\n• Export to multiple formats via Pandoc\n• PowerPoint & presentation export\n• Export tables to Excel/ODS spreadsheets\n• Document import & conversion\n• Table creation helper\n• 22 beautiful themes (including Dracula, Nord, Tokyo Night, Gruvbox, Ayu, Concrete, and more)\n• Undo/redo functionality\n• Live word count and statistics',
|
||||
buttons: ['OK']
|
||||
});
|
||||
}
|
||||
@@ -1552,14 +1584,15 @@ function openFileFromPath(filePath) {
|
||||
currentFile = filePath;
|
||||
const content = fs.readFileSync(filePath, 'utf-8');
|
||||
if (mainWindow && mainWindow.webContents) {
|
||||
// Wait for the renderer to be ready (TabManager initialized) before sending file data
|
||||
if (rendererReady) {
|
||||
mainWindow.webContents.send('file-opened', { path: filePath, content });
|
||||
} else {
|
||||
// Store file to open after renderer is ready
|
||||
app.pendingFile = filePath;
|
||||
}
|
||||
console.log('Attempting to open file:', filePath, 'rendererReady:', rendererReady);
|
||||
// Always try to send, the renderer will handle it when ready
|
||||
mainWindow.webContents.send('file-opened', { path: filePath, content });
|
||||
} else {
|
||||
// Store file to open after window is created
|
||||
app.pendingFile = filePath;
|
||||
}
|
||||
} else {
|
||||
console.error('File does not exist:', filePath);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+40
-1
@@ -949,6 +949,7 @@ class TabManager {
|
||||
|
||||
// File operations
|
||||
openFile(filePath, content) {
|
||||
console.log('openFile called with:', filePath, 'content length:', content.length);
|
||||
let tab = this.tabs.get(this.activeTabId);
|
||||
|
||||
// Handle both forward and back slashes for cross-platform compatibility
|
||||
@@ -956,13 +957,21 @@ class TabManager {
|
||||
|
||||
// If current tab is empty and untitled, reuse it
|
||||
if (!tab.filePath && !tab.isDirty && tab.content === '') {
|
||||
console.log('Reusing current tab');
|
||||
tab.filePath = filePath;
|
||||
tab.title = fileName;
|
||||
tab.content = content;
|
||||
tab.originalContent = content;
|
||||
tab.isDirty = false;
|
||||
|
||||
// Update the editor immediately
|
||||
const editor = document.getElementById(`editor-${this.activeTabId}`);
|
||||
if (editor) {
|
||||
editor.value = content;
|
||||
}
|
||||
} else {
|
||||
// Create new tab for the file
|
||||
console.log('Creating new tab for file');
|
||||
this.createNewTab();
|
||||
tab = this.tabs.get(this.activeTabId);
|
||||
tab.filePath = filePath;
|
||||
@@ -970,12 +979,29 @@ class TabManager {
|
||||
tab.content = content;
|
||||
tab.originalContent = content;
|
||||
tab.isDirty = false;
|
||||
|
||||
// Wait a moment for the DOM to update, then set content
|
||||
setTimeout(() => {
|
||||
const editor = document.getElementById(`editor-${this.activeTabId}`);
|
||||
if (editor) {
|
||||
editor.value = content;
|
||||
this.updatePreview(this.activeTabId);
|
||||
this.updateWordCount();
|
||||
}
|
||||
}, 50);
|
||||
}
|
||||
|
||||
this.restoreTabState(this.activeTabId);
|
||||
this.updatePreview(this.activeTabId);
|
||||
this.updateWordCount();
|
||||
this.startAutoSave();
|
||||
this.addToRecentFiles(filePath);
|
||||
this.updateTabBar();
|
||||
|
||||
// Notify main process about current file for exports
|
||||
const { ipcRenderer } = require('electron');
|
||||
ipcRenderer.send('set-current-file', filePath);
|
||||
|
||||
console.log('File opened successfully');
|
||||
}
|
||||
|
||||
getCurrentContent() {
|
||||
@@ -1078,6 +1104,19 @@ ipcRenderer.on('theme-changed', (event, theme) => {
|
||||
document.body.className = `theme-${theme}`;
|
||||
});
|
||||
|
||||
// Undo/Redo handlers
|
||||
ipcRenderer.on('undo', () => {
|
||||
if (tabManager) {
|
||||
tabManager.undo();
|
||||
}
|
||||
});
|
||||
|
||||
ipcRenderer.on('redo', () => {
|
||||
if (tabManager) {
|
||||
tabManager.redo();
|
||||
}
|
||||
});
|
||||
|
||||
// Font size adjustment
|
||||
let currentFontSize = parseInt(localStorage.getItem('fontSize')) || 15;
|
||||
|
||||
|
||||
@@ -0,0 +1,825 @@
|
||||
/* ========================================
|
||||
PanConverter v1.7.1 - Modern UI
|
||||
Glassmorphism, Gradients & Animations
|
||||
======================================== */
|
||||
|
||||
/* Modern Color Palette */
|
||||
:root {
|
||||
/* Primary Brand Colors - Purple-Blue Gradient */
|
||||
--primary-gradient: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
--primary-light: #8b9aff;
|
||||
--primary-dark: #5661b3;
|
||||
|
||||
/* Accent Colors */
|
||||
--accent-green: #10b981;
|
||||
--accent-blue: #3b82f6;
|
||||
--accent-purple: #8b5cf6;
|
||||
--accent-pink: #ec4899;
|
||||
|
||||
/* Neutral Colors */
|
||||
--gray-50: #f9fafb;
|
||||
--gray-100: #f3f4f6;
|
||||
--gray-200: #e5e7eb;
|
||||
--gray-300: #d1d5db;
|
||||
--gray-400: #9ca3af;
|
||||
--gray-500: #6b7280;
|
||||
--gray-600: #4b5563;
|
||||
--gray-700: #374151;
|
||||
--gray-800: #1f2937;
|
||||
--gray-900: #111827;
|
||||
|
||||
/* Glassmorphism */
|
||||
--glass-bg: rgba(255, 255, 255, 0.7);
|
||||
--glass-border: rgba(255, 255, 255, 0.18);
|
||||
--glass-shadow: 0 8px 32px 0 rgba(31, 38, 135, 0.15);
|
||||
|
||||
/* Effects */
|
||||
--blur-amount: 10px;
|
||||
--transition-speed: 0.3s;
|
||||
--transition-ease: cubic-bezier(0.4, 0, 0.2, 1);
|
||||
}
|
||||
|
||||
/* Reset & Base */
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
|
||||
overflow: hidden;
|
||||
height: 100vh;
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 50%, #f093fb 100%);
|
||||
background-size: 200% 200%;
|
||||
animation: gradientShift 15s ease infinite;
|
||||
color: var(--gray-900);
|
||||
}
|
||||
|
||||
@keyframes gradientShift {
|
||||
0% { background-position: 0% 50%; }
|
||||
50% { background-position: 100% 50%; }
|
||||
100% { background-position: 0% 50%; }
|
||||
}
|
||||
|
||||
.container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100vh;
|
||||
padding: 12px;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
/* Glass Container for main content */
|
||||
.main-content-glass {
|
||||
background: var(--glass-bg);
|
||||
backdrop-filter: blur(var(--blur-amount));
|
||||
-webkit-backdrop-filter: blur(var(--blur-amount));
|
||||
border: 1px solid var(--glass-border);
|
||||
border-radius: 20px;
|
||||
box-shadow: var(--glass-shadow);
|
||||
overflow: hidden;
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
/* Tab Bar - Modern Glassmorphism */
|
||||
.tab-bar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background: rgba(255, 255, 255, 0.5);
|
||||
backdrop-filter: blur(10px);
|
||||
border-bottom: 1px solid rgba(255, 255, 255, 0.2);
|
||||
padding: 8px 12px;
|
||||
min-height: 48px;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.tab {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 8px 16px;
|
||||
background: rgba(255, 255, 255, 0.3);
|
||||
backdrop-filter: blur(8px);
|
||||
border: 1px solid rgba(255, 255, 255, 0.3);
|
||||
border-radius: 12px;
|
||||
margin-right: 4px;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
max-width: 200px;
|
||||
min-width: 120px;
|
||||
transition: all var(--transition-speed) var(--transition-ease);
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
.tab:hover {
|
||||
background: rgba(255, 255, 255, 0.5);
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.tab.active {
|
||||
background: linear-gradient(135deg, rgba(102, 126, 234, 0.9), rgba(118, 75, 162, 0.9));
|
||||
color: white;
|
||||
border-color: rgba(255, 255, 255, 0.5);
|
||||
box-shadow: 0 6px 20px rgba(102, 126, 234, 0.4);
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
.tab-title {
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.tab-close {
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
border: none;
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
cursor: pointer;
|
||||
padding: 4px;
|
||||
margin-left: 8px;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 6px;
|
||||
color: currentColor;
|
||||
transition: all var(--transition-speed) var(--transition-ease);
|
||||
}
|
||||
|
||||
.tab-close:hover {
|
||||
background: rgba(255, 255, 255, 0.4);
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
|
||||
.new-tab-button {
|
||||
background: rgba(255, 255, 255, 0.3);
|
||||
backdrop-filter: blur(8px);
|
||||
border: 1px solid rgba(255, 255, 255, 0.3);
|
||||
border-radius: 10px;
|
||||
padding: 8px 16px;
|
||||
cursor: pointer;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
color: var(--gray-700);
|
||||
transition: all var(--transition-speed) var(--transition-ease);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.new-tab-button:hover {
|
||||
background: rgba(255, 255, 255, 0.5);
|
||||
transform: scale(1.05);
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
/* Toolbar - Modern Gradient Buttons */
|
||||
.toolbar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 10px 16px;
|
||||
background: rgba(255, 255, 255, 0.4);
|
||||
backdrop-filter: blur(10px);
|
||||
border-bottom: 1px solid rgba(255, 255, 255, 0.2);
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.toolbar button {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
border: 1px solid rgba(255, 255, 255, 0.3);
|
||||
background: rgba(255, 255, 255, 0.3);
|
||||
backdrop-filter: blur(8px);
|
||||
border-radius: 10px;
|
||||
cursor: pointer;
|
||||
transition: all var(--transition-speed) var(--transition-ease);
|
||||
color: var(--gray-700);
|
||||
}
|
||||
|
||||
.toolbar button:hover {
|
||||
background: var(--primary-gradient);
|
||||
border-color: transparent;
|
||||
color: white;
|
||||
transform: translateY(-2px) scale(1.05);
|
||||
box-shadow: 0 6px 16px rgba(102, 126, 234, 0.3);
|
||||
}
|
||||
|
||||
.toolbar button:active {
|
||||
transform: translateY(0) scale(0.98);
|
||||
}
|
||||
|
||||
.toolbar-separator {
|
||||
width: 1px;
|
||||
height: 24px;
|
||||
background: linear-gradient(180deg, transparent, rgba(255, 255, 255, 0.4), transparent);
|
||||
margin: 0 8px;
|
||||
}
|
||||
|
||||
/* Tab Content */
|
||||
.tab-content {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.tab-content:not(.active) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Editor Container */
|
||||
.editor-container {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
background: rgba(255, 255, 255, 0.3);
|
||||
backdrop-filter: blur(10px);
|
||||
border-radius: 0 0 20px 20px;
|
||||
}
|
||||
|
||||
.pane {
|
||||
flex: 1;
|
||||
overflow: auto;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.pane:first-child {
|
||||
border-right: 1px solid rgba(255, 255, 255, 0.3);
|
||||
}
|
||||
|
||||
/* Custom Scrollbar */
|
||||
.pane::-webkit-scrollbar,
|
||||
.editor-textarea::-webkit-scrollbar {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
}
|
||||
|
||||
.pane::-webkit-scrollbar-track,
|
||||
.editor-textarea::-webkit-scrollbar-track {
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.pane::-webkit-scrollbar-thumb,
|
||||
.editor-textarea::-webkit-scrollbar-thumb {
|
||||
background: var(--primary-gradient);
|
||||
border-radius: 10px;
|
||||
border: 2px solid rgba(255, 255, 255, 0.2);
|
||||
}
|
||||
|
||||
.pane::-webkit-scrollbar-thumb:hover,
|
||||
.editor-textarea::-webkit-scrollbar-thumb:hover {
|
||||
background: linear-gradient(135deg, #8b9aff, #9d6fd8);
|
||||
}
|
||||
|
||||
.editor-textarea {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 24px;
|
||||
font-family: 'JetBrains Mono', 'Fira Code', 'SF Mono', Monaco, 'Courier New', monospace;
|
||||
font-size: 15px;
|
||||
line-height: 1.7;
|
||||
border: none;
|
||||
outline: none;
|
||||
resize: none;
|
||||
background: transparent;
|
||||
color: var(--gray-900);
|
||||
}
|
||||
|
||||
.pane:last-child {
|
||||
padding: 0;
|
||||
background: rgba(255, 255, 255, 0.5);
|
||||
backdrop-filter: blur(15px);
|
||||
}
|
||||
|
||||
.preview-content {
|
||||
max-width: none;
|
||||
margin: 0;
|
||||
padding: 24px 32px;
|
||||
line-height: 1.8;
|
||||
font-size: 15px;
|
||||
color: var(--gray-900);
|
||||
}
|
||||
|
||||
/* Status Bar - Glassmorphism */
|
||||
.status-bar {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 8px 20px;
|
||||
background: rgba(255, 255, 255, 0.5);
|
||||
backdrop-filter: blur(10px);
|
||||
border-top: 1px solid rgba(255, 255, 255, 0.2);
|
||||
border-radius: 0 0 20px 20px;
|
||||
font-size: 12px;
|
||||
color: var(--gray-600);
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
/* Preview Styles - Modern Typography */
|
||||
.preview-content h1, .preview-content h2, .preview-content h3 {
|
||||
background: var(--primary-gradient);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
background-clip: text;
|
||||
font-weight: 700;
|
||||
margin-top: 28px;
|
||||
margin-bottom: 16px;
|
||||
line-height: 1.3;
|
||||
}
|
||||
|
||||
.preview-content h1 {
|
||||
font-size: 2.5em;
|
||||
border-bottom: 3px solid;
|
||||
border-image: var(--primary-gradient) 1;
|
||||
padding-bottom: 12px;
|
||||
}
|
||||
|
||||
.preview-content h2 {
|
||||
font-size: 2em;
|
||||
border-bottom: 2px solid rgba(102, 126, 234, 0.3);
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
|
||||
.preview-content p {
|
||||
margin-bottom: 18px;
|
||||
line-height: 1.8;
|
||||
}
|
||||
|
||||
.preview-content code {
|
||||
padding: 3px 8px;
|
||||
margin: 0 2px;
|
||||
font-size: 90%;
|
||||
background: linear-gradient(135deg, rgba(102, 126, 234, 0.1), rgba(118, 75, 162, 0.1));
|
||||
border: 1px solid rgba(102, 126, 234, 0.2);
|
||||
border-radius: 6px;
|
||||
font-family: 'JetBrains Mono', 'Fira Code', monospace;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.preview-content pre {
|
||||
padding: 20px;
|
||||
overflow-x: auto;
|
||||
font-size: 14px;
|
||||
line-height: 1.6;
|
||||
background: rgba(255, 255, 255, 0.6);
|
||||
backdrop-filter: blur(10px);
|
||||
border: 1px solid rgba(102, 126, 234, 0.2);
|
||||
border-radius: 12px;
|
||||
margin-bottom: 20px;
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.preview-content pre code {
|
||||
background: transparent;
|
||||
border: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.preview-content blockquote {
|
||||
padding: 16px 20px;
|
||||
color: var(--gray-700);
|
||||
border-left: 4px solid;
|
||||
border-image: var(--primary-gradient) 1;
|
||||
margin-bottom: 20px;
|
||||
background: rgba(255, 255, 255, 0.4);
|
||||
backdrop-filter: blur(8px);
|
||||
border-radius: 0 8px 8px 0;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.preview-content a {
|
||||
color: #667eea;
|
||||
text-decoration: none;
|
||||
font-weight: 600;
|
||||
position: relative;
|
||||
transition: color var(--transition-speed);
|
||||
}
|
||||
|
||||
.preview-content a::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 0;
|
||||
bottom: -2px;
|
||||
width: 0;
|
||||
height: 2px;
|
||||
background: var(--primary-gradient);
|
||||
transition: width var(--transition-speed) var(--transition-ease);
|
||||
}
|
||||
|
||||
.preview-content a:hover {
|
||||
color: #764ba2;
|
||||
}
|
||||
|
||||
.preview-content a:hover::after {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.preview-content table {
|
||||
border-collapse: separate;
|
||||
border-spacing: 0;
|
||||
margin-bottom: 20px;
|
||||
width: 100%;
|
||||
border-radius: 12px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.preview-content table th,
|
||||
.preview-content table td {
|
||||
padding: 12px 16px;
|
||||
border: 1px solid rgba(102, 126, 234, 0.2);
|
||||
}
|
||||
|
||||
.preview-content table th {
|
||||
font-weight: 600;
|
||||
background: var(--primary-gradient);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.preview-content table tr:nth-child(even) {
|
||||
background: rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
|
||||
/* Modern Dialogs */
|
||||
.export-dialog,
|
||||
.batch-dialog,
|
||||
.find-dialog-overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: rgba(0, 0, 0, 0.4);
|
||||
backdrop-filter: blur(8px);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 1000;
|
||||
animation: fadeIn 0.3s var(--transition-ease);
|
||||
}
|
||||
|
||||
@keyframes fadeIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.export-dialog.hidden,
|
||||
.batch-dialog.hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.export-dialog-content,
|
||||
.batch-dialog-content {
|
||||
background: rgba(255, 255, 255, 0.95);
|
||||
backdrop-filter: blur(20px);
|
||||
border: 1px solid rgba(255, 255, 255, 0.3);
|
||||
border-radius: 20px;
|
||||
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
|
||||
width: 90%;
|
||||
max-width: 650px;
|
||||
max-height: 90vh;
|
||||
overflow-y: auto;
|
||||
animation: slideUpFade 0.4s var(--transition-ease);
|
||||
}
|
||||
|
||||
@keyframes slideUpFade {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(30px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
.export-dialog-header,
|
||||
.batch-dialog-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 20px 24px;
|
||||
border-bottom: 1px solid rgba(102, 126, 234, 0.2);
|
||||
background: var(--primary-gradient);
|
||||
border-radius: 20px 20px 0 0;
|
||||
}
|
||||
|
||||
.export-dialog-header h3,
|
||||
.batch-dialog-header h3 {
|
||||
margin: 0;
|
||||
font-size: 20px;
|
||||
font-weight: 700;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.export-dialog-body,
|
||||
.batch-dialog-body {
|
||||
padding: 24px;
|
||||
}
|
||||
|
||||
.export-section,
|
||||
.batch-section {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.export-section label,
|
||||
.batch-section label {
|
||||
display: block;
|
||||
font-weight: 600;
|
||||
margin-bottom: 8px;
|
||||
color: var(--gray-700);
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.export-section select,
|
||||
.export-section input,
|
||||
.batch-section select,
|
||||
.batch-section input {
|
||||
width: 100%;
|
||||
padding: 10px 14px;
|
||||
border: 2px solid rgba(102, 126, 234, 0.2);
|
||||
border-radius: 10px;
|
||||
font-size: 14px;
|
||||
background: rgba(255, 255, 255, 0.8);
|
||||
backdrop-filter: blur(5px);
|
||||
transition: all var(--transition-speed) var(--transition-ease);
|
||||
}
|
||||
|
||||
.export-section select:focus,
|
||||
.export-section input:focus,
|
||||
.batch-section select:focus,
|
||||
.batch-section input:focus {
|
||||
outline: none;
|
||||
border-color: #667eea;
|
||||
box-shadow: 0 0 0 4px rgba(102, 126, 234, 0.1);
|
||||
background: white;
|
||||
}
|
||||
|
||||
/* Modern Buttons */
|
||||
.export-dialog-footer,
|
||||
.batch-dialog-footer {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 12px;
|
||||
padding: 20px 24px;
|
||||
border-top: 1px solid rgba(102, 126, 234, 0.2);
|
||||
background: rgba(255, 255, 255, 0.5);
|
||||
backdrop-filter: blur(10px);
|
||||
border-radius: 0 0 20px 20px;
|
||||
}
|
||||
|
||||
.export-dialog-footer button,
|
||||
.batch-dialog-footer button,
|
||||
.folder-input-group button {
|
||||
padding: 10px 24px;
|
||||
border: none;
|
||||
border-radius: 10px;
|
||||
cursor: pointer;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
transition: all var(--transition-speed) var(--transition-ease);
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.export-dialog-footer button.primary,
|
||||
.batch-dialog-footer button.primary {
|
||||
background: var(--primary-gradient);
|
||||
color: white;
|
||||
box-shadow: 0 4px 12px rgba(102, 126, 234, 0.4);
|
||||
}
|
||||
|
||||
.export-dialog-footer button.primary:hover,
|
||||
.batch-dialog-footer button.primary:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 6px 20px rgba(102, 126, 234, 0.5);
|
||||
}
|
||||
|
||||
.export-dialog-footer button:not(.primary),
|
||||
.batch-dialog-footer button:not(.primary),
|
||||
.folder-input-group button {
|
||||
background: rgba(255, 255, 255, 0.8);
|
||||
color: var(--gray-700);
|
||||
border: 2px solid rgba(102, 126, 234, 0.2);
|
||||
}
|
||||
|
||||
.export-dialog-footer button:not(.primary):hover,
|
||||
.batch-dialog-footer button:not(.primary):hover,
|
||||
.folder-input-group button:hover {
|
||||
background: white;
|
||||
border-color: #667eea;
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
/* Find Dialog - Floating Modern */
|
||||
.find-dialog {
|
||||
position: absolute;
|
||||
top: 70px;
|
||||
right: 24px;
|
||||
background: rgba(255, 255, 255, 0.95);
|
||||
backdrop-filter: blur(20px);
|
||||
border: 1px solid rgba(255, 255, 255, 0.3);
|
||||
border-radius: 16px;
|
||||
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.2);
|
||||
z-index: 1000;
|
||||
min-width: 420px;
|
||||
padding: 16px;
|
||||
animation: slideInRight 0.3s var(--transition-ease);
|
||||
}
|
||||
|
||||
@keyframes slideInRight {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateX(30px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateX(0);
|
||||
}
|
||||
}
|
||||
|
||||
.find-dialog.hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Progress Bars - Modern Gradient */
|
||||
.progress-bar {
|
||||
width: 100%;
|
||||
height: 8px;
|
||||
background: rgba(102, 126, 234, 0.1);
|
||||
border-radius: 10px;
|
||||
overflow: hidden;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.progress-fill {
|
||||
height: 100%;
|
||||
background: var(--primary-gradient);
|
||||
transition: width 0.4s var(--transition-ease);
|
||||
width: 0%;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.progress-fill::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: linear-gradient(90deg,
|
||||
transparent,
|
||||
rgba(255, 255, 255, 0.3),
|
||||
transparent
|
||||
);
|
||||
animation: shimmer 2s infinite;
|
||||
}
|
||||
|
||||
@keyframes shimmer {
|
||||
0% {
|
||||
transform: translateX(-100%);
|
||||
}
|
||||
100% {
|
||||
transform: translateX(100%);
|
||||
}
|
||||
}
|
||||
|
||||
/* Auto-save Indicator - Modern */
|
||||
.auto-save-indicator {
|
||||
position: fixed;
|
||||
top: 24px;
|
||||
right: 24px;
|
||||
background: var(--primary-gradient);
|
||||
color: white;
|
||||
padding: 10px 20px;
|
||||
border-radius: 12px;
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
z-index: 10000;
|
||||
box-shadow: 0 4px 20px rgba(102, 126, 234, 0.4);
|
||||
animation: slideInRight 0.3s ease-out;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.auto-save-indicator::before {
|
||||
content: '✓';
|
||||
display: inline-block;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
background: white;
|
||||
color: #667eea;
|
||||
border-radius: 50%;
|
||||
font-size: 12px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* Enhanced Statistics - Modern */
|
||||
.enhanced-stats {
|
||||
font-size: 11px;
|
||||
color: var(--gray-600);
|
||||
padding: 2px 0;
|
||||
margin-left: 16px;
|
||||
font-family: 'JetBrains Mono', monospace;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
/* Line Numbers - Modern */
|
||||
.line-numbers {
|
||||
min-width: 50px;
|
||||
padding: 12px 8px;
|
||||
background: rgba(255, 255, 255, 0.3);
|
||||
backdrop-filter: blur(8px);
|
||||
border-right: 1px solid rgba(102, 126, 234, 0.2);
|
||||
font-family: 'JetBrains Mono', monospace;
|
||||
font-size: 13px;
|
||||
line-height: 1.7;
|
||||
color: var(--gray-500);
|
||||
text-align: right;
|
||||
user-select: none;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.line-numbers.hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Animations & Transitions */
|
||||
.toolbar button,
|
||||
.tab,
|
||||
.new-tab-button,
|
||||
.export-dialog-footer button,
|
||||
.batch-dialog-footer button {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.toolbar button::before,
|
||||
.tab::before,
|
||||
.new-tab-button::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-radius: 50%;
|
||||
background: rgba(255, 255, 255, 0.4);
|
||||
transform: translate(-50%, -50%);
|
||||
transition: width 0.6s, height 0.6s;
|
||||
}
|
||||
|
||||
.toolbar button:hover::before,
|
||||
.tab:hover::before,
|
||||
.new-tab-button:hover::before {
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
}
|
||||
|
||||
/* Responsive Design */
|
||||
@media (max-width: 768px) {
|
||||
.container {
|
||||
padding: 8px;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.export-dialog-content,
|
||||
.batch-dialog-content {
|
||||
max-width: 95%;
|
||||
}
|
||||
|
||||
.find-dialog {
|
||||
right: 12px;
|
||||
min-width: 320px;
|
||||
}
|
||||
}
|
||||
|
||||
/* Hide default elements */
|
||||
.pane.hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.pane.full-width {
|
||||
border-right: none;
|
||||
}
|
||||
+1241
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user