Refactor symbols app: split large files (max 300 lines)

- Split styles.css (1319 lines) into 6 CSS modules:
  - base.css, layout.css, modal.css, text-generator.css, components.css, legend.css
- Split app.js (1219 lines) into 8 JS modules:
  - core.js, custom.js, dxf.js, export.js, legend.js, legend-export.js, path-parser.js, utils.js
- Split symbols.js (870 lines) into 10 JS modules:
  - index.js, schaeden.js, werkzeuge.js, bauteile.js, moebel.js, sanitaer.js, vermessung.js, vermessung-infra.js, vermessung-topo.js, init.js
- Updated index.html to load new modular files

All files now comply with 300-line maximum rule.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
architeur
2025-12-14 21:34:03 +01:00
parent c0ae55a597
commit d707c5001d
28 changed files with 3514 additions and 3411 deletions

View File

@@ -0,0 +1,104 @@
// ============================================
// LEGEND EXPORT - Legenden SVG/PNG Export
// ============================================
function exportLegendSVG() {
if (legendItems.length === 0) {
showNotification('Legende ist leer', 'error');
return;
}
const itemHeight = 50;
const width = 400;
const height = legendItems.length * itemHeight + 60;
let svg = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ${width} ${height}" width="${width}" height="${height}">
<rect width="${width}" height="${height}" fill="white"/>
<text x="20" y="30" font-family="Arial" font-size="18" font-weight="bold">Legende</text>
<line x1="20" y1="40" x2="${width - 20}" y2="40" stroke="#ccc" stroke-width="1"/>`;
legendItems.forEach((item, index) => {
const y = 60 + index * itemHeight;
svg += `<g transform="translate(20, ${y})">
<g transform="scale(0.5)">${item.svg.replace(/<svg[^>]*>/, '').replace('</svg>', '')}</g>
<text x="50" y="20" font-family="Arial" font-size="14" font-weight="bold">${escapeHtml(item.name)}</text>
${item.description ? `<text x="50" y="35" font-family="Arial" font-size="11" fill="#666">${escapeHtml(item.description)}</text>` : ''}
</g>`;
});
svg += '</svg>';
const blob = new Blob([svg], { type: 'image/svg+xml' });
const url = URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = url;
link.download = 'legende.svg';
link.click();
URL.revokeObjectURL(url);
showNotification('Legende als SVG exportiert!');
}
function exportLegendPNG() {
if (legendItems.length === 0) {
showNotification('Legende ist leer', 'error');
return;
}
const itemHeight = 50;
const width = 400;
const height = legendItems.length * itemHeight + 60;
const canvas = document.createElement('canvas');
canvas.width = width * 2;
canvas.height = height * 2;
const ctx = canvas.getContext('2d');
ctx.scale(2, 2);
ctx.fillRect(0, 0, width, height);
ctx.fillStyle = '#000';
ctx.font = 'bold 18px Arial';
ctx.fillText('Legende', 20, 30);
ctx.strokeStyle = '#ccc';
ctx.beginPath();
ctx.moveTo(20, 40);
ctx.lineTo(width - 20, 40);
ctx.stroke();
let loadedCount = 0;
legendItems.forEach((item, index) => {
const y = 60 + index * itemHeight;
const img = new Image();
const svgBlob = new Blob([item.svg], { type: 'image/svg+xml' });
img.src = URL.createObjectURL(svgBlob);
img.onload = () => {
ctx.drawImage(img, 20, y - 5, 32, 32);
ctx.fillStyle = '#000';
ctx.font = 'bold 14px Arial';
ctx.fillText(item.name, 60, y + 15);
if (item.description) {
ctx.fillStyle = '#666';
ctx.font = '11px Arial';
ctx.fillText(item.description, 60, y + 30);
}
loadedCount++;
if (loadedCount === legendItems.length) {
canvas.toBlob(blob => {
const url = URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = url;
link.download = 'legende.png';
link.click();
URL.revokeObjectURL(url);
showNotification('Legende als PNG exportiert!');
}, 'image/png');
}
};
});
}