@sequent-org/moodboard 1.0.20 → 1.0.22
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 +1 -1
- package/src/ui/styles/workspace.css +4 -3
- package/src/utils/topbarIconLoader.js +130 -84
- package/src/assets/icons/topbar/README.md +0 -39
- /package/src/assets/icons/{topbar/grid-cross.svg → grid-cross.svg} +0 -0
- /package/src/assets/icons/{topbar/grid-dot.svg → grid-dot.svg} +0 -0
- /package/src/assets/icons/{topbar/grid-line.svg → grid-line.svg} +0 -0
- /package/src/assets/icons/{topbar/grid-off.svg → grid-off.svg} +0 -0
- /package/src/assets/icons/{topbar/paint.svg → paint.svg} +0 -0
package/package.json
CHANGED
|
@@ -201,19 +201,20 @@
|
|
|
201
201
|
display: inline-flex;
|
|
202
202
|
align-items: center;
|
|
203
203
|
justify-content: center;
|
|
204
|
-
width:
|
|
205
|
-
height:
|
|
204
|
+
width: 30px;
|
|
205
|
+
height: 30px;
|
|
206
206
|
border: none;
|
|
207
207
|
border-radius: 8px;
|
|
208
208
|
/* background: #E1F5FE; */
|
|
209
209
|
/* color: #212121; */
|
|
210
|
+
background: none;
|
|
210
211
|
font-size: 18px;
|
|
211
212
|
font-weight: 500;
|
|
212
213
|
cursor: pointer;
|
|
213
214
|
transition: all 0.2s ease;
|
|
214
215
|
text-align: center;
|
|
215
216
|
position: relative;
|
|
216
|
-
margin:
|
|
217
|
+
margin: 0px;
|
|
217
218
|
}
|
|
218
219
|
|
|
219
220
|
.moodboard-toolbar__button:hover {
|
|
@@ -1,77 +1,53 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Загрузчик SVG иконок для верхней панели
|
|
3
|
+
* Работает точно так же как IconLoader для левой панели
|
|
3
4
|
*/
|
|
4
5
|
export class TopbarIconLoader {
|
|
5
6
|
constructor() {
|
|
6
|
-
this.
|
|
7
|
-
this.
|
|
7
|
+
this.cache = new Map();
|
|
8
|
+
this.icons = {};
|
|
8
9
|
}
|
|
9
10
|
|
|
11
|
+
/**
|
|
12
|
+
* Инициализирует иконки при создании экземпляра
|
|
13
|
+
*/
|
|
10
14
|
async init() {
|
|
15
|
+
// Импортируем все SVG файлы статически, как в IconLoader
|
|
11
16
|
try {
|
|
12
|
-
//
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
} catch (error) {
|
|
21
|
-
console.error('❌ Критическая ошибка загрузки иконок верхней панели:', error);
|
|
22
|
-
// В случае ошибки у нас уже есть встроенные иконки
|
|
23
|
-
}
|
|
24
|
-
}
|
|
17
|
+
// Используем динамический импорт для всех иконок topbar
|
|
18
|
+
const iconModules = await Promise.all([
|
|
19
|
+
import('../assets/icons/grid-line.svg?raw'),
|
|
20
|
+
import('../assets/icons/grid-dot.svg?raw'),
|
|
21
|
+
import('../assets/icons/grid-cross.svg?raw'),
|
|
22
|
+
import('../assets/icons/grid-off.svg?raw'),
|
|
23
|
+
import('../assets/icons/paint.svg?raw')
|
|
24
|
+
]);
|
|
25
25
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
const iconNames = ['grid-line', 'grid-dot', 'grid-cross', 'grid-off', 'paint'];
|
|
29
|
-
|
|
30
|
-
for (const iconName of iconNames) {
|
|
31
|
-
try {
|
|
32
|
-
const svgContent = await this.loadIconFromFile(iconName);
|
|
33
|
-
if (svgContent) {
|
|
34
|
-
this.icons.set(iconName, svgContent);
|
|
35
|
-
console.log(`✅ Загружена иконка из файла: ${iconName}`);
|
|
36
|
-
}
|
|
37
|
-
} catch (error) {
|
|
38
|
-
console.warn(`⚠️ Не удалось загрузить иконку ${iconName} из файла:`, error.message);
|
|
39
|
-
// Оставляем встроенную версию
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
console.log(`📦 Всего загружено ${this.icons.size} иконок верхней панели`);
|
|
44
|
-
}
|
|
26
|
+
// Сохраняем иконки в кэш
|
|
27
|
+
const iconNames = ['grid-line', 'grid-dot', 'grid-cross', 'grid-off', 'paint'];
|
|
45
28
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
`/assets/icons/topbar/${iconName}.svg`
|
|
54
|
-
];
|
|
55
|
-
|
|
56
|
-
for (const path of paths) {
|
|
57
|
-
try {
|
|
58
|
-
const response = await fetch(path);
|
|
59
|
-
if (response.ok) {
|
|
60
|
-
const svgContent = await response.text();
|
|
61
|
-
console.log(`✅ Иконка ${iconName} загружена с пути: ${path}`);
|
|
62
|
-
return svgContent;
|
|
29
|
+
iconNames.forEach((name, index) => {
|
|
30
|
+
if (iconModules[index] && iconModules[index].default) {
|
|
31
|
+
this.icons[name] = iconModules[index].default;
|
|
32
|
+
this.cache.set(name, iconModules[index].default);
|
|
33
|
+
} else {
|
|
34
|
+
console.warn(`⚠️ Иконка ${name} не загружена, используем fallback`);
|
|
35
|
+
this.icons[name] = this.getFallbackIcon(name);
|
|
63
36
|
}
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
} catch (error) {
|
|
40
|
+
console.error('❌ Ошибка статической загрузки иконок topbar:', error);
|
|
41
|
+
console.log('🔄 Пробуем загрузить встроенные SVG иконки...');
|
|
42
|
+
// В случае ошибки загружаем встроенные SVG иконки
|
|
43
|
+
this.loadBuiltInIcons();
|
|
68
44
|
}
|
|
69
|
-
|
|
70
|
-
return null; // Возвращаем null вместо ошибки
|
|
71
45
|
}
|
|
72
46
|
|
|
73
|
-
|
|
74
|
-
|
|
47
|
+
/**
|
|
48
|
+
* Загружает встроенные SVG иконки (резервный метод)
|
|
49
|
+
*/
|
|
50
|
+
loadBuiltInIcons() {
|
|
75
51
|
const builtInIcons = {
|
|
76
52
|
'grid-line': `<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
77
53
|
<path d="M2 2H16V4H2V2Z" fill="currentColor"/>
|
|
@@ -119,44 +95,114 @@ export class TopbarIconLoader {
|
|
|
119
95
|
</svg>`
|
|
120
96
|
};
|
|
121
97
|
|
|
122
|
-
|
|
98
|
+
Object.keys(builtInIcons).forEach(name => {
|
|
99
|
+
this.icons[name] = builtInIcons[name];
|
|
100
|
+
this.cache.set(name, builtInIcons[name]);
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
console.log('📦 Загружены встроенные SVG иконки topbar');
|
|
123
104
|
}
|
|
124
105
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
106
|
+
/**
|
|
107
|
+
* Загружает SVG иконку по имени
|
|
108
|
+
* @param {string} iconName - имя иконки без расширения
|
|
109
|
+
* @returns {Promise<string>} SVG содержимое
|
|
110
|
+
*/
|
|
111
|
+
async loadIcon(iconName) {
|
|
112
|
+
if (this.cache.has(iconName)) {
|
|
113
|
+
console.log(`📦 Загружаем иконку ${iconName} из кэша`);
|
|
114
|
+
return this.cache.get(iconName);
|
|
134
115
|
}
|
|
135
|
-
|
|
136
|
-
console.log(`📦 Загружено ${this.icons.size} встроенных иконок верхней панели`);
|
|
137
|
-
}
|
|
138
116
|
|
|
139
|
-
|
|
140
|
-
|
|
117
|
+
// Если иконка уже загружена статически
|
|
118
|
+
if (this.icons[iconName]) {
|
|
119
|
+
console.log(`📦 Загружаем иконку ${iconName} из статического кэша`);
|
|
120
|
+
return this.icons[iconName];
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// Возвращаем fallback
|
|
124
|
+
console.warn(`⚠️ Иконка ${iconName} не найдена, используем fallback`);
|
|
125
|
+
return this.getFallbackIcon(iconName);
|
|
141
126
|
}
|
|
142
127
|
|
|
143
128
|
/**
|
|
144
|
-
* Загружает все иконки
|
|
129
|
+
* Загружает все иконки для topbar
|
|
130
|
+
* @returns {Promise<Object>} объект с иконками
|
|
145
131
|
*/
|
|
146
132
|
async loadAllIcons() {
|
|
147
|
-
|
|
148
|
-
this.icons.
|
|
149
|
-
|
|
150
|
-
}
|
|
151
|
-
|
|
133
|
+
// Если иконки еще не инициализированы
|
|
134
|
+
if (Object.keys(this.icons).length === 0) {
|
|
135
|
+
await this.init();
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
return this.icons;
|
|
152
139
|
}
|
|
153
140
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
141
|
+
/**
|
|
142
|
+
* Возвращает fallback иконку если загрузка не удалась
|
|
143
|
+
* @param {string} iconName - имя иконки
|
|
144
|
+
* @returns {string} fallback SVG
|
|
145
|
+
*/
|
|
146
|
+
getFallbackIcon(iconName) {
|
|
147
|
+
// Простые fallback иконки в виде геометрических фигур
|
|
148
|
+
const fallbacks = {
|
|
149
|
+
'grid-line': '<svg width="18" height="18" viewBox="0 0 18 18"><path d="M2 2H16V4H2V2Z" fill="currentColor"/><path d="M2 7H16V9H2V7Z" fill="currentColor"/><path d="M2 12H16V14H2V12Z" fill="currentColor"/><path d="M2 2V16H4V2H2Z" fill="currentColor"/><path d="M7 2V16H9V2H7Z" fill="currentColor"/><path d="M12 2V16H14V2H12Z" fill="currentColor"/></svg>',
|
|
150
|
+
'grid-dot': '<svg width="18" height="18" viewBox="0 0 18 18"><circle cx="4" cy="4" r="1.5" fill="currentColor"/><circle cx="9" cy="4" r="1.5" fill="currentColor"/><circle cx="14" cy="4" r="1.5" fill="currentColor"/><circle cx="4" cy="9" r="1.5" fill="currentColor"/><circle cx="9" cy="9" r="1.5" fill="currentColor"/><circle cx="14" cy="9" r="1.5" fill="currentColor"/><circle cx="4" cy="14" r="1.5" fill="currentColor"/><circle cx="9" cy="14" r="1.5" fill="currentColor"/><circle cx="14" cy="14" r="1.5" fill="currentColor"/></svg>',
|
|
151
|
+
'grid-cross': '<svg width="18" height="18" viewBox="0 0 18 18"><path d="M3 3L6 6M6 3L3 6" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/><path d="M9 3L12 6M12 3L9 6" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/><path d="M3 9L6 12M6 9L3 12" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/><path d="M9 9L12 12M12 9L9 12" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg>',
|
|
152
|
+
'grid-off': '<svg width="18" height="18" viewBox="0 0 18 18"><path d="M2 2H16V4H2V2Z" fill="currentColor" opacity="0.3"/><path d="M2 7H16V9H2V7Z" fill="currentColor" opacity="0.3"/><path d="M2 12H16V14H2V12Z" fill="currentColor" opacity="0.3"/><path d="M2 2V16H4V2H2Z" fill="currentColor" opacity="0.3"/><path d="M7 2V16H9V2H7Z" fill="currentColor" opacity="0.3"/><path d="M12 2V16H14V2H12Z" fill="currentColor" opacity="0.3"/><path d="M1 17L17 1" stroke="currentColor" stroke-width="2" stroke-linecap="round"/></svg>',
|
|
153
|
+
'paint': '<svg width="18" height="18" viewBox="0 0 18 18"><path d="M4 3H10L13 6V13A2 2 0 0 1 11 15H6A2 2 0 0 1 4 13V3Z" stroke="currentColor" stroke-width="1.5" fill="none"/><path d="M10 3V6H13" stroke="currentColor" stroke-width="1.5"/><path d="M14 10S15.5 11.5 15.5 13A1.5 1.5 0 0 1 13 13C13 11.5 14 10 14 10Z" fill="currentColor" stroke="currentColor" stroke-width="0.5"/></svg>'
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
return fallbacks[iconName] || fallbacks['grid-line'];
|
|
157
157
|
}
|
|
158
158
|
|
|
159
|
+
/**
|
|
160
|
+
* Очищает кэш иконок
|
|
161
|
+
*/
|
|
159
162
|
clearCache() {
|
|
160
|
-
this.
|
|
163
|
+
this.cache.clear();
|
|
161
164
|
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Принудительно перезагружает иконку (игнорируя кэш)
|
|
168
|
+
* @param {string} iconName - имя иконки без расширения
|
|
169
|
+
* @returns {Promise<string>} SVG содержимое
|
|
170
|
+
*/
|
|
171
|
+
async reloadIcon(iconName) {
|
|
172
|
+
// Удаляем из кэша
|
|
173
|
+
console.log(`🗑️ Очищаем кэш для иконки ${iconName}`);
|
|
174
|
+
this.cache.delete(iconName);
|
|
175
|
+
|
|
176
|
+
try {
|
|
177
|
+
// Пробуем переимпортировать иконку
|
|
178
|
+
const iconModule = await import(`../assets/icons/${iconName}.svg?raw`);
|
|
179
|
+
if (iconModule && iconModule.default) {
|
|
180
|
+
const svgContent = iconModule.default;
|
|
181
|
+
console.log(`✅ Иконка ${iconName} перезагружена успешно`);
|
|
182
|
+
this.icons[iconName] = svgContent;
|
|
183
|
+
this.cache.set(iconName, svgContent);
|
|
184
|
+
return svgContent;
|
|
185
|
+
} else {
|
|
186
|
+
throw new Error(`Failed to reload icon: ${iconName}`);
|
|
187
|
+
}
|
|
188
|
+
} catch (error) {
|
|
189
|
+
console.error(`❌ Ошибка перезагрузки иконки ${iconName}:`, error);
|
|
190
|
+
return this.getFallbackIcon(iconName);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Получает иконку по имени (синхронный метод для совместимости)
|
|
196
|
+
*/
|
|
197
|
+
getIcon(name) {
|
|
198
|
+
return this.icons[name] || this.getFallbackIcon(name);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// Создаем глобальный экземпляр
|
|
203
|
+
export const topbarIconLoader = new TopbarIconLoader();
|
|
204
|
+
|
|
205
|
+
// Добавляем в глобальную область для отладки
|
|
206
|
+
if (typeof window !== 'undefined') {
|
|
207
|
+
window.topbarIconLoader = topbarIconLoader;
|
|
162
208
|
}
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
# SVG Иконки для Верхней Панели
|
|
2
|
-
|
|
3
|
-
Эта папка содержит SVG иконки для кнопок верхней панели MoodBoard.
|
|
4
|
-
|
|
5
|
-
## Иконки
|
|
6
|
-
|
|
7
|
-
### Сетка
|
|
8
|
-
- **`grid-line.svg`** - Сетка с линиями
|
|
9
|
-
- **`grid-dot.svg`** - Сетка с точками
|
|
10
|
-
- **`grid-cross.svg`** - Сетка с крестиками
|
|
11
|
-
- **`grid-off.svg`** - Сетка выключена (с перечеркиванием)
|
|
12
|
-
|
|
13
|
-
### Инструменты
|
|
14
|
-
- **`paint.svg`** - Палитра фона
|
|
15
|
-
|
|
16
|
-
## Технические детали
|
|
17
|
-
|
|
18
|
-
- **Размер**: 18x18 пикселей
|
|
19
|
-
- **ViewBox**: 0 0 18 18
|
|
20
|
-
- **Цвет**: Использует `currentColor` для наследования цвета от родительского элемента
|
|
21
|
-
- **Формат**: SVG с оптимизированными путями
|
|
22
|
-
|
|
23
|
-
## Использование
|
|
24
|
-
|
|
25
|
-
Иконки загружаются через `TopbarIconLoader` и добавляются в DOM как SVG символы с ID вида `icon-{имя}`.
|
|
26
|
-
|
|
27
|
-
```html
|
|
28
|
-
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
29
|
-
<use href="#icon-grid-line"/>
|
|
30
|
-
</svg>
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
## Добавление новых иконок
|
|
34
|
-
|
|
35
|
-
1. Создайте SVG файл в этой папке
|
|
36
|
-
2. Убедитесь, что используется `currentColor` для цвета
|
|
37
|
-
3. Добавьте иконку в `TopbarIconLoader.loadBuiltInIcons()` как fallback
|
|
38
|
-
4. Обновите соответствующий код в `Topbar.js`
|
|
39
|
-
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|