Files
SPA-landing/symbols/js/app/core.js
architeur d707c5001d 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>
2025-12-14 21:34:03 +01:00

147 lines
4.9 KiB
JavaScript

// ============================================
// CORE - Initialisierung und Rendering
// Gutachter Symbolbibliothek v2.0
// ============================================
// ========== GLOBALE VARIABLEN ==========
let currentFilter = 'all';
let currentSearch = '';
let selectedSymbols = new Set();
let legendItems = [];
// ========== INITIALISIERUNG ==========
document.addEventListener('DOMContentLoaded', function() {
renderSymbols();
setupEventListeners();
loadLegendFromStorage();
});
// ========== EVENT LISTENERS ==========
function setupEventListeners() {
// Suche
document.getElementById('searchInput').addEventListener('input', function(e) {
currentSearch = e.target.value.toLowerCase();
renderSymbols();
});
// Filter Pills
document.querySelectorAll('.filter-pill').forEach(pill => {
pill.addEventListener('click', function() {
document.querySelectorAll('.filter-pill').forEach(p => p.classList.remove('active'));
this.classList.add('active');
currentFilter = this.dataset.filter;
renderSymbols();
});
});
// Modal schließen
document.getElementById('legendModal').addEventListener('click', function(e) {
if (e.target === this) {
closeLegendModal();
}
});
// Escape-Taste zum Schließen
document.addEventListener('keydown', function(e) {
if (e.key === 'Escape') {
closeLegendModal();
}
});
}
// ========== SYMBOLE RENDERN ==========
function renderSymbols() {
const container = document.getElementById('symbolGrid');
container.innerHTML = '';
let hasResults = false;
Object.keys(SYMBOLS).forEach(categoryKey => {
const category = SYMBOLS[categoryKey];
// Filter nach Kategorie
if (currentFilter !== 'all' && currentFilter !== categoryKey) {
return;
}
const filteredItems = category.items.filter(item => {
if (!currentSearch) return true;
return item.name.toLowerCase().includes(currentSearch) ||
item.tags.some(tag => tag.toLowerCase().includes(currentSearch));
});
if (filteredItems.length === 0) return;
hasResults = true;
// Kategorie-Header
const categoryHeader = document.createElement('div');
categoryHeader.className = 'category-header';
categoryHeader.innerHTML = `<span>${category.icon} ${category.name}</span><span class="category-count">${filteredItems.length} Symbole</span>`;
container.appendChild(categoryHeader);
// Symbol-Grid für diese Kategorie
const categoryGrid = document.createElement('div');
categoryGrid.className = 'category-grid';
filteredItems.forEach(item => {
const card = createSymbolCard(item, categoryKey);
categoryGrid.appendChild(card);
});
container.appendChild(categoryGrid);
});
if (!hasResults) {
container.innerHTML = '<div class="no-results">Keine Symbole gefunden. Versuchen Sie einen anderen Suchbegriff.</div>';
}
}
// ========== SYMBOL-KARTE ERSTELLEN ==========
function createSymbolCard(item, categoryKey) {
const card = document.createElement('div');
card.className = 'symbol-card';
// Spezielle Klasse für Vermessungssymbole
if (categoryKey.startsWith('vermessung_')) {
card.classList.add('vermessung');
}
const isSelected = selectedSymbols.has(item.id);
if (isSelected) {
card.classList.add('selected');
}
card.innerHTML = `
<div class="symbol-preview">${item.svg}</div>
<div class="symbol-name">${item.name}</div>
<div class="symbol-actions">
<button class="btn-action btn-copy" onclick="copyAsImage('${item.id}')" title="Als Bild kopieren (transparent)">
📋 Kopieren
</button>
<button class="btn-action btn-svg" onclick="downloadSVG('${item.id}')" title="SVG herunterladen">
⬇️ SVG
</button>
<button class="btn-action btn-png" onclick="downloadSymbolPNG('${item.id}')" title="PNG herunterladen">PNG</button>
<button class="btn-action btn-jpg" onclick="downloadSymbolJPG('${item.id}')" title="JPG herunterladen">JPG</button>
<button class="btn-action btn-dxf" onclick="downloadDXF('${item.id}')" title="DXF herunterladen">
📐 DXF
</button>
<button class="btn-action btn-legend ${isSelected ? 'active' : ''}" onclick="toggleLegendSelection('${item.id}')" title="Zur Legende hinzufügen">
📑
</button>
</div>
`;
return card;
}
// ========== SYMBOL FINDEN ==========
function findSymbol(id) {
for (const categoryKey of Object.keys(SYMBOLS)) {
const item = SYMBOLS[categoryKey].items.find(i => i.id === id);
if (item) return item;
}
return null;
}