/
Gabryelf
/
Icons-Customize-Gen
Обзор
Документация
Войти
/
Gabryelf
/
Icons-Customize-Gen
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
js/views/EditorView.js
307 строк
11 KB
Valeev Serj
exp_version_0.0.1-->0.02
17 июл 2026, 00:16
17 июл 2026, 00:16
6c659ac
Код
Авторство
О чём код?
// views/EditorView.js import { Project } from '../models/Project.js'; import { CanvasService } from '../services/CanvasService.js'; import { IconLibraryService } from '../services/IconLibraryService.js'; import { LayerController } from '../controllers/LayerController.js'; import { SettingsController } from '../controllers/SettingsController.js'; import { DragController } from '../controllers/DragController.js'; import { LayerView } from './LayerView.js'; import { ToolbarView } from './ToolbarView.js'; import { HistoryController } from '../core/HistoryController.js'; import { Storage } from '../core/Storage.js'; import { generateProjectName } from '../utils/nameGenerator.js'; export class EditorView { constructor(container, eventBus, data = {}) { this.container = container; this.events = eventBus; this.projectId = data.projectId || null; this.project = null; this.canvasService = null; this.layerController = null; this.history = null; this.settingsController = null; this.dragController = null; this.layerView = null; this.toolbarView = null; } render() { // Получаем проект для отображения названия const projectName = this.loadProjectName(); this.container.innerHTML = ` <header class="app-header" id="appHeader"> <div class="logo"> ✦ IconForge <small>· конструктор</small> </div> <div class="header-actions" id="toolbarContainer"> </div> </header> <div class="app-layout"> <aside class="sidebar" id="sidebar"> <div class="panel-section"> <div class="section-title"> <span>📚 Библиотека</span> <span class="badge" id="iconCount">0</span> </div> <div class="icon-grid" id="iconGrid"></div> </div> <div class="panel-section"> <div class="section-title"> <span>🎛 Настройки</span> <span class="badge" id="selectedLabel">не выбран</span> </div> <div class="param-group" id="paramGroup"></div> </div> <div class="panel-section" style="flex:1;min-height:0;"> <div class="section-title"> <span>🧩 Слои</span> <span class="badge" id="layerCount">0</span> </div> <div class="layer-list" id="layerList"></div> <button class="btn-add-layer" id="btnAddLayer">+ Добавить слой</button> </div> </aside> <div class="canvas-container" id="canvasContainer"> <div class="canvas-wrapper" id="canvasWrapper"> <canvas id="canvas" width="600" height="600"></canvas> <div class="project-name-editor" id="projectNameEditor"> <span id="projectNameDisplay">${projectName || 'Новый проект'}</span> <button id="btnRenameProject" title="Переименовать проект">✎</button> </div> </div> <div class="canvas-hint" id="canvasHint">✧ Перетащите иконку из библиотеки или кликните для добавления</div> </div> </div> `; setTimeout(() => this.initEditor(), 50); } loadProjectName() { if (this.projectId) { const data = Storage.loadProject(this.projectId); if (data && data.meta && data.meta.name) { return data.meta.name; } } return generateProjectName(); } initEditor() { const canvas = document.getElementById('canvas'); if (!canvas) { console.error('Canvas не найден'); return; } this.project = this.loadProject(); // Если проект без имени - генерируем if (!this.project.name || this.project.name === 'Новый проект') { this.project.name = generateProjectName(); } // Обновляем отображение имени this.updateProjectNameDisplay(); this.canvasService = new CanvasService(canvas); this.canvasService.resize(this.project.width, this.project.height); this.iconLibrary = new IconLibraryService(); this.layerController = new LayerController(this.project, this.events); this.history = new HistoryController(this.project, this.events); this.settingsController = new SettingsController(this.layerController, this.events); this.dragController = new DragController(this.canvasService, this.layerController, this.events); this.layerView = new LayerView(this.layerController, this.events); this.toolbarView = new ToolbarView( this.project, this.canvasService, this.history, this.events, this.projectId ); this.initUI(); this.bindEvents(); this.renderCanvas(); this.updateCanvasSize(); this.showHint(); console.log('✏️ Редактор запущен!'); } updateProjectNameDisplay() { const display = document.getElementById('projectNameDisplay'); if (display) { display.textContent = this.project.name; } } loadProject() { if (this.projectId) { const data = Storage.loadProject(this.projectId); if (data && data.project) { const project = Project.fromJSON(data.project); if (data.meta && data.meta.name) { project.name = data.meta.name; } return project; } } const project = new Project(); project.name = generateProjectName(); const demo = { src: 'assets/icons/star.svg', x: 300, y: 300, width: 80, height: 80, name: 'Звезда' }; project.addLayer(demo); return project; } initUI() { const grid = document.getElementById('iconGrid'); if (!grid) return; const icons = this.iconLibrary.getIcons(); const countEl = document.getElementById('iconCount'); if (countEl) countEl.textContent = icons.length; const shown = icons.slice(0, 25); grid.innerHTML = shown.map(icon => ` <div class="icon-item" data-src="${icon.src}" title="${icon.name}"> <img src="${icon.src}" alt="${icon.name}" loading="lazy" /> <span class="icon-label">${icon.name}</span> </div> `).join(''); grid.querySelectorAll('.icon-item').forEach(el => { el.addEventListener('click', () => { const src = el.dataset.src; const name = el.title || 'Иконка'; this.layerController.add({ src: src, x: this.canvasService.width / 2 + (Math.random() - 0.5) * 80, y: this.canvasService.height / 2 + (Math.random() - 0.5) * 80, width: 64, height: 64, opacity: 100, name: name, }); this.hideHint(); }); }); } bindEvents() { this.events.on('project:changed', () => this.renderCanvas()); this.events.on('project:restored', () => this.renderCanvas()); window.addEventListener('resize', () => this.updateCanvasSize()); const canvas = document.getElementById('canvas'); if (canvas) { canvas.addEventListener('dblclick', (e) => { const pos = this.canvasService.getMousePos(e); const icons = this.iconLibrary.getIcons(); const random = icons[Math.floor(Math.random() * icons.length)]; if (random) { this.layerController.add({ src: random.src, x: pos.x, y: pos.y, width: 56, height: 56, opacity: 100, name: random.name, }); this.hideHint(); } }); } // Переименование проекта const btnRename = document.getElementById('btnRenameProject'); if (btnRename) { btnRename.addEventListener('click', () => { const newName = prompt('Введите новое название проекта:', this.project.name); if (newName && newName.trim()) { this.project.name = newName.trim(); this.updateProjectNameDisplay(); this.events.emit('project:changed'); // Автосохранение при переименовании if (this.toolbarView) { this.toolbarView.saveProject(); } } }); } // Двойной клик по названию для переименования const display = document.getElementById('projectNameDisplay'); if (display) { display.addEventListener('dblclick', () => { const btnRename = document.getElementById('btnRenameProject'); if (btnRename) btnRename.click(); }); } } renderCanvas() { if (this.canvasService) { this.canvasService.render(this.project); } } updateCanvasSize() { const container = document.getElementById('canvasWrapper'); const canvas = document.getElementById('canvas'); if (!container || !canvas) return; const rect = container.parentElement.getBoundingClientRect(); const padding = 32; const maxW = rect.width - padding; const maxH = rect.height - padding; const size = Math.min(maxW, maxH, 800); const aspect = canvas.width / canvas.height; let displayW = size; let displayH = size / aspect; if (displayH > maxH) { displayH = maxH; displayW = displayH * aspect; } if (displayW > maxW) { displayW = maxW; displayH = displayW / aspect; } canvas.style.width = displayW + 'px'; canvas.style.height = displayH + 'px'; } showHint() { const hint = document.getElementById('canvasHint'); if (hint && this.project.layers.length === 0) { hint.classList.add('visible'); } } hideHint() { const hint = document.getElementById('canvasHint'); if (hint) { hint.classList.remove('visible'); } } }