Integration with new changes - fix problems with icons

This commit is contained in:
Reece Browne 2025-08-25 18:12:48 +01:00
parent 9cdeb013e6
commit 5025e06289
4 changed files with 95 additions and 90 deletions

View File

@ -1,7 +1,6 @@
#!/usr/bin/env node
const { icons } = require('@iconify-json/material-symbols');
const { getIcons } = require('@iconify/utils');
const fs = require('fs');
const path = require('path');
@ -89,68 +88,73 @@ function scanForUsedIcons() {
return iconArray;
}
// Auto-detect used icons
const usedIcons = scanForUsedIcons();
// Main async function
async function main() {
// Auto-detect used icons
const usedIcons = scanForUsedIcons();
// Check if we need to regenerate (compare with existing)
const outputPath = path.join(__dirname, '..', 'src', 'assets', 'material-symbols-icons.json');
let needsRegeneration = true;
// Check if we need to regenerate (compare with existing)
const outputPath = path.join(__dirname, '..', 'src', 'assets', 'material-symbols-icons.json');
let needsRegeneration = true;
if (fs.existsSync(outputPath)) {
try {
const existingSet = JSON.parse(fs.readFileSync(outputPath, 'utf8'));
const existingIcons = Object.keys(existingSet.icons || {}).sort();
const currentIcons = [...usedIcons].sort();
if (JSON.stringify(existingIcons) === JSON.stringify(currentIcons)) {
needsRegeneration = false;
info(`✅ Icon set already up-to-date (${usedIcons.length} icons, ${Math.round(fs.statSync(outputPath).size / 1024)}KB)`);
if (fs.existsSync(outputPath)) {
try {
const existingSet = JSON.parse(fs.readFileSync(outputPath, 'utf8'));
const existingIcons = Object.keys(existingSet.icons || {}).sort();
const currentIcons = [...usedIcons].sort();
if (JSON.stringify(existingIcons) === JSON.stringify(currentIcons)) {
needsRegeneration = false;
info(`✅ Icon set already up-to-date (${usedIcons.length} icons, ${Math.round(fs.statSync(outputPath).size / 1024)}KB)`);
}
} catch (error) {
// If we can't parse existing file, regenerate
needsRegeneration = true;
}
} catch (error) {
// If we can't parse existing file, regenerate
needsRegeneration = true;
}
}
if (!needsRegeneration) {
info('🎉 No regeneration needed!');
process.exit(0);
}
if (!needsRegeneration) {
info('🎉 No regeneration needed!');
process.exit(0);
}
info(`🔍 Extracting ${usedIcons.length} icons from Material Symbols...`);
info(`🔍 Extracting ${usedIcons.length} icons from Material Symbols...`);
// Extract only our used icons from the full set
const extractedIcons = getIcons(icons, usedIcons);
// Dynamic import of ES module
const { getIcons } = await import('@iconify/utils');
// Extract only our used icons from the full set
const extractedIcons = getIcons(icons, usedIcons);
if (!extractedIcons) {
console.error('❌ Failed to extract icons');
process.exit(1);
}
if (!extractedIcons) {
console.error('❌ Failed to extract icons');
process.exit(1);
}
// Check for missing icons
const extractedIconNames = Object.keys(extractedIcons.icons || {});
const missingIcons = usedIcons.filter(icon => !extractedIconNames.includes(icon));
// Check for missing icons
const extractedIconNames = Object.keys(extractedIcons.icons || {});
const missingIcons = usedIcons.filter(icon => !extractedIconNames.includes(icon));
if (missingIcons.length > 0) {
info(`⚠️ Missing icons (${missingIcons.length}): ${missingIcons.join(', ')}`);
info('💡 These icons don\'t exist in Material Symbols. Please use available alternatives.');
}
if (missingIcons.length > 0) {
info(`⚠️ Missing icons (${missingIcons.length}): ${missingIcons.join(', ')}`);
info('💡 These icons don\'t exist in Material Symbols. Please use available alternatives.');
}
// Create output directory
const outputDir = path.join(__dirname, '..', 'src', 'assets');
if (!fs.existsSync(outputDir)) {
fs.mkdirSync(outputDir, { recursive: true });
}
// Create output directory
const outputDir = path.join(__dirname, '..', 'src', 'assets');
if (!fs.existsSync(outputDir)) {
fs.mkdirSync(outputDir, { recursive: true });
}
// Write the extracted icon set to a file (outputPath already defined above)
fs.writeFileSync(outputPath, JSON.stringify(extractedIcons, null, 2));
// Write the extracted icon set to a file (outputPath already defined above)
fs.writeFileSync(outputPath, JSON.stringify(extractedIcons, null, 2));
info(`✅ Successfully extracted ${Object.keys(extractedIcons.icons || {}).length} icons`);
info(`📦 Bundle size: ${Math.round(JSON.stringify(extractedIcons).length / 1024)}KB`);
info(`💾 Saved to: ${outputPath}`);
info(`✅ Successfully extracted ${Object.keys(extractedIcons.icons || {}).length} icons`);
info(`📦 Bundle size: ${Math.round(JSON.stringify(extractedIcons).length / 1024)}KB`);
info(`💾 Saved to: ${outputPath}`);
// Generate TypeScript types
const typesContent = `// Auto-generated icon types
// Generate TypeScript types
const typesContent = `// Auto-generated icon types
// This file is automatically generated by scripts/generate-icons.js
// Do not edit manually - changes will be overwritten
@ -168,8 +172,15 @@ declare const iconSet: IconSet;
export default iconSet;
`;
const typesPath = path.join(outputDir, 'material-symbols-icons.d.ts');
fs.writeFileSync(typesPath, typesContent);
const typesPath = path.join(outputDir, 'material-symbols-icons.d.ts');
fs.writeFileSync(typesPath, typesContent);
info(`📝 Generated types: ${typesPath}`);
info(`🎉 Icon extraction complete!`);
info(`📝 Generated types: ${typesPath}`);
info(`🎉 Icon extraction complete!`);
}
// Run the main function
main().catch(error => {
console.error('❌ Script failed:', error);
process.exit(1);
});

View File

@ -327,7 +327,22 @@ const PageEditor = ({
return sourceFiles.size > 0 ? sourceFiles : null;
}, [activeFileIds, selectors]);
// Helper function to generate proper filename for exports
const getExportFilename = useCallback((): string => {
if (activeFileIds.length <= 1) {
// Single file - use original name
return displayDocument?.name || 'document.pdf';
}
// Multiple files - use first file name with " (merged)" suffix
const firstFile = selectors.getFile(activeFileIds[0]);
if (firstFile) {
const baseName = firstFile.name.replace(/\.pdf$/i, '');
return `${baseName} (merged).pdf`;
}
return 'merged-document.pdf';
}, [activeFileIds, selectors, displayDocument]);
const onExportSelected = useCallback(async () => {
if (!displayDocument || selectedPageNumbers.length === 0) return;
@ -355,17 +370,18 @@ const PageEditor = ({
console.log('Exporting selected pages:', selectedPageNumbers, 'with DOM rotations applied');
const sourceFiles = getSourceFiles();
const exportFilename = getExportFilename();
const result = sourceFiles
? await pdfExportService.exportPDFMultiFile(
documentWithDOMState,
sourceFiles,
selectedPageIds,
{ selectedOnly: true, filename: documentWithDOMState.name }
{ selectedOnly: true, filename: exportFilename }
)
: await pdfExportService.exportPDF(
documentWithDOMState,
selectedPageIds,
{ selectedOnly: true, filename: documentWithDOMState.name }
{ selectedOnly: true, filename: exportFilename }
);
// Step 4: Download the result
@ -376,7 +392,7 @@ const PageEditor = ({
console.error('Export failed:', error);
setExportLoading(false);
}
}, [displayDocument, selectedPageNumbers, mergedPdfDocument, splitPositions, getSourceFiles]);
}, [displayDocument, selectedPageNumbers, mergedPdfDocument, splitPositions, getSourceFiles, getExportFilename]);
const onExportAll = useCallback(async () => {
if (!displayDocument) return;
@ -399,10 +415,11 @@ const PageEditor = ({
const filenames: string[] = [];
const sourceFiles = getSourceFiles();
const exportFilename = getExportFilename();
for (const doc of processedDocuments) {
const result = sourceFiles
? await pdfExportService.exportPDFMultiFile(doc, sourceFiles, [], { filename: doc.name })
: await pdfExportService.exportPDF(doc, [], { filename: doc.name });
? await pdfExportService.exportPDFMultiFile(doc, sourceFiles, [], { filename: exportFilename })
: await pdfExportService.exportPDF(doc, [], { filename: exportFilename });
blobs.push(result.blob);
filenames.push(result.filename);
}
@ -416,24 +433,25 @@ const PageEditor = ({
});
const zipBlob = await zip.generateAsync({ type: 'blob' });
const zipFilename = displayDocument.name.replace(/\.pdf$/i, '.zip');
const zipFilename = exportFilename.replace(/\.pdf$/i, '.zip');
pdfExportService.downloadFile(zipBlob, zipFilename);
} else {
// Single document - regular export
console.log('Exporting as single PDF');
const sourceFiles = getSourceFiles();
const exportFilename = getExportFilename();
const result = sourceFiles
? await pdfExportService.exportPDFMultiFile(
processedDocuments,
sourceFiles,
[],
{ selectedOnly: false, filename: processedDocuments.name }
{ selectedOnly: false, filename: exportFilename }
)
: await pdfExportService.exportPDF(
processedDocuments,
[],
{ selectedOnly: false, filename: processedDocuments.name }
{ selectedOnly: false, filename: exportFilename }
);
pdfExportService.downloadFile(result.blob, result.filename);
@ -444,7 +462,7 @@ const PageEditor = ({
console.error('Export failed:', error);
setExportLoading(false);
}
}, [displayDocument, mergedPdfDocument, splitPositions, getSourceFiles]);
}, [displayDocument, mergedPdfDocument, splitPositions, getSourceFiles, getExportFilename]);
// Apply DOM changes to document state using dedicated service
const applyChanges = useCallback(() => {
@ -543,32 +561,6 @@ const PageEditor = ({
{displayDocument && (
<Box ref={gridContainerRef} p={0} style={{ position: 'relative' }}>
{/* File name and basic controls */}
<Group mb="md" p="md" justify="space-between">
<TextInput
placeholder="Enter filename"
defaultValue={displayDocument.name.replace(/\.pdf$/i, '')}
style={{ minWidth: 300 }}
/>
<Group>
<Button
variant={selectionMode ? "filled" : "outline"}
onClick={() => setSelectionMode(!selectionMode)}
>
{selectionMode ? "Exit Selection" : "Select Pages"}
</Button>
{selectionMode && (
<>
<Button variant="outline" onClick={() => toggleSelectAll(displayDocument?.pages.length || 0)}>
{selectedPageNumbers.length === displayDocument.pages.length ? "Deselect All" : "Select All"}
</Button>
<Text size="sm" c="dimmed">
{selectedPageNumbers.length} selected
</Text>
</>
)}
</Group>
</Group>
{/* Split Lines Overlay */}

View File

@ -31,7 +31,7 @@ export class PDFExportService {
const originalPDFBytes = await pdfDocument.file.arrayBuffer();
const sourceDoc = await PDFLibDocument.load(originalPDFBytes);
const blob = await this.createSingleDocument(sourceDoc, pagesToExport);
const exportFilename = this.generateFilename(filename || pdfDocument.name, selectedOnly);
const exportFilename = this.generateFilename(filename || pdfDocument.name, selectedOnly, false);
return { blob, filename: exportFilename };
} catch (error) {
@ -62,7 +62,7 @@ export class PDFExportService {
}
const blob = await this.createMultiSourceDocument(sourceFiles, pagesToExport);
const exportFilename = this.generateFilename(filename || pdfDocument.name, selectedOnly);
const exportFilename = this.generateFilename(filename || pdfDocument.name, selectedOnly, false);
return { blob, filename: exportFilename };
} catch (error) {

View File

@ -51,6 +51,8 @@ export interface PageEditorFunctions {
handleDelete: () => void;
handleSplit: () => void;
handleSplitAll: () => void;
handlePageBreak: () => void;
handlePageBreakAll: () => void;
onExportSelected: () => void;
onExportAll: () => void;
exportLoading: boolean;