mirror of
https://github.com/amitwh/markdown-converter.git
synced 2026-08-02 10:00:17 +05:30
fix: integrate PDF viewer into tab system for multitab support
- Add tab type system ('markdown' and 'pdf')
- Create PDF tabs with their own state (page, zoom, rotation)
- Update closeTab to properly clean up PDF resources
- Update updateUI to handle PDF tabs (hide toolbar, etc.)
- Add visual indicators for PDF tabs in tab bar
- Add CSS styles for PDF tab containers
Fixes: PDF and markdown multitab function not working
Amit Haridas
This commit is contained in:
+267
-72
@@ -105,7 +105,13 @@ class TabManager {
|
|||||||
isDirty: false,
|
isDirty: false,
|
||||||
editorView: null,
|
editorView: null,
|
||||||
findMatches: [],
|
findMatches: [],
|
||||||
currentMatchIndex: -1
|
currentMatchIndex: -1,
|
||||||
|
type: 'markdown', // 'markdown' or 'pdf'
|
||||||
|
// PDF-specific state
|
||||||
|
pdfDoc: null,
|
||||||
|
pdfCurrentPage: 1,
|
||||||
|
pdfZoomLevel: 1.0,
|
||||||
|
pdfRotation: 0
|
||||||
});
|
});
|
||||||
|
|
||||||
this.setupEventListeners();
|
this.setupEventListeners();
|
||||||
@@ -161,17 +167,23 @@ class TabManager {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
createNewTab() {
|
createNewTab(type = 'markdown') {
|
||||||
const newTabId = this.nextTabId++;
|
const newTabId = this.nextTabId++;
|
||||||
const tab = {
|
const tab = {
|
||||||
id: newTabId,
|
id: newTabId,
|
||||||
title: 'Untitled',
|
title: type === 'pdf' ? 'PDF Document' : 'Untitled',
|
||||||
content: '',
|
content: '',
|
||||||
filePath: null,
|
filePath: null,
|
||||||
isDirty: false,
|
isDirty: false,
|
||||||
editorView: null,
|
editorView: null,
|
||||||
findMatches: [],
|
findMatches: [],
|
||||||
currentMatchIndex: -1
|
currentMatchIndex: -1,
|
||||||
|
type: type,
|
||||||
|
// PDF-specific state
|
||||||
|
pdfDoc: null,
|
||||||
|
pdfCurrentPage: 1,
|
||||||
|
pdfZoomLevel: 1.0,
|
||||||
|
pdfRotation: 0
|
||||||
};
|
};
|
||||||
|
|
||||||
this.tabs.set(newTabId, tab);
|
this.tabs.set(newTabId, tab);
|
||||||
@@ -181,6 +193,193 @@ class TabManager {
|
|||||||
this.updateTabBar();
|
this.updateTabBar();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
createPdfTab(filePath) {
|
||||||
|
const newTabId = this.nextTabId++;
|
||||||
|
const fileName = require('path').basename(filePath);
|
||||||
|
const tab = {
|
||||||
|
id: newTabId,
|
||||||
|
title: fileName,
|
||||||
|
content: '',
|
||||||
|
filePath: filePath,
|
||||||
|
isDirty: false,
|
||||||
|
editorView: null,
|
||||||
|
findMatches: [],
|
||||||
|
currentMatchIndex: -1,
|
||||||
|
type: 'pdf',
|
||||||
|
// PDF-specific state
|
||||||
|
pdfDoc: null,
|
||||||
|
pdfCurrentPage: 1,
|
||||||
|
pdfZoomLevel: 1.0,
|
||||||
|
pdfRotation: 0
|
||||||
|
};
|
||||||
|
|
||||||
|
this.tabs.set(newTabId, tab);
|
||||||
|
this.createPdfTabElements(tab);
|
||||||
|
this.switchToTab(newTabId);
|
||||||
|
this.loadPdfInTab(tab.id, filePath);
|
||||||
|
this.updateTabBar();
|
||||||
|
return tab.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
createPdfTabElements(tab) {
|
||||||
|
// Create PDF tab content container
|
||||||
|
const tabContent = document.createElement('div');
|
||||||
|
tabContent.className = 'tab-content';
|
||||||
|
tabContent.id = `tab-content-${tab.id}`;
|
||||||
|
tabContent.dataset.tabId = tab.id;
|
||||||
|
tabContent.dataset.tabType = 'pdf';
|
||||||
|
|
||||||
|
tabContent.innerHTML = `
|
||||||
|
<div class="pdf-tab-container" id="pdf-container-${tab.id}">
|
||||||
|
<div class="pdf-controls">
|
||||||
|
<button class="pdf-nav-btn" data-action="prev" title="Previous Page">◀</button>
|
||||||
|
<input type="number" class="pdf-page-input" id="pdf-page-${tab.id}" value="1" min="1">
|
||||||
|
<span class="pdf-page-info">/ <span id="pdf-total-${tab.id}">1</span></span>
|
||||||
|
<button class="pdf-nav-btn" data-action="next" title="Next Page">▶</button>
|
||||||
|
<button class="pdf-zoom-btn" data-action="zoom-out" title="Zoom Out">−</button>
|
||||||
|
<span class="pdf-zoom-level" id="pdf-zoom-${tab.id}">100%</span>
|
||||||
|
<button class="pdf-zoom-btn" data-action="zoom-in" title="Zoom In">+</button>
|
||||||
|
<button class="pdf-zoom-btn" data-action="fit-width" title="Fit Width">↔</button>
|
||||||
|
<button class="pdf-rotate-btn" data-action="rotate-left" title="Rotate Left">↺</button>
|
||||||
|
<button class="pdf-rotate-btn" data-action="rotate-right" title="Rotate Right">↻</button>
|
||||||
|
</div>
|
||||||
|
<div class="pdf-canvas-container">
|
||||||
|
<canvas id="pdf-canvas-${tab.id}"></canvas>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
document.querySelector('.editor-container').appendChild(tabContent);
|
||||||
|
|
||||||
|
// Add event listeners for PDF controls
|
||||||
|
this.setupPdfTabEvents(tab.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
setupPdfTabEvents(tabId) {
|
||||||
|
const container = document.getElementById(`pdf-container-${tabId}`);
|
||||||
|
if (!container) return;
|
||||||
|
|
||||||
|
container.addEventListener('click', async (e) => {
|
||||||
|
const action = e.target.dataset.action;
|
||||||
|
if (!action) return;
|
||||||
|
|
||||||
|
const tab = this.tabs.get(tabId);
|
||||||
|
if (!tab || !tab.pdfDoc) return;
|
||||||
|
|
||||||
|
switch (action) {
|
||||||
|
case 'prev':
|
||||||
|
if (tab.pdfCurrentPage > 1) {
|
||||||
|
tab.pdfCurrentPage--;
|
||||||
|
await this.renderPdfPageInTab(tabId);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'next':
|
||||||
|
if (tab.pdfCurrentPage < tab.pdfDoc.numPages) {
|
||||||
|
tab.pdfCurrentPage++;
|
||||||
|
await this.renderPdfPageInTab(tabId);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'zoom-out':
|
||||||
|
if (tab.pdfZoomLevel > 0.25) {
|
||||||
|
tab.pdfZoomLevel -= 0.25;
|
||||||
|
await this.renderPdfPageInTab(tabId);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'zoom-in':
|
||||||
|
if (tab.pdfZoomLevel < 4.0) {
|
||||||
|
tab.pdfZoomLevel += 0.25;
|
||||||
|
await this.renderPdfPageInTab(tabId);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'fit-width':
|
||||||
|
const page = await tab.pdfDoc.getPage(tab.pdfCurrentPage);
|
||||||
|
const viewport = page.getViewport({ scale: 1, rotation: tab.pdfRotation });
|
||||||
|
const containerWidth = container.querySelector('.pdf-canvas-container').clientWidth - 40;
|
||||||
|
tab.pdfZoomLevel = containerWidth / viewport.width;
|
||||||
|
await this.renderPdfPageInTab(tabId);
|
||||||
|
break;
|
||||||
|
case 'rotate-left':
|
||||||
|
tab.pdfRotation = (tab.pdfRotation - 90 + 360) % 360;
|
||||||
|
await this.renderPdfPageInTab(tabId);
|
||||||
|
break;
|
||||||
|
case 'rotate-right':
|
||||||
|
tab.pdfRotation = (tab.pdfRotation + 90) % 360;
|
||||||
|
await this.renderPdfPageInTab(tabId);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Page input handler
|
||||||
|
const pageInput = document.getElementById(`pdf-page-${tabId}`);
|
||||||
|
if (pageInput) {
|
||||||
|
pageInput.addEventListener('change', async (e) => {
|
||||||
|
const tab = this.tabs.get(tabId);
|
||||||
|
const pageNum = parseInt(e.target.value);
|
||||||
|
if (tab && tab.pdfDoc && pageNum >= 1 && pageNum <= tab.pdfDoc.numPages) {
|
||||||
|
tab.pdfCurrentPage = pageNum;
|
||||||
|
await this.renderPdfPageInTab(tabId);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async loadPdfInTab(tabId, filePath) {
|
||||||
|
const tab = this.tabs.get(tabId);
|
||||||
|
if (!tab) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
document.getElementById('status-text').textContent = 'Loading PDF...';
|
||||||
|
|
||||||
|
const loadingTask = getPdfjsLib().getDocument(filePath);
|
||||||
|
tab.pdfDoc = await loadingTask.promise;
|
||||||
|
tab.pdfCurrentPage = 1;
|
||||||
|
tab.pdfZoomLevel = 1.0;
|
||||||
|
tab.pdfRotation = 0;
|
||||||
|
|
||||||
|
// Update UI
|
||||||
|
document.getElementById(`pdf-total-${tabId}`).textContent = tab.pdfDoc.numPages;
|
||||||
|
document.getElementById(`pdf-page-${tabId}`).value = 1;
|
||||||
|
document.getElementById(`pdf-page-${tabId}`).max = tab.pdfDoc.numPages;
|
||||||
|
document.getElementById(`pdf-zoom-${tabId}`).textContent = '100%';
|
||||||
|
|
||||||
|
await this.renderPdfPageInTab(tabId);
|
||||||
|
|
||||||
|
document.getElementById('status-text').textContent = `PDF: ${tab.title} (${tab.pdfDoc.numPages} pages)`;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error loading PDF:', error);
|
||||||
|
document.getElementById('status-text').textContent = 'Error loading PDF';
|
||||||
|
alert('Error loading PDF: ' + error.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async renderPdfPageInTab(tabId) {
|
||||||
|
const tab = this.tabs.get(tabId);
|
||||||
|
if (!tab || !tab.pdfDoc) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const page = await tab.pdfDoc.getPage(tab.pdfCurrentPage);
|
||||||
|
const canvas = document.getElementById(`pdf-canvas-${tabId}`);
|
||||||
|
if (!canvas) return;
|
||||||
|
|
||||||
|
const ctx = canvas.getContext('2d');
|
||||||
|
const viewport = page.getViewport({ scale: tab.pdfZoomLevel, rotation: tab.pdfRotation });
|
||||||
|
|
||||||
|
canvas.width = viewport.width;
|
||||||
|
canvas.height = viewport.height;
|
||||||
|
|
||||||
|
await page.render({
|
||||||
|
canvasContext: ctx,
|
||||||
|
viewport: viewport
|
||||||
|
}).promise;
|
||||||
|
|
||||||
|
// Update UI
|
||||||
|
document.getElementById(`pdf-page-${tabId}`).value = tab.pdfCurrentPage;
|
||||||
|
document.getElementById(`pdf-zoom-${tabId}`).textContent = Math.round(tab.pdfZoomLevel * 100) + '%';
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error rendering PDF page:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
createTabElements(tab) {
|
createTabElements(tab) {
|
||||||
// Create tab content container
|
// Create tab content container
|
||||||
const tabContent = document.createElement('div');
|
const tabContent = document.createElement('div');
|
||||||
@@ -263,19 +462,30 @@ class TabManager {
|
|||||||
if (this.tabs.size === 1) return; // Don't close the last tab
|
if (this.tabs.size === 1) return; // Don't close the last tab
|
||||||
|
|
||||||
const tab = this.tabs.get(tabId);
|
const tab = this.tabs.get(tabId);
|
||||||
if (tab.isDirty) {
|
if (!tab) return;
|
||||||
// Show confirmation dialog for unsaved changes
|
|
||||||
|
if (tab.isDirty && tab.type === 'markdown') {
|
||||||
|
// Show confirmation dialog for unsaved changes (only for markdown)
|
||||||
const result = confirm('You have unsaved changes. Do you want to close this tab without saving?');
|
const result = confirm('You have unsaved changes. Do you want to close this tab without saving?');
|
||||||
if (!result) return;
|
if (!result) return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Destroy CodeMirror view
|
// Destroy CodeMirror view (for markdown tabs)
|
||||||
if (tab?.editorView) {
|
if (tab?.editorView) {
|
||||||
tab.editorView.destroy();
|
tab.editorView.destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Destroy PDF document (for PDF tabs)
|
||||||
|
if (tab?.pdfDoc) {
|
||||||
|
try {
|
||||||
|
tab.pdfDoc.destroy();
|
||||||
|
} catch (e) {
|
||||||
|
console.warn('Error destroying PDF:', e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Remove tab elements
|
// Remove tab elements
|
||||||
const tabElement = document.querySelector(`[data-tab-id="${tabId}"]`);
|
const tabElement = document.querySelector(`.tab[data-tab-id="${tabId}"]`);
|
||||||
const tabContent = document.getElementById(`tab-content-${tabId}`);
|
const tabContent = document.getElementById(`tab-content-${tabId}`);
|
||||||
|
|
||||||
if (tabElement?.classList.contains('tab')) {
|
if (tabElement?.classList.contains('tab')) {
|
||||||
@@ -309,17 +519,20 @@ class TabManager {
|
|||||||
|
|
||||||
sortedTabs.forEach(tab => {
|
sortedTabs.forEach(tab => {
|
||||||
const tabElement = document.createElement('div');
|
const tabElement = document.createElement('div');
|
||||||
tabElement.className = `tab ${tab.id === this.activeTabId ? 'active' : ''}`;
|
const typeClass = tab.type === 'pdf' ? 'pdf-tab' : 'markdown-tab';
|
||||||
|
tabElement.className = `tab ${typeClass} ${tab.id === this.activeTabId ? 'active' : ''}`;
|
||||||
tabElement.dataset.tabId = tab.id;
|
tabElement.dataset.tabId = tab.id;
|
||||||
|
tabElement.dataset.tabType = tab.type || 'markdown';
|
||||||
|
|
||||||
const title = tab.filePath ?
|
const title = tab.filePath ?
|
||||||
tab.filePath.split('/').pop() :
|
tab.filePath.split('/').pop() :
|
||||||
tab.title;
|
tab.title;
|
||||||
|
|
||||||
const dirtyIndicator = tab.isDirty ? ' •' : '';
|
const dirtyIndicator = tab.isDirty ? ' •' : '';
|
||||||
|
const typeIndicator = tab.type === 'pdf' ? '📄 ' : '';
|
||||||
|
|
||||||
tabElement.innerHTML = `
|
tabElement.innerHTML = `
|
||||||
<span class="tab-title">${title}${dirtyIndicator}</span>
|
<span class="tab-title">${typeIndicator}${title}${dirtyIndicator}</span>
|
||||||
<button class="tab-close" title="Close tab">×</button>
|
<button class="tab-close" title="Close tab">×</button>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
@@ -338,9 +551,25 @@ class TabManager {
|
|||||||
activeContent.classList.add('active');
|
activeContent.classList.add('active');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update preview visibility
|
// Get active tab to check type
|
||||||
this.updatePreviewVisibility();
|
const activeTab = this.tabs.get(this.activeTabId);
|
||||||
this.updateLineNumbers();
|
|
||||||
|
// Show/hide toolbar based on tab type
|
||||||
|
const toolbar = document.querySelector('.toolbar');
|
||||||
|
if (toolbar) {
|
||||||
|
if (activeTab?.type === 'pdf') {
|
||||||
|
toolbar.classList.add('hidden');
|
||||||
|
} else {
|
||||||
|
toolbar.classList.remove('hidden');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update preview visibility (only for markdown tabs)
|
||||||
|
if (activeTab?.type !== 'pdf') {
|
||||||
|
this.updatePreviewVisibility();
|
||||||
|
this.updateLineNumbers();
|
||||||
|
}
|
||||||
|
|
||||||
this.updateTabBar();
|
this.updateTabBar();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4093,12 +4322,13 @@ ipcRenderer.on('insert-content', (event, content) => {
|
|||||||
// PDF VIEWER FUNCTIONALITY
|
// PDF VIEWER FUNCTIONALITY
|
||||||
// ============================================
|
// ============================================
|
||||||
|
|
||||||
|
// Legacy PDF viewer globals - kept for PDF editor dialogs that still use them
|
||||||
let pdfDoc = null;
|
let pdfDoc = null;
|
||||||
let pdfCurrentPage = 1;
|
let pdfCurrentPage = 1;
|
||||||
let pdfZoomLevel = 1.0;
|
let pdfZoomLevel = 1.0;
|
||||||
let pdfRotation = 0;
|
let pdfRotation = 0;
|
||||||
let pdfFilePath = null;
|
let pdfFilePath = null;
|
||||||
let isPdfViewerActive = false; // Track if PDF viewer is currently shown
|
let isPdfViewerActive = false;
|
||||||
|
|
||||||
// Initialize PDF.js
|
// Initialize PDF.js
|
||||||
// Lazy-load pdfjs-dist only when PDF viewer is needed
|
// Lazy-load pdfjs-dist only when PDF viewer is needed
|
||||||
@@ -4111,62 +4341,19 @@ function getPdfjsLib() {
|
|||||||
return _pdfjsLib;
|
return _pdfjsLib;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Open PDF file
|
// Open PDF file - now creates a tab instead of replacing the entire view
|
||||||
async function openPdfFile(filePath) {
|
async function openPdfFile(filePath) {
|
||||||
// Prevent multiple simultaneous PDF loads
|
// Check if this PDF is already open in a tab
|
||||||
if (isPdfViewerActive && pdfFilePath === filePath) {
|
for (const [tabId, tab] of tabManager.tabs) {
|
||||||
console.log('PDF already open:', filePath);
|
if (tab.type === 'pdf' && tab.filePath === filePath) {
|
||||||
return;
|
// Just switch to the existing tab
|
||||||
}
|
tabManager.switchToTab(tabId);
|
||||||
|
return;
|
||||||
// Close any existing PDF first
|
|
||||||
if (pdfDoc) {
|
|
||||||
try {
|
|
||||||
await pdfDoc.destroy();
|
|
||||||
} catch (e) {
|
|
||||||
console.warn('Error destroying previous PDF:', e);
|
|
||||||
}
|
}
|
||||||
pdfDoc = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
// Create a new PDF tab
|
||||||
// Show loading state
|
tabManager.createPdfTab(filePath);
|
||||||
document.getElementById('status-text').textContent = 'Loading PDF...';
|
|
||||||
|
|
||||||
const loadingTask = getPdfjsLib().getDocument(filePath);
|
|
||||||
pdfDoc = await loadingTask.promise;
|
|
||||||
pdfFilePath = filePath;
|
|
||||||
pdfCurrentPage = 1;
|
|
||||||
pdfZoomLevel = 1.0;
|
|
||||||
pdfRotation = 0;
|
|
||||||
isPdfViewerActive = true;
|
|
||||||
|
|
||||||
// Update UI
|
|
||||||
document.getElementById('pdf-total-pages').textContent = pdfDoc.numPages;
|
|
||||||
document.getElementById('pdf-page-input').value = 1;
|
|
||||||
document.getElementById('pdf-page-input').max = pdfDoc.numPages;
|
|
||||||
document.getElementById('pdf-filename').textContent = require('path').basename(filePath);
|
|
||||||
document.getElementById('pdf-zoom-level').textContent = '100%';
|
|
||||||
|
|
||||||
// Hide markdown toolbar, tabs, show PDF viewer
|
|
||||||
document.querySelector('.toolbar').classList.add('hidden');
|
|
||||||
document.getElementById('tab-bar').classList.add('hidden');
|
|
||||||
document.querySelectorAll('.tab-content').forEach(tc => tc.classList.add('hidden'));
|
|
||||||
document.getElementById('pdf-viewer-container').classList.remove('hidden');
|
|
||||||
|
|
||||||
// Render first page
|
|
||||||
await renderPdfPage(pdfCurrentPage);
|
|
||||||
|
|
||||||
// Update status
|
|
||||||
document.getElementById('status-text').textContent = `PDF: ${require('path').basename(filePath)} (${pdfDoc.numPages} pages)`;
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error loading PDF:', error);
|
|
||||||
isPdfViewerActive = false;
|
|
||||||
pdfDoc = null;
|
|
||||||
pdfFilePath = null;
|
|
||||||
document.getElementById('status-text').textContent = 'Error loading PDF';
|
|
||||||
alert('Error loading PDF: ' + error.message);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Render PDF page
|
// Render PDF page
|
||||||
@@ -4279,7 +4466,7 @@ document.getElementById('pdf-close')?.addEventListener('click', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
async function closePdfViewer() {
|
async function closePdfViewer() {
|
||||||
// Destroy PDF document to free memory
|
// Legacy PDF viewer close - for backward compatibility with PDF editor dialogs
|
||||||
if (pdfDoc) {
|
if (pdfDoc) {
|
||||||
try {
|
try {
|
||||||
await pdfDoc.destroy();
|
await pdfDoc.destroy();
|
||||||
@@ -4292,19 +4479,27 @@ async function closePdfViewer() {
|
|||||||
pdfFilePath = null;
|
pdfFilePath = null;
|
||||||
isPdfViewerActive = false;
|
isPdfViewerActive = false;
|
||||||
|
|
||||||
// Hide PDF viewer
|
// If we're using the new tab-based system, close the current PDF tab
|
||||||
document.getElementById('pdf-viewer-container').classList.add('hidden');
|
if (tabManager) {
|
||||||
|
const activeTab = tabManager.tabs.get(tabManager.activeTabId);
|
||||||
|
if (activeTab && activeTab.type === 'pdf') {
|
||||||
|
tabManager.closeTab(tabManager.activeTabId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Legacy: Hide PDF viewer container
|
||||||
|
document.getElementById('pdf-viewer-container')?.classList.add('hidden');
|
||||||
|
|
||||||
// Show markdown tabs, tab bar, and toolbar
|
// Show markdown tabs, tab bar, and toolbar
|
||||||
document.getElementById('tab-bar').classList.remove('hidden');
|
document.getElementById('tab-bar')?.classList.remove('hidden');
|
||||||
document.querySelectorAll('.tab-content').forEach(tc => tc.classList.remove('hidden'));
|
document.querySelectorAll('.tab-content').forEach(tc => tc.classList.remove('hidden'));
|
||||||
document.querySelector('.toolbar').classList.remove('hidden');
|
document.querySelector('.toolbar')?.classList.remove('hidden');
|
||||||
|
|
||||||
// Activate the correct markdown tab
|
// Activate the correct markdown tab
|
||||||
if (tabManager) {
|
if (tabManager) {
|
||||||
const activeTab = document.querySelector(`.tab-content[data-tab-id="${tabManager.activeTabId}"]`);
|
const activeTab = document.querySelector(`.tab-content[data-tab-id="${tabManager.activeTabId}"]`);
|
||||||
if (activeTab) activeTab.classList.add('active');
|
if (activeTab) activeTab.classList.add('active');
|
||||||
// Refresh the active tab
|
|
||||||
tabManager.updatePreview(tabManager.activeTabId);
|
tabManager.updatePreview(tabManager.activeTabId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -107,6 +107,105 @@ body {
|
|||||||
outline-offset: 2px;
|
outline-offset: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* PDF Tab Styles */
|
||||||
|
.tab.pdf-tab {
|
||||||
|
background: #e3f2fd;
|
||||||
|
border-color: #90caf9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab.pdf-tab.active {
|
||||||
|
background: #fff;
|
||||||
|
border-color: #1976d2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab.pdf-tab .tab-title {
|
||||||
|
color: #1565c0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* PDF Tab Container */
|
||||||
|
.pdf-tab-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
height: 100%;
|
||||||
|
background: var(--bg-primary, #fff);
|
||||||
|
}
|
||||||
|
|
||||||
|
.pdf-tab-container .pdf-controls {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
padding: 8px 16px;
|
||||||
|
background: #f5f5f5;
|
||||||
|
border-bottom: 1px solid #ddd;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pdf-tab-container .pdf-nav-btn,
|
||||||
|
.pdf-tab-container .pdf-zoom-btn,
|
||||||
|
.pdf-tab-container .pdf-rotate-btn {
|
||||||
|
background: #fff;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
border-radius: 4px;
|
||||||
|
padding: 4px 8px;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 14px;
|
||||||
|
min-width: 28px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pdf-tab-container .pdf-nav-btn:hover,
|
||||||
|
.pdf-tab-container .pdf-zoom-btn:hover,
|
||||||
|
.pdf-tab-container .pdf-rotate-btn:hover {
|
||||||
|
background: #e0e0e0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pdf-tab-container .pdf-page-input {
|
||||||
|
width: 50px;
|
||||||
|
text-align: center;
|
||||||
|
padding: 4px;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pdf-tab-container .pdf-page-info {
|
||||||
|
color: #666;
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pdf-tab-container .pdf-zoom-level {
|
||||||
|
min-width: 50px;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 13px;
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pdf-tab-container .pdf-canvas-container {
|
||||||
|
flex: 1;
|
||||||
|
overflow: auto;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 20px;
|
||||||
|
background: #525659;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pdf-tab-container .pdf-canvas-container canvas {
|
||||||
|
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Dark theme PDF tab */
|
||||||
|
body.dark .tab.pdf-tab {
|
||||||
|
background: #1a237e;
|
||||||
|
border-color: #3949ab;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.dark .tab.pdf-tab .tab-title {
|
||||||
|
color: #90caf9;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.dark .pdf-tab-container .pdf-controls {
|
||||||
|
background: #2d2d2d;
|
||||||
|
border-color: #444;
|
||||||
|
}
|
||||||
|
|
||||||
/* Tab Content */
|
/* Tab Content */
|
||||||
.tab-content {
|
.tab-content {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|||||||
Reference in New Issue
Block a user