@sequent-org/moodboard 1.2.60 → 1.2.62

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sequent-org/moodboard",
3
- "version": "1.2.60",
3
+ "version": "1.2.62",
4
4
  "type": "module",
5
5
  "description": "Interactive moodboard",
6
6
  "main": "./src/index.js",
@@ -17,46 +17,33 @@ export class DataManager {
17
17
  // Очищаем доску перед загрузкой
18
18
  this.clearBoard();
19
19
 
20
- // Восстанавливаем тип сетки и её параметры до загрузки объектов
20
+ // Применяем settings централизованно (если есть апплаер), иначе старым способом
21
21
  try {
22
- const grid = (data.settings && data.settings.grid) || data.grid || (data.board && data.board.grid);
23
- if (grid && grid.type) {
24
- const payload = { type: grid.type };
25
- const opts = grid.options || null;
26
- if (opts && typeof opts === 'object') {
27
- payload.options = opts;
22
+ if (this.coreMoodboard?.settingsApplier && data.settings) {
23
+ this.coreMoodboard.settingsApplier.apply(data.settings);
24
+ } else {
25
+ // fallback оставлен для совместимости (если где-то аплеер не создан)
26
+ const grid = (data.settings && data.settings.grid) || data.grid || (data.board && data.board.grid);
27
+ if (grid && grid.type) {
28
+ const payload = { type: grid.type };
29
+ const opts = grid.options || null;
30
+ if (opts && typeof opts === 'object') payload.options = opts;
31
+ this.coreMoodboard.eventBus.emit(this.coreMoodboard.Events?.UI?.GridChange || 'ui:grid:change', payload);
32
+ }
33
+ const settings = data.settings || {};
34
+ const bg = settings.backgroundColor;
35
+ if (bg && this.coreMoodboard?.pixi?.app?.renderer) {
36
+ const s = typeof bg === 'string' ? (bg.startsWith('#') ? bg.slice(1) : bg) : null;
37
+ const bgInt = typeof bg === 'number' ? bg : (s ? parseInt(s, 16) : null);
38
+ if (bgInt != null) this.coreMoodboard.pixi.app.renderer.backgroundColor = bgInt;
39
+ }
40
+ const z = settings.zoom && (settings.zoom.current || settings.zoom.default);
41
+ const world = this.coreMoodboard?.pixi?.worldLayer || this.coreMoodboard?.pixi?.app?.stage;
42
+ if (world && Number.isFinite(z) && z > 0) {
43
+ world.scale.set(z);
44
+ const percent = Math.round(z * 100);
45
+ try { this.coreMoodboard.eventBus.emit('ui:zoom:percent', { percentage: percent }); } catch (_) {}
28
46
  }
29
- this.coreMoodboard.eventBus.emit(this.coreMoodboard.Events?.UI?.GridChange || 'ui:grid:change', payload);
30
- }
31
- } catch (_) {}
32
-
33
- // Восстановим фон и зум из settings, если есть
34
- try {
35
- const settings = data.settings || {};
36
- // Фон
37
- const bg = settings.backgroundColor;
38
- if (bg && this.coreMoodboard?.pixi?.app?.renderer) {
39
- const parseHex = (v) => {
40
- if (typeof v === 'number') return v;
41
- if (typeof v === 'string') {
42
- const s = v.startsWith('#') ? v.slice(1) : v;
43
- const n = parseInt(s, 16);
44
- if (Number.isFinite(n)) return n;
45
- }
46
- return null;
47
- };
48
- const bgInt = parseHex(bg);
49
- if (bgInt != null) this.coreMoodboard.pixi.app.renderer.backgroundColor = bgInt;
50
- }
51
- // Зум
52
- const z = settings.zoom && (settings.zoom.current || settings.zoom.default);
53
- const world = this.coreMoodboard?.pixi?.worldLayer || this.coreMoodboard?.pixi?.app?.stage;
54
- if (world && Number.isFinite(z) && z > 0) {
55
- world.scale.set(z);
56
- const percent = Math.round(z * 100);
57
- try {
58
- this.coreMoodboard.eventBus.emit('ui:zoom:percent', { percentage: percent });
59
- } catch (_) {}
60
47
  }
61
48
  } catch (_) {}
62
49
 
@@ -18,6 +18,7 @@ import { NotePropertiesPanel } from '../ui/NotePropertiesPanel.js';
18
18
  import { FilePropertiesPanel } from '../ui/FilePropertiesPanel.js';
19
19
  import { AlignmentGuides } from '../tools/AlignmentGuides.js';
20
20
  import { ImageUploadService } from '../services/ImageUploadService.js';
21
+ import { SettingsApplier } from '../services/SettingsApplier.js';
21
22
 
22
23
  /**
23
24
  * Готовый MoodBoard с UI - главный класс пакета
@@ -84,6 +85,15 @@ export class MoodBoard {
84
85
  // Инициализируем CoreMoodBoard
85
86
  await this.initCoreMoodBoard();
86
87
 
88
+ // Настройки (единая точка применения)
89
+ this.settingsApplier = new SettingsApplier(
90
+ this.coreMoodboard.eventBus,
91
+ this.coreMoodboard.pixi,
92
+ this.coreMoodboard.boardService || null
93
+ );
94
+ // Делаем доступным для других подсистем
95
+ this.coreMoodboard.settingsApplier = this.settingsApplier;
96
+
87
97
  // Создаем менеджеры
88
98
  this.dataManager = new DataManager(this.coreMoodboard);
89
99
  this.actionHandler = new ActionHandler(this.dataManager, this.workspaceManager);
@@ -131,6 +141,10 @@ export class MoodBoard {
131
141
 
132
142
  // Предоставляем доступ к сервису через core
133
143
  this.coreMoodboard.imageUploadService = this.imageUploadService;
144
+ // Передаем ссылку на topbar в апплаер настроек для синхронизации UI
145
+ if (this.settingsApplier && this.topbar) {
146
+ this.settingsApplier.setUI({ topbar: this.topbar });
147
+ }
134
148
 
135
149
  // Настраиваем коллбеки событий
136
150
  this.setupEventCallbacks();
@@ -0,0 +1,97 @@
1
+ import { Events } from '../core/events/Events.js';
2
+
3
+ export class SettingsApplier {
4
+ constructor(eventBus, pixi, boardService = null, uiRefs = {}) {
5
+ this.eventBus = eventBus;
6
+ this.pixi = pixi;
7
+ this.boardService = boardService;
8
+ this.ui = uiRefs || {};
9
+ this.settings = {};
10
+ }
11
+
12
+ setUI(uiRefs = {}) {
13
+ this.ui = { ...this.ui, ...uiRefs };
14
+ }
15
+
16
+ set(partial) {
17
+ this.settings = { ...this.settings, ...(partial || {}) };
18
+ this.apply(this.settings);
19
+ }
20
+
21
+ get() {
22
+ return { ...this.settings };
23
+ }
24
+
25
+ apply(settings = {}) {
26
+ this.settings = { ...this.settings, ...settings };
27
+ const s = this.settings;
28
+
29
+ // 1) Фон
30
+ if (s.backgroundColor && this.pixi?.app?.renderer) {
31
+ const bgInt = this._toIntColor(s.backgroundColor);
32
+ if (bgInt != null) this.pixi.app.renderer.backgroundColor = bgInt;
33
+ // Синхронизация UI цвета (если доступен topbar)
34
+ if (this.ui.topbar) {
35
+ try {
36
+ const boardHex = this._toHex(bgInt);
37
+ this.ui.topbar.setCurrentBoardHex(boardHex);
38
+ } catch (_) {}
39
+ }
40
+ }
41
+
42
+ // 2) Сетка
43
+ if (s.grid && s.grid.type) {
44
+ try {
45
+ const payload = { type: s.grid.type };
46
+ // Пробрасываем дополнительные опции, если есть
47
+ const options = s.grid.options || {
48
+ size: s.grid.size,
49
+ color: this._maybeInt(s.grid.color),
50
+ enabled: s.grid.visible !== false
51
+ };
52
+ if (options) payload.options = options;
53
+ this.eventBus.emit(Events.UI.GridChange, payload);
54
+ if (this.ui.topbar && s.grid.type) {
55
+ this.ui.topbar.setActive(s.grid.type);
56
+ }
57
+ } catch (_) {}
58
+ }
59
+
60
+ // 3) Зум
61
+ if (s.zoom && (typeof s.zoom.current === 'number')) {
62
+ const world = this.pixi?.worldLayer || this.pixi?.app?.stage;
63
+ if (world) {
64
+ const z = Math.max(0.1, Math.min(5, s.zoom.current));
65
+ world.scale.set(z);
66
+ try { this.eventBus.emit(Events.UI.ZoomPercent, { percentage: Math.round(z * 100) }); } catch (_) {}
67
+ }
68
+ }
69
+ }
70
+
71
+ _toIntColor(hexOrInt) {
72
+ if (typeof hexOrInt === 'number') return hexOrInt;
73
+ if (typeof hexOrInt === 'string') {
74
+ const s = hexOrInt.startsWith('#') ? hexOrInt.slice(1) : hexOrInt;
75
+ const n = parseInt(s, 16);
76
+ return Number.isFinite(n) ? n : null;
77
+ }
78
+ return null;
79
+ }
80
+
81
+ _maybeInt(v) {
82
+ if (v == null) return v;
83
+ if (typeof v === 'number') return v;
84
+ if (typeof v === 'string') {
85
+ const s = v.startsWith('#') ? v.slice(1) : v;
86
+ const n = parseInt(s, 16);
87
+ return Number.isFinite(n) ? n : v;
88
+ }
89
+ return v;
90
+ }
91
+
92
+ _toHex(intColor) {
93
+ try { return `#${(intColor >>> 0).toString(16).padStart(6, '0')}`.toLowerCase(); } catch (_) { return '#f5f5f5'; }
94
+ }
95
+ }
96
+
97
+
package/src/ui/Topbar.js CHANGED
@@ -37,7 +37,7 @@ export class Topbar {
37
37
  this.createTopbar();
38
38
  this.attachEvents();
39
39
  // Активируем дефолтную кнопку (line) до прихода события из ядра
40
- this.setActive('line');
40
+ // не подсвечиваем дефолт до прихода актуального типа из ядра
41
41
 
42
42
  // Синхронизация активного состояния по событию из ядра
43
43
  this.eventBus.on(Events.UI.GridCurrent, ({ type }) => {
@@ -50,11 +50,13 @@ export class Topbar {
50
50
  this.setPaintButtonHex(btnHex);
51
51
  });
52
52
 
53
- // Инициализация цвета кнопки "краска" из текущего фона доски, если доступен
53
+ // Инициализация цвета кнопки "краска" из настроек (или фона рендерера)
54
54
  try {
55
- const bgHex = this._getCurrentBoardBackgroundHex();
55
+ const ap = window?.moodboard?.coreMoodboard?.settingsApplier;
56
+ const bgHex = (ap && ap.get && ap.get().backgroundColor) || this._getCurrentBoardBackgroundHex();
56
57
  if (bgHex) {
57
- const mapped = this.mapBoardToBtnHex(bgHex);
58
+ this._currentBoardHex = String(bgHex).toLowerCase();
59
+ const mapped = this.mapBoardToBtnHex(this._currentBoardHex);
58
60
  this.setPaintButtonHex(mapped);
59
61
  }
60
62
  } catch (_) {}
@@ -178,7 +180,7 @@ export class Topbar {
178
180
  /** Возвращает текущий цвет фона канваса как hex-строку #RRGGBB */
179
181
  _getCurrentBoardBackgroundHex() {
180
182
  try {
181
- const app = window?.moodboard?.core?.pixi?.app;
183
+ const app = window?.moodboard?.coreMoodboard?.pixi?.app || window?.moodboard?.core?.pixi?.app;
182
184
  const colorInt = app?.renderer?.background?.color ?? app?.renderer?.backgroundColor;
183
185
  if (typeof colorInt !== 'number') return null;
184
186
  const hex = `#${colorInt.toString(16).padStart(6, '0')}`;
@@ -255,8 +257,9 @@ export class Topbar {
255
257
  b.style.borderColor = darken(c.hex, 0.35);
256
258
  // Цвет галочки — чёрный для максимальной видимости
257
259
  b.style.color = '#111';
258
- // Для надёжного сравнения — сохраняем исходный hex в dataset
260
+ // Для надёжного сравнения — сохраняем оба значения в dataset
259
261
  b.dataset.hex = String(c.hex).toLowerCase();
262
+ b.dataset.board = String(c.board).toLowerCase();
260
263
  // Галочка по центру
261
264
  const tick = document.createElement('i');
262
265
  tick.className = 'moodboard-topbar__paint-tick';
@@ -279,11 +282,16 @@ export class Topbar {
279
282
  });
280
283
  pop.appendChild(grid);
281
284
 
282
- // Выделяем активный цвет галочкой
285
+ // Выделяем активный цвет галочкой по фактическому boardHex
283
286
  try {
284
- const boardHex = this._getCurrentBoardBackgroundHex();
285
- const targetHex = (this.mapBoardToBtnHex(boardHex) || '#B3E5FC').toLowerCase();
286
- const match = grid.querySelector(`[data-hex="${targetHex}"]`);
287
+ const ap = window?.moodboard?.coreMoodboard?.settingsApplier;
288
+ const boardHex = (
289
+ (ap && ap.get && ap.get().backgroundColor) ||
290
+ this._currentBoardHex ||
291
+ this._getCurrentBoardBackgroundHex() ||
292
+ ''
293
+ ).toLowerCase();
294
+ const match = boardHex ? grid.querySelector(`[data-board="${boardHex}"]`) : null;
287
295
  if (match) match.classList.add('is-active');
288
296
  } catch (_) {}
289
297
 
@@ -293,16 +301,7 @@ export class Topbar {
293
301
  pop.style.left = `${rect.left - this.element.getBoundingClientRect().left}px`;
294
302
  pop.style.top = `${rect.bottom - this.element.getBoundingClientRect().top + 6}px`;
295
303
 
296
- // Подсветить текущий активный кружок галочкой)
297
- try {
298
- const currentBtnHex = (this._paintBtn && getComputedStyle(this._paintBtn).getPropertyValue('--paint-btn-color')) || '';
299
- const normalized = currentBtnHex.trim() || '#B3E5FC';
300
- const match = Array.from(grid.children).find((el) => {
301
- const bg = el && el.style && el.style.background ? el.style.background.toLowerCase() : '';
302
- return bg === normalized.toLowerCase();
303
- });
304
- if (match) match.classList.add('is-active');
305
- } catch (_) {}
304
+ // (дополнительная подсветка не требуется см. блок выше)
306
305
 
307
306
  this.element.appendChild(pop);
308
307
  this._paintPopover = pop;