@sequent-org/moodboard 1.2.71 → 1.2.73

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.71",
3
+ "version": "1.2.73",
4
4
  "type": "module",
5
5
  "description": "Interactive moodboard",
6
6
  "main": "./src/index.js",
package/src/core/index.js CHANGED
@@ -574,6 +574,13 @@ export class CoreMoodBoard {
574
574
  stage.x += delta.x;
575
575
  stage.y += delta.y;
576
576
  }
577
+ // Сообщаем системе об обновлении позиции мира для автосохранения
578
+ try {
579
+ const world = this.pixi.worldLayer || this.pixi.app.stage;
580
+ this.eventBus.emit(Events.Grid.BoardDataChanged, {
581
+ settings: { pan: { x: world.x || 0, y: world.y || 0 } }
582
+ });
583
+ } catch (_) {}
577
584
  });
578
585
 
579
586
  // Миникарта перенесена в BoardService
@@ -2167,6 +2174,10 @@ export class CoreMoodBoard {
2167
2174
  };
2168
2175
  const world = this.pixi?.worldLayer || app?.stage;
2169
2176
  const currentZoom = Math.max(0.1, Math.min(5, world?.scale?.x || 1));
2177
+ const currentPan = {
2178
+ x: (world?.x ?? 0),
2179
+ y: (world?.y ?? 0)
2180
+ };
2170
2181
  const canvasW = app?.view?.clientWidth || app?.view?.width || 0;
2171
2182
  const canvasH = app?.view?.clientHeight || app?.view?.height || 0;
2172
2183
 
@@ -2191,6 +2202,7 @@ export class CoreMoodBoard {
2191
2202
  backgroundColor: toHex(rendererBg ?? 0xF5F5F5),
2192
2203
  grid: gridSettings || undefined,
2193
2204
  zoom: { min: 0.1, max: 5.0, default: 1.0, current: currentZoom },
2205
+ pan: currentPan,
2194
2206
  canvas: { width: canvasW, height: canvasH }
2195
2207
  };
2196
2208
 
@@ -175,7 +175,9 @@ export class FileObject {
175
175
 
176
176
  // Иконка файла в верхней части
177
177
  const iconSize = Math.min(48, w * 0.4);
178
- const iconX = (w - iconSize) / 2;
178
+ // Центрируем фактическую ширину иконки (она рисуется как 80% от size)
179
+ const iconWidthDrawn = iconSize * 0.8;
180
+ const iconX = (w - iconWidthDrawn) / 2;
179
181
  const iconY = 16;
180
182
 
181
183
  // Определяем цвет иконки по расширению файла
@@ -236,21 +238,55 @@ export class FileObject {
236
238
 
237
239
  _updateTextPosition() {
238
240
  if (!this.fileNameText) return;
239
-
240
- // Обновляем стиль текста
241
- this.fileNameText.style.wordWrapWidth = this.width - 8;
241
+
242
+ // Обновляем стиль текста (ограничиваем по подложке и переносим слова)
243
+ this.fileNameText.style.wordWrap = true;
244
+ this.fileNameText.style.wordWrapWidth = Math.max(1, this.width - 16);
242
245
  this.fileNameText.updateText();
243
-
244
- // Позиционируем название файла
246
+
247
+ // Параметры иконки и отступов
248
+ const iconSize = Math.min(48, this.width * 0.4);
249
+ const iconY = 16;
250
+ const gapName = 8; // расстояние между иконкой и названием (уменьшено в 2 раза)
251
+ const gapSize = 6; // расстояние между названием и размером
252
+ const bottomPad = 10; // нижний внутренний отступ подложки
253
+
254
+ // Позиционируем название файла непосредственно под иконкой и по центру
245
255
  this.fileNameText.anchor.set(0.5, 0);
246
256
  this.fileNameText.x = this.width / 2;
247
- this.fileNameText.y = this.height - 40;
248
-
249
- // Позиционируем размер файла
257
+ this.fileNameText.y = iconY + iconSize + gapName;
258
+
259
+ // Позиционируем размер файла под названием
250
260
  if (this.fileSizeText) {
251
261
  this.fileSizeText.anchor.set(0.5, 0);
252
262
  this.fileSizeText.x = this.width / 2;
253
- this.fileSizeText.y = this.height - 20;
263
+ this.fileSizeText.y = this.fileNameText.y + this.fileNameText.height + gapSize;
264
+ }
265
+
266
+ // Адаптивная высота подложки: не даём текстам выходить за пределы
267
+ const contentBottom = this.fileSizeText
268
+ ? (this.fileSizeText.y + this.fileSizeText.height)
269
+ : (this.fileNameText.y + this.fileNameText.height);
270
+ const requiredHeight = Math.ceil(contentBottom + bottomPad);
271
+ if (requiredHeight > this.height) {
272
+ const previous = this.height;
273
+ this.height = requiredHeight;
274
+ // Перерисовываем фон и иконку под новую высоту
275
+ this._redraw();
276
+ // Повторно позиционируем тексты (одноразово)
277
+ if (this.height !== previous) {
278
+ // Предотвращаем возможную рекурсию: вторая установка не должна дальше менять высоту
279
+ this.fileNameText.style.wordWrapWidth = Math.max(1, this.width - 16);
280
+ this.fileNameText.updateText();
281
+ this.fileNameText.anchor.set(0.5, 0);
282
+ this.fileNameText.x = this.width / 2;
283
+ this.fileNameText.y = iconY + iconSize + gapName;
284
+ if (this.fileSizeText) {
285
+ this.fileSizeText.anchor.set(0.5, 0);
286
+ this.fileSizeText.x = this.width / 2;
287
+ this.fileSizeText.y = this.fileNameText.y + this.fileNameText.height + gapSize;
288
+ }
289
+ }
254
290
  }
255
291
  }
256
292
 
@@ -70,6 +70,16 @@ export class SettingsApplier {
70
70
  try { this.eventBus.emit(Events.UI.ZoomPercent, { percentage: Math.round(z * 100) }); } catch (_) {}
71
71
  }
72
72
  }
73
+
74
+ // 4) Панорамирование (позиция мира)
75
+ if (s.pan && typeof s.pan.x === 'number' && typeof s.pan.y === 'number') {
76
+ const world = this.pixi?.worldLayer || this.pixi?.app?.stage;
77
+ if (world) {
78
+ world.x = s.pan.x;
79
+ world.y = s.pan.y;
80
+ // Обновление зависимых слоёв/панелей выполняется по их событиям; здесь только применяем позицию
81
+ }
82
+ }
73
83
  }
74
84
 
75
85
  _toIntColor(hexOrInt) {
@@ -592,28 +592,30 @@ export class PlacementTool extends BaseTool {
592
592
  background.drawRect(0, 0, width, height);
593
593
  background.endFill();
594
594
 
595
- // Иконка-заглушка файла наверху
595
+ // Иконка-заглушка файла наверху (центрируем фактическую ширину)
596
596
  const icon = new PIXI.Graphics();
597
597
  const iconSize = Math.min(48, width * 0.4);
598
- const iconX = (width - iconSize) / 2;
598
+ const iconWidthDrawn = iconSize * 0.8;
599
+ const iconX = (width - iconWidthDrawn) / 2;
599
600
  const iconY = 16;
600
601
  icon.beginFill(0x6B7280, 1);
601
- icon.drawRect(iconX, iconY, iconSize * 0.8, iconSize);
602
+ icon.drawRect(iconX, iconY, iconWidthDrawn, iconSize);
602
603
  icon.endFill();
603
604
 
604
605
  // Текст названия файла
605
606
  const fileName = this.selectedFile.fileName || 'File';
606
- const displayName = fileName.length > 15 ? fileName.substring(0, 12) + '...' : fileName;
607
+ const displayName = fileName;
607
608
  const nameText = new PIXI.Text(displayName, {
608
609
  fontFamily: 'system-ui, -apple-system, Segoe UI, Roboto, Arial, sans-serif',
609
610
  fontSize: 12,
610
611
  fill: 0x333333,
611
612
  align: 'center',
612
613
  wordWrap: true,
613
- wordWrapWidth: width - 8
614
+ wordWrapWidth: Math.max(1, width - 16)
614
615
  });
615
- nameText.x = (width - nameText.width) / 2;
616
- nameText.y = height - 40;
616
+ nameText.anchor.set(0.5, 0);
617
+ nameText.x = width / 2;
618
+ nameText.y = iconY + iconSize + 8;
617
619
 
618
620
  // Добавляем в контейнер в правильном порядке
619
621
  this.ghostContainer.addChild(shadow);