iwgt 2.4.10 → 2.4.12
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/dist/data/references/commonjs-complete-guide.json +1082 -0
- package/dist/data/references/commonjs-reference.json +1 -1
- package/dist/data/references/javascript-guide.json +436 -0
- package/dist/data/references/liquid-filters.json +1 -1
- package/dist/data/references/liquid-variables.json +1 -1
- package/dist/data/widget-wrapper-and-context.md +647 -0
- package/dist/generators/index.js +5 -0
- package/dist/server-http.js +1 -1
- package/dist/server.js +57 -2
- package/dist/tools/index.d.ts +4 -0
- package/dist/tools/index.js +136 -5
- package/package.json +1 -1
|
@@ -0,0 +1,647 @@
|
|
|
1
|
+
# Системная обёртка виджетов и контекст выполнения
|
|
2
|
+
|
|
3
|
+
## Системная обёртка (layout wrapper)
|
|
4
|
+
|
|
5
|
+
**ВАЖНО:** Весь код из `snippet.liquid` автоматически оборачивается системой InSales в `div` с классом `layout` и уникальным классом виджета.
|
|
6
|
+
|
|
7
|
+
### Структура обёртки
|
|
8
|
+
|
|
9
|
+
```html
|
|
10
|
+
<div
|
|
11
|
+
class="layout widget-type_#{widget_handle}"
|
|
12
|
+
style="--heading-hide:false; --delete-borders:false; --align-title:left; ..."
|
|
13
|
+
data-widget-drop-item-id="209226033"
|
|
14
|
+
>
|
|
15
|
+
<!-- ВАШ КОД ИЗ snippet.liquid -->
|
|
16
|
+
</div>
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
### Шаблон класса виджета
|
|
20
|
+
|
|
21
|
+
```
|
|
22
|
+
widget-type_#{widget_handle}
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Пример: для виджета с `handle: "system-widget-story"` класс будет `widget-type_system-widget-story`
|
|
26
|
+
|
|
27
|
+
### CSS переменные из настроек
|
|
28
|
+
|
|
29
|
+
Система автоматически преобразует настройки виджета из `settings_form.json` в CSS-переменные в атрибуте `style`.
|
|
30
|
+
|
|
31
|
+
**Правило преобразования:**
|
|
32
|
+
- Название настройки становится CSS-переменной: `layout-wide-bg` → `--layout-wide-bg`
|
|
33
|
+
- Значение настройки становится значением CSS-переменной
|
|
34
|
+
|
|
35
|
+
**Пример:**
|
|
36
|
+
|
|
37
|
+
```json
|
|
38
|
+
// settings_form.json
|
|
39
|
+
{
|
|
40
|
+
"handle": "layout-wide-bg",
|
|
41
|
+
"type": "checkbox",
|
|
42
|
+
"value": true
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Преобразуется в:
|
|
47
|
+
```html
|
|
48
|
+
style="--layout-wide-bg:true"
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### Полный пример
|
|
52
|
+
|
|
53
|
+
```html
|
|
54
|
+
<div
|
|
55
|
+
class="layout widget-type_system-widget-story"
|
|
56
|
+
style="--heading-hide:false; --delete-borders:false; --align-title:left; --stories-rounding:false; --slide-width:200px; --slide-gap:30rem; --open-link:normal; --img-ratio:1; --banner-border-radius:0px; --slide-width-mobile:150px; --img-ratio-mobile:1; --layout-wide-bg:true; --layout-pt:2vw; --layout-pb:2vw; --layout-wide-content:false; --layout-edge:false; --hide-desktop:false; --hide-mobile:false;"
|
|
57
|
+
data-widget-drop-item-id="209226033"
|
|
58
|
+
>
|
|
59
|
+
<!-- html из snippet.liquid -->
|
|
60
|
+
</div>
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Контекст выполнения виджета
|
|
64
|
+
|
|
65
|
+
### Основные переменные контекста
|
|
66
|
+
|
|
67
|
+
#### 1. `widget_settings` - настройки виджета
|
|
68
|
+
|
|
69
|
+
Доступ к значениям из `settings_form.json`:
|
|
70
|
+
|
|
71
|
+
```liquid
|
|
72
|
+
{{ widget_settings.layout-wide-content }}
|
|
73
|
+
{{ widget_settings.title_text-default }}
|
|
74
|
+
{{ widget_settings.menu-handle }}
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
#### 2. `data.blocks` - блоки виджета (только для BlockListWidgetType)
|
|
78
|
+
|
|
79
|
+
**ВАЖНО:** Для виджетов типа `BlockListWidgetType` блоки доступны через переменную `data.blocks`.
|
|
80
|
+
|
|
81
|
+
**Перебор блоков:**
|
|
82
|
+
|
|
83
|
+
```liquid
|
|
84
|
+
{% for block in data.blocks %}
|
|
85
|
+
{{ block.name }}
|
|
86
|
+
{{ block.image }}
|
|
87
|
+
{{ block.link }}
|
|
88
|
+
{% endfor %}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
**Доступные поля блока** зависят от `block_template_handle`, указанного в `info.json`.
|
|
92
|
+
|
|
93
|
+
Например, для `system-banner-video`:
|
|
94
|
+
- `block.link` - ссылка
|
|
95
|
+
- `block.image` - заставка
|
|
96
|
+
|
|
97
|
+
#### 3. `widget_messages` - переводы текстов
|
|
98
|
+
|
|
99
|
+
Содержит переводы из файла `messages.json`:
|
|
100
|
+
|
|
101
|
+
```liquid
|
|
102
|
+
{{ widget_messages.button_text }}
|
|
103
|
+
{{ widget_messages.empty_state }}
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
#### 4. Доступ к сущностям магазина через настройки
|
|
107
|
+
|
|
108
|
+
Через настройки виджета можно получить доступ к различным сущностям магазина.
|
|
109
|
+
|
|
110
|
+
**Пример: вывод меню**
|
|
111
|
+
|
|
112
|
+
```liquid
|
|
113
|
+
{% comment %}
|
|
114
|
+
В settings_form.json есть настройка:
|
|
115
|
+
{
|
|
116
|
+
"handle": "menu-handle",
|
|
117
|
+
"type": "menu",
|
|
118
|
+
"value": "main-menu"
|
|
119
|
+
}
|
|
120
|
+
{% endcomment %}
|
|
121
|
+
|
|
122
|
+
{% for link in linklists[widget_settings.menu-handle].links %}
|
|
123
|
+
<li class="header__menu-item" data-navigation-item data-menu-item-id="{{ link.id}}">
|
|
124
|
+
<div class="header__menu-controls">
|
|
125
|
+
<a href="{{ link.url }}" class="header__menu-link" data-navigation-link="{{ link.url }}">
|
|
126
|
+
{{ link.title }}
|
|
127
|
+
</a>
|
|
128
|
+
</div>
|
|
129
|
+
</li>
|
|
130
|
+
{% endfor %}
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
**Пример: вывод категории**
|
|
134
|
+
|
|
135
|
+
```liquid
|
|
136
|
+
{% comment %}
|
|
137
|
+
В settings_form.json есть настройка:
|
|
138
|
+
{
|
|
139
|
+
"handle": "collection-handle",
|
|
140
|
+
"type": "collection",
|
|
141
|
+
"value": null
|
|
142
|
+
}
|
|
143
|
+
{% endcomment %}
|
|
144
|
+
|
|
145
|
+
{% assign collection = collections[widget_settings.collection-handle] %}
|
|
146
|
+
{% if collection %}
|
|
147
|
+
<h2>{{ collection.title }}</h2>
|
|
148
|
+
{% for product in collection.products %}
|
|
149
|
+
{{ product.title }}
|
|
150
|
+
{% endfor %}
|
|
151
|
+
{% endif %}
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### Глобальные переменные Liquid
|
|
155
|
+
|
|
156
|
+
В контексте виджета доступны все глобальные переменные InSales Liquid:
|
|
157
|
+
|
|
158
|
+
- `account` - данные магазина
|
|
159
|
+
- `template` - текущий шаблон страницы
|
|
160
|
+
- `language` / `languages` - локализация
|
|
161
|
+
- `product` - товар (на странице товара)
|
|
162
|
+
- `collection` - категория (на странице категории)
|
|
163
|
+
- `cart` - корзина
|
|
164
|
+
- `linklists` - все меню магазина
|
|
165
|
+
- `collections` - все категории магазина
|
|
166
|
+
- `settings` - глобальные настройки темы
|
|
167
|
+
|
|
168
|
+
Полный список в справочнике: `get_liquid_variables`
|
|
169
|
+
|
|
170
|
+
## JavaScript виджета (snippet.js)
|
|
171
|
+
|
|
172
|
+
### Системная обёртка snippet.js
|
|
173
|
+
|
|
174
|
+
**ВАЖНО:** Весь код из `snippet.js` автоматически оборачивается системой в `try/catch` блок с предопределёнными переменными.
|
|
175
|
+
|
|
176
|
+
**Система оборачивает ваш код так:**
|
|
177
|
+
|
|
178
|
+
```js
|
|
179
|
+
try {
|
|
180
|
+
let widget = '.widget-type_your-widget-handle';
|
|
181
|
+
let $widget = $('.widget-type_your-widget-handle');
|
|
182
|
+
|
|
183
|
+
// ВАШ КОД ИЗ snippet.js
|
|
184
|
+
|
|
185
|
+
} catch(error) {
|
|
186
|
+
console.error('Widget "widget-type_your-widget-handle"', error)
|
|
187
|
+
}
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
**Доступные переменные:**
|
|
191
|
+
- `widget` - строка с селектором виджета (`.widget-type_#{handle}`)
|
|
192
|
+
- `$widget` - jQuery объект виджета (если подключен jQuery)
|
|
193
|
+
|
|
194
|
+
**Ваш код в snippet.js:**
|
|
195
|
+
|
|
196
|
+
```js
|
|
197
|
+
// НЕ нужно оборачивать в try/catch - это делается автоматически!
|
|
198
|
+
// НЕ нужно объявлять widget и $widget - они уже доступны!
|
|
199
|
+
|
|
200
|
+
// Можно сразу использовать переменные:
|
|
201
|
+
console.log('Виджет инициализирован:', widget);
|
|
202
|
+
|
|
203
|
+
if ($widget.length) {
|
|
204
|
+
// Работа с jQuery
|
|
205
|
+
$widget.find('.block').each(function() {
|
|
206
|
+
// ...
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// Или с vanilla JS:
|
|
211
|
+
const widgetEl = document.querySelector(widget);
|
|
212
|
+
if (widgetEl) {
|
|
213
|
+
// ...
|
|
214
|
+
}
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
### EventBus - события визуального редактора
|
|
218
|
+
|
|
219
|
+
**EventBus** - это сервисный объект с событиями визуального редактора виджетов InSales.
|
|
220
|
+
|
|
221
|
+
**События изменения настроек виджета:**
|
|
222
|
+
|
|
223
|
+
```js
|
|
224
|
+
EventBus.subscribe([
|
|
225
|
+
'widget:input-setting:insales:system:editor',
|
|
226
|
+
'widget:change-setting:insales:system:editor',
|
|
227
|
+
'widget:input-color:insales:system:editor'
|
|
228
|
+
], (data) => {
|
|
229
|
+
console.log('Настройка изменена:', data);
|
|
230
|
+
});
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
**Структура объекта data:**
|
|
234
|
+
|
|
235
|
+
```js
|
|
236
|
+
{
|
|
237
|
+
widget_id: 87289537, // ID виджета
|
|
238
|
+
widget_item_id: 209226033, // ID экземпляра виджета
|
|
239
|
+
setting_name: "align-title", // Название настройки
|
|
240
|
+
value: "center", // Новое значение
|
|
241
|
+
unit: "px", // Единица измерения (для числовых)
|
|
242
|
+
type: "icon_group" // Тип настройки
|
|
243
|
+
}
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
**Примеры событий:**
|
|
247
|
+
|
|
248
|
+
```js
|
|
249
|
+
// Изменение выравнивания
|
|
250
|
+
{
|
|
251
|
+
setting_name: "align-title",
|
|
252
|
+
type: "icon_group",
|
|
253
|
+
unit: undefined,
|
|
254
|
+
value: "center",
|
|
255
|
+
widget_id: 87289537,
|
|
256
|
+
widget_item_id: 209226033
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
// Изменение цвета с оттенками
|
|
260
|
+
{
|
|
261
|
+
widget_id: 87289537,
|
|
262
|
+
widget_item_id: 209226033,
|
|
263
|
+
setting_name: "bg-details-stories-color",
|
|
264
|
+
value: "#338072",
|
|
265
|
+
type: "color",
|
|
266
|
+
shades: [
|
|
267
|
+
{name: "minor", light: -3, dark: 10},
|
|
268
|
+
{name: "major", light: -7, dark: 20},
|
|
269
|
+
{name: "half", light: -50, dark: 50}
|
|
270
|
+
]
|
|
271
|
+
}
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
**Типы настроек (type):**
|
|
275
|
+
- `color` - цветовая настройка
|
|
276
|
+
- `text` - текстовое поле
|
|
277
|
+
- `number` - числовое поле
|
|
278
|
+
- `select` - выпадающий список
|
|
279
|
+
- `fonts_select` - выбор шрифта
|
|
280
|
+
- `icon_group` - группа иконок
|
|
281
|
+
- и другие...
|
|
282
|
+
|
|
283
|
+
**Пример использования EventBus:**
|
|
284
|
+
|
|
285
|
+
```js
|
|
286
|
+
// Обновление стилей при изменении настроек в редакторе
|
|
287
|
+
EventBus.subscribe([
|
|
288
|
+
'widget:input-setting:insales:system:editor',
|
|
289
|
+
'widget:change-setting:insales:system:editor'
|
|
290
|
+
], (data) => {
|
|
291
|
+
if (data.setting_name === 'slide-gap') {
|
|
292
|
+
// Обновляем слайдер с новым значением gap
|
|
293
|
+
const widgetEl = document.querySelector(widget);
|
|
294
|
+
if (widgetEl && window.Splide) {
|
|
295
|
+
const splide = widgetEl.querySelector('.splide');
|
|
296
|
+
// Переинициализация слайдера
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
});
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
## Архитектура виджетов InSales (важно!)
|
|
303
|
+
|
|
304
|
+
### НЕ ИСПОЛЬЗУЮТСЯ:
|
|
305
|
+
|
|
306
|
+
❌ **Кастомные теги** - нестандартные HTML-теги являются ОШИБКОЙ
|
|
307
|
+
❌ **React, Angular** и другие фреймворки
|
|
308
|
+
|
|
309
|
+
### ИСПОЛЬЗУЮТСЯ:
|
|
310
|
+
|
|
311
|
+
✅ **Liquid** - шаблонизатор для разметки (snippet.liquid)
|
|
312
|
+
✅ **Vanilla JavaScript** - для логики виджета (snippet.js)
|
|
313
|
+
✅ **CommonJS API** - для работы с магазином (Cart, Products, EventBus и т.д.)
|
|
314
|
+
✅ **Библиотеки** - указанные в `info.json` в поле `libraries` (jquery, splide, swiper и т.д.)
|
|
315
|
+
|
|
316
|
+
### Правильная структура HTML
|
|
317
|
+
|
|
318
|
+
```liquid
|
|
319
|
+
<div class="widget-container">
|
|
320
|
+
{% if widget_settings.show-heading %}
|
|
321
|
+
<h2 class="widget-heading">{{ widget_settings.heading-text }}</h2>
|
|
322
|
+
{% endif %}
|
|
323
|
+
|
|
324
|
+
{% if data.blocks %}
|
|
325
|
+
<div class="widget-blocks">
|
|
326
|
+
{% for block in data.blocks %}
|
|
327
|
+
<div class="widget-block">
|
|
328
|
+
{% if block.image %}
|
|
329
|
+
<img src="{{ block.image | img_url: '800x' }}" alt="{{ block.name }}">
|
|
330
|
+
{% endif %}
|
|
331
|
+
{% if block.name %}
|
|
332
|
+
<h3>{{ block.name }}</h3>
|
|
333
|
+
{% endif %}
|
|
334
|
+
{% if block.link %}
|
|
335
|
+
<a href="{{ block.link }}" class="widget-link">Подробнее</a>
|
|
336
|
+
{% endif %}
|
|
337
|
+
</div>
|
|
338
|
+
{% endfor %}
|
|
339
|
+
</div>
|
|
340
|
+
{% endif %}
|
|
341
|
+
</div>
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
## Debugging
|
|
345
|
+
|
|
346
|
+
### Вывод доступных переменных
|
|
347
|
+
|
|
348
|
+
```liquid
|
|
349
|
+
{% help %}
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
### Вывод свойств объекта
|
|
353
|
+
|
|
354
|
+
```liquid
|
|
355
|
+
{% help account %}
|
|
356
|
+
{% help product %}
|
|
357
|
+
{% help widget_settings %}
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
### Проверка значения переменной
|
|
361
|
+
|
|
362
|
+
```liquid
|
|
363
|
+
{{ widget_settings | json }}
|
|
364
|
+
{{ data.blocks | json }}
|
|
365
|
+
```
|
|
366
|
+
|
|
367
|
+
## Стили виджета (snippet.scss)
|
|
368
|
+
|
|
369
|
+
### Структура SCSS файла
|
|
370
|
+
|
|
371
|
+
**ВАЖНО:** Весь код в `snippet.scss` автоматически оборачивается в класс виджета.
|
|
372
|
+
|
|
373
|
+
Система компилирует ваш SCSS так:
|
|
374
|
+
```scss
|
|
375
|
+
// Ваш код в snippet.scss:
|
|
376
|
+
& {
|
|
377
|
+
padding: 2rem;
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
// Компилируется в:
|
|
381
|
+
.layout.widget-type_your-widget {
|
|
382
|
+
padding: 2rem;
|
|
383
|
+
}
|
|
384
|
+
```
|
|
385
|
+
|
|
386
|
+
### Использование & (амперсанд)
|
|
387
|
+
|
|
388
|
+
Символ `&` обращается к родительскому классу (`.layout.widget-type_#{handle}`):
|
|
389
|
+
|
|
390
|
+
```scss
|
|
391
|
+
& {
|
|
392
|
+
// Стили для родительского элемента
|
|
393
|
+
border-bottom: 1px solid var(--bg-minor-shade);
|
|
394
|
+
box-shadow: 0px 10px 20px -10px rgba(0,0,0,0.1);
|
|
395
|
+
position: relative;
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
// Состояния на основе CSS-переменных из настроек
|
|
399
|
+
&[style*="--article-hide-photo:true"] {
|
|
400
|
+
.article-photo {
|
|
401
|
+
display: none!important;
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
&[style*="--hide-favorites:true"][style*="--hide-personal:false"] {
|
|
406
|
+
.navigation-bar {
|
|
407
|
+
grid-template-columns: repeat(4, 1fr);
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
### Работа с CSS-переменными
|
|
413
|
+
|
|
414
|
+
Настройки виджета автоматически становятся CSS-переменными:
|
|
415
|
+
|
|
416
|
+
```scss
|
|
417
|
+
& {
|
|
418
|
+
// Используем переменные из настроек
|
|
419
|
+
padding-top: var(--layout-pt, 2rem);
|
|
420
|
+
padding-bottom: var(--layout-pb, 2rem);
|
|
421
|
+
|
|
422
|
+
// Переопределяем переменные
|
|
423
|
+
--grid-list-min-width: 190px;
|
|
424
|
+
--grid-list-row-gap: 1rem;
|
|
425
|
+
--grid-list-column-gap: 2rem;
|
|
426
|
+
|
|
427
|
+
@media screen and (max-width: 767px) {
|
|
428
|
+
--grid-list-min-width: 50%;
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
```
|
|
432
|
+
|
|
433
|
+
### Глобальный миксин background-color
|
|
434
|
+
|
|
435
|
+
**ВАЖНО:** В системе InSales глобально доступен миксин для работы с цветами фона, который автоматически управляет цветом текста в зависимости от яркости фона.
|
|
436
|
+
|
|
437
|
+
```scss
|
|
438
|
+
@mixin background-color($color) {
|
|
439
|
+
$dark_selector: '[style*="#{$color}-is-dark:true"]';
|
|
440
|
+
$light_selector: '[style*="#{$color}-is-light:true"]';
|
|
441
|
+
background-color: var(#{$color});
|
|
442
|
+
@at-root #{selector-append($dark_selector, &)} {
|
|
443
|
+
color: var(--color-text-light);
|
|
444
|
+
--color-text: var(--color-text-light);
|
|
445
|
+
--color-text-minor-shade: var(--color-text-light-minor-shade);
|
|
446
|
+
--color-text-major-shade: var(--color-text-light-major-shade);
|
|
447
|
+
--color-text-half-shade: var(--color-text-light-half-shade);
|
|
448
|
+
}
|
|
449
|
+
@at-root #{selector-append($light_selector, &)} {
|
|
450
|
+
color: var(--color-text-dark);
|
|
451
|
+
--color-text: var(--color-text-dark);
|
|
452
|
+
--color-text-minor-shade: var(--color-text-dark-minor-shade);
|
|
453
|
+
--color-text-major-shade: var(--color-text-dark-major-shade);
|
|
454
|
+
--color-text-half-shade: var(--color-text-dark-half-shade);
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
```
|
|
458
|
+
|
|
459
|
+
**Использование миксина:**
|
|
460
|
+
|
|
461
|
+
```scss
|
|
462
|
+
.widget-block {
|
|
463
|
+
// Применяем фоновый цвет с автоматической адаптацией текста
|
|
464
|
+
@include background-color(--bg-color);
|
|
465
|
+
|
|
466
|
+
// Система автоматически добавит переменные:
|
|
467
|
+
// --bg-color-is-dark:true или --bg-color-is-light:true
|
|
468
|
+
// в атрибут style родительского элемента
|
|
469
|
+
}
|
|
470
|
+
```
|
|
471
|
+
|
|
472
|
+
**Как это работает:**
|
|
473
|
+
1. Настройка цвета в `settings_form.json` типа `color` создаёт CSS-переменную
|
|
474
|
+
2. Система анализирует яркость цвета и добавляет `--название-цвета-is-dark:true` или `--название-цвета-is-light:true`
|
|
475
|
+
3. Миксин автоматически применяет правильный цвет текста (светлый для тёмного фона, тёмный для светлого)
|
|
476
|
+
|
|
477
|
+
**Доступные оттенки текста:**
|
|
478
|
+
- `--color-text` - основной цвет текста
|
|
479
|
+
- `--color-text-minor-shade` - лёгкий оттенок
|
|
480
|
+
- `--color-text-major-shade` - сильный оттенок
|
|
481
|
+
- `--color-text-half-shade` - средний оттенок
|
|
482
|
+
|
|
483
|
+
### Полный пример SCSS
|
|
484
|
+
|
|
485
|
+
```scss
|
|
486
|
+
& {
|
|
487
|
+
// Основные стили
|
|
488
|
+
padding-top: var(--layout-pt, 2rem);
|
|
489
|
+
padding-bottom: var(--layout-pb, 2rem);
|
|
490
|
+
position: relative;
|
|
491
|
+
|
|
492
|
+
// Используем миксин для фонового цвета
|
|
493
|
+
@include background-color(--bg-widget-color);
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
// Широкий фон
|
|
497
|
+
&[style*="--layout-wide-bg:true"] {
|
|
498
|
+
width: 100vw;
|
|
499
|
+
margin-left: calc(50% - 50vw);
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
// Скрытие на устройствах
|
|
503
|
+
&[style*="--hide-mobile:true"] {
|
|
504
|
+
@media (max-width: 767px) {
|
|
505
|
+
display: none;
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
// Вложенные элементы
|
|
510
|
+
.widget-container {
|
|
511
|
+
max-width: var(--layout-content-max-width, 1200px);
|
|
512
|
+
margin: 0 auto;
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
.widget-block {
|
|
516
|
+
@include background-color(--bg-block-color);
|
|
517
|
+
|
|
518
|
+
img {
|
|
519
|
+
width: 100%;
|
|
520
|
+
height: auto;
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
&:hover {
|
|
524
|
+
transform: scale(1.02);
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
```
|
|
528
|
+
|
|
529
|
+
## Типичные ошибки
|
|
530
|
+
|
|
531
|
+
### ❌ НЕПРАВИЛЬНО (Liquid):
|
|
532
|
+
|
|
533
|
+
```liquid
|
|
534
|
+
<!-- НЕ ИСПОЛЬЗУЙТЕ кастомные теги -->
|
|
535
|
+
<custom-tag>
|
|
536
|
+
<another-custom-tag>
|
|
537
|
+
Контент
|
|
538
|
+
</another-custom-tag>
|
|
539
|
+
</custom-tag>
|
|
540
|
+
|
|
541
|
+
<!-- НЕ добавляйте обёртку layout вручную -->
|
|
542
|
+
<div class="layout">
|
|
543
|
+
<!-- код виджета -->
|
|
544
|
+
</div>
|
|
545
|
+
```
|
|
546
|
+
|
|
547
|
+
### ❌ НЕПРАВИЛЬНО (SCSS):
|
|
548
|
+
|
|
549
|
+
```scss
|
|
550
|
+
// НЕ добавляйте класс виджета вручную
|
|
551
|
+
.layout.widget-type_my-widget {
|
|
552
|
+
padding: 2rem;
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
// НЕ используйте :root или html для переменных виджета
|
|
556
|
+
:root {
|
|
557
|
+
--my-variable: 10px;
|
|
558
|
+
}
|
|
559
|
+
```
|
|
560
|
+
|
|
561
|
+
### ✅ ПРАВИЛЬНО (Liquid):
|
|
562
|
+
|
|
563
|
+
```liquid
|
|
564
|
+
<!-- Используйте обычные HTML-теги -->
|
|
565
|
+
<div class="grid">
|
|
566
|
+
<div class="grid-cell">
|
|
567
|
+
Контент
|
|
568
|
+
</div>
|
|
569
|
+
</div>
|
|
570
|
+
|
|
571
|
+
<!-- Обёртка layout добавится автоматически -->
|
|
572
|
+
<div class="widget-content">
|
|
573
|
+
<!-- ваш код -->
|
|
574
|
+
</div>
|
|
575
|
+
```
|
|
576
|
+
|
|
577
|
+
### ✅ ПРАВИЛЬНО (SCSS):
|
|
578
|
+
|
|
579
|
+
```scss
|
|
580
|
+
// Используйте & для родительского элемента
|
|
581
|
+
& {
|
|
582
|
+
padding: 2rem;
|
|
583
|
+
|
|
584
|
+
// Определяйте переменные здесь
|
|
585
|
+
--my-variable: 10px;
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
// Селекторы элементов без &
|
|
589
|
+
.widget-content {
|
|
590
|
+
margin: 1rem 0;
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
// Состояния с &
|
|
594
|
+
&[style*="--some-setting:true"] {
|
|
595
|
+
.element {
|
|
596
|
+
display: none;
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
```
|
|
600
|
+
|
|
601
|
+
## Работа с блоками
|
|
602
|
+
|
|
603
|
+
### Проверка наличия блоков
|
|
604
|
+
|
|
605
|
+
```liquid
|
|
606
|
+
{% if data.blocks and data.blocks.size > 0 %}
|
|
607
|
+
<!-- вывод блоков -->
|
|
608
|
+
{% else %}
|
|
609
|
+
<!-- заглушка или пустое состояние -->
|
|
610
|
+
<div class="widget-empty">
|
|
611
|
+
{{ widget_messages.no_blocks_message }}
|
|
612
|
+
</div>
|
|
613
|
+
{% endif %}
|
|
614
|
+
```
|
|
615
|
+
|
|
616
|
+
### Перебор блоков с индексом
|
|
617
|
+
|
|
618
|
+
```liquid
|
|
619
|
+
{% assign slide_index = 0 %}
|
|
620
|
+
{% for block in data.blocks %}
|
|
621
|
+
<div class="slide" data-slide-index="{{ slide_index }}">
|
|
622
|
+
{{ block.name }}
|
|
623
|
+
</div>
|
|
624
|
+
{% assign slide_index = slide_index | plus: 1 %}
|
|
625
|
+
{% endfor %}
|
|
626
|
+
```
|
|
627
|
+
|
|
628
|
+
### Доступ к полям блока
|
|
629
|
+
|
|
630
|
+
Поля блока зависят от `block_template_handle`. Например:
|
|
631
|
+
|
|
632
|
+
**system-banner-2:**
|
|
633
|
+
- `block.name` - название (текст)
|
|
634
|
+
- `block.image` - изображение (файл)
|
|
635
|
+
- `block.link` - ссылка (текст)
|
|
636
|
+
|
|
637
|
+
**system-banner-video:**
|
|
638
|
+
- `block.link` - ссылка на видео (текст)
|
|
639
|
+
- `block.image` - заставка видео (файл)
|
|
640
|
+
|
|
641
|
+
**system-benefit-2:**
|
|
642
|
+
- `block.name` - заголовок (текст)
|
|
643
|
+
- `block.description` - описание (HTML)
|
|
644
|
+
- `block.image` - изображение (файл)
|
|
645
|
+
|
|
646
|
+
Полный список шаблонов блоков и их полей: `get_block_templates`
|
|
647
|
+
|
package/dist/generators/index.js
CHANGED
|
@@ -259,6 +259,11 @@ export function generateSettingsForm(commonSettings) {
|
|
|
259
259
|
if (setting.clearable)
|
|
260
260
|
item.clearable = setting.clearable;
|
|
261
261
|
}
|
|
262
|
+
else if (setting.type === 'file') {
|
|
263
|
+
item.value = setting.value || null;
|
|
264
|
+
if (setting['with-generate-logo'])
|
|
265
|
+
item['with-generate-logo'] = setting['with-generate-logo'];
|
|
266
|
+
}
|
|
262
267
|
// Общие свойства
|
|
263
268
|
if (setting.help)
|
|
264
269
|
item.help = setting.help;
|
package/dist/server-http.js
CHANGED