@toaster-builder/site-runtime 0.1.0

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.
Files changed (70) hide show
  1. package/README.md +38 -0
  2. package/dist/module.d.mts +7 -0
  3. package/dist/module.json +12 -0
  4. package/dist/module.mjs +21 -0
  5. package/dist/runtime/assets/editor/add-block.svg +5 -0
  6. package/dist/runtime/assets/editor/ai-assistant.svg +5 -0
  7. package/dist/runtime/assets/editor/block-settings-center.svg +3 -0
  8. package/dist/runtime/assets/editor/block-settings-path.svg +3 -0
  9. package/dist/runtime/assets/editor/copy-block.svg +10 -0
  10. package/dist/runtime/assets/editor/delete-block.svg +4 -0
  11. package/dist/runtime/assets/editor/hide-block.svg +6 -0
  12. package/dist/runtime/assets/editor/move-block-down.svg +3 -0
  13. package/dist/runtime/assets/editor/move-block-up.svg +3 -0
  14. package/dist/runtime/assets/editor/show-block.svg +4 -0
  15. package/dist/runtime/components/BlockEditorFrame.d.vue.ts +16 -0
  16. package/dist/runtime/components/BlockEditorFrame.vue +418 -0
  17. package/dist/runtime/components/BlockEditorFrame.vue.d.ts +16 -0
  18. package/dist/runtime/components/BlockPlacementProvider.d.vue.ts +16 -0
  19. package/dist/runtime/components/BlockPlacementProvider.vue +12 -0
  20. package/dist/runtime/components/BlockPlacementProvider.vue.d.ts +16 -0
  21. package/dist/runtime/components/PageRegionRenderer.d.vue.ts +16 -0
  22. package/dist/runtime/components/PageRegionRenderer.vue +50 -0
  23. package/dist/runtime/components/PageRegionRenderer.vue.d.ts +16 -0
  24. package/dist/runtime/components/PageRenderer.d.vue.ts +3 -0
  25. package/dist/runtime/components/PageRenderer.vue +65 -0
  26. package/dist/runtime/components/PageRenderer.vue.d.ts +3 -0
  27. package/dist/runtime/composables/useBuilder.d.ts +15 -0
  28. package/dist/runtime/composables/useBuilder.js +27 -0
  29. package/dist/runtime/composables/useBuilderEventService.d.ts +3 -0
  30. package/dist/runtime/composables/useBuilderEventService.js +14 -0
  31. package/dist/runtime/composables/useBuilderState.d.ts +8 -0
  32. package/dist/runtime/composables/useBuilderState.js +21 -0
  33. package/dist/runtime/composables/usePageRegistry.d.ts +6 -0
  34. package/dist/runtime/composables/usePageRegistry.js +76 -0
  35. package/dist/runtime/composables/usePageSettings.d.ts +21 -0
  36. package/dist/runtime/composables/usePageSettings.js +90 -0
  37. package/dist/runtime/events/builder-event.d.ts +9 -0
  38. package/dist/runtime/events/builder-event.js +14 -0
  39. package/dist/runtime/events/builder-form-preview-token-event.d.ts +7 -0
  40. package/dist/runtime/events/builder-form-preview-token-event.js +19 -0
  41. package/dist/runtime/events/builder-page-state-event.d.ts +9 -0
  42. package/dist/runtime/events/builder-page-state-event.js +62 -0
  43. package/dist/runtime/events/builder-ready-ping-event.d.ts +6 -0
  44. package/dist/runtime/events/builder-ready-ping-event.js +10 -0
  45. package/dist/runtime/events/site-options-updated-event.d.ts +8 -0
  46. package/dist/runtime/events/site-options-updated-event.js +18 -0
  47. package/dist/runtime/plugin.d.ts +10 -0
  48. package/dist/runtime/plugin.js +10 -0
  49. package/dist/runtime/server/tsconfig.json +3 -0
  50. package/dist/runtime/services/builder-event-service.d.ts +37 -0
  51. package/dist/runtime/services/builder-event-service.js +104 -0
  52. package/dist/runtime/types/assets.d.ts +5 -0
  53. package/dist/runtime/types/page.d.ts +37 -0
  54. package/dist/runtime/types/page.js +9 -0
  55. package/dist/runtime/utils/block-options.d.ts +2 -0
  56. package/dist/runtime/utils/block-options.js +9 -0
  57. package/dist/runtime/utils/block-placement.d.ts +2 -0
  58. package/dist/runtime/utils/block-placement.js +1 -0
  59. package/dist/runtime/utils/common.d.ts +2 -0
  60. package/dist/runtime/utils/common.js +6 -0
  61. package/dist/runtime/utils/css-variables.d.ts +7 -0
  62. package/dist/runtime/utils/css-variables.js +35 -0
  63. package/dist/runtime/utils/fonts.d.ts +8 -0
  64. package/dist/runtime/utils/fonts.js +80 -0
  65. package/dist/runtime/utils/page-config.d.ts +3 -0
  66. package/dist/runtime/utils/page-config.js +114 -0
  67. package/dist/runtime/utils/page-options.d.ts +3 -0
  68. package/dist/runtime/utils/page-options.js +26 -0
  69. package/dist/types.d.mts +3 -0
  70. package/package.json +65 -0
package/README.md ADDED
@@ -0,0 +1,38 @@
1
+ # @toaster-builder/site-runtime
2
+
3
+ Общий Nuxt runtime для пользовательских сайтов Toaster и их интеграции с Builder.
4
+
5
+ Пакет пока находится в версии `0.x`: совместимость публичного API фиксируется SemVer, а версия протокола обмена с Builder хранится отдельно.
6
+
7
+ ## Разработка в Docker
8
+
9
+ Для работы нужен только Docker с Compose plugin.
10
+
11
+ ```bash
12
+ make install
13
+ make dev
14
+ ```
15
+
16
+ Playground откроется на <http://localhost:3002>.
17
+
18
+ Основные проверки:
19
+
20
+ ```bash
21
+ make check
22
+ make build
23
+ make pack
24
+ ```
25
+
26
+ `make pack` создаёт локальный tarball, которым можно проверить установку пакета в шаблон до публикации в npm.
27
+
28
+ ## Подключение к Nuxt
29
+
30
+ ```bash
31
+ npm install @toaster-builder/site-runtime
32
+ ```
33
+
34
+ ```ts
35
+ export default defineNuxtConfig({
36
+ modules: ['@toaster-builder/site-runtime'],
37
+ })
38
+ ```
@@ -0,0 +1,7 @@
1
+ import * as _nuxt_schema from '@nuxt/schema';
2
+
3
+ type ModuleOptions = Record<string, never>;
4
+ declare const _default: _nuxt_schema.NuxtModule<ModuleOptions, ModuleOptions, false>;
5
+
6
+ export { _default as default };
7
+ export type { ModuleOptions };
@@ -0,0 +1,12 @@
1
+ {
2
+ "name": "@toaster-builder/site-runtime",
3
+ "configKey": "toasterSiteRuntime",
4
+ "compatibility": {
5
+ "nuxt": ">=4.0.0"
6
+ },
7
+ "version": "0.1.0",
8
+ "builder": {
9
+ "@nuxt/module-builder": "1.0.3",
10
+ "unbuild": "3.6.1"
11
+ }
12
+ }
@@ -0,0 +1,21 @@
1
+ import { defineNuxtModule, createResolver, addPlugin } from '@nuxt/kit';
2
+
3
+ const module$1 = defineNuxtModule({
4
+ meta: {
5
+ name: "@toaster-builder/site-runtime",
6
+ configKey: "toasterSiteRuntime",
7
+ compatibility: {
8
+ nuxt: ">=4.0.0"
9
+ }
10
+ },
11
+ defaults: {},
12
+ setup(_options, nuxt) {
13
+ const resolver = createResolver(import.meta.url);
14
+ const runtimeDirectory = resolver.resolve("./runtime");
15
+ nuxt.options.alias["#toaster-site-runtime"] = runtimeDirectory;
16
+ nuxt.options.build.transpile.push(runtimeDirectory);
17
+ addPlugin(resolver.resolve("./runtime/plugin"));
18
+ }
19
+ });
20
+
21
+ export { module$1 as default };
@@ -0,0 +1,5 @@
1
+ <svg preserveAspectRatio="none" overflow="visible" style="display: block;" width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <g id="plus">
3
+ <path id="Vector" d="M2.9162 7H11.0838M7 2.9162V11.0838" stroke="#48484A" stroke-width="1.5" stroke-linecap="round"/>
4
+ </g>
5
+ </svg>
@@ -0,0 +1,5 @@
1
+ <svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <path d="M8.25 2.5C8.55 5.56 10.11 7.12 13.17 7.42C10.11 7.72 8.55 9.28 8.25 12.34C7.95 9.28 6.39 7.72 3.33 7.42C6.39 7.12 7.95 5.56 8.25 2.5Z" stroke="#48484A" stroke-width="1.5" stroke-linejoin="round"/>
3
+ <path d="M14.58 10C14.77 11.96 15.77 12.96 17.73 13.15C15.77 13.34 14.77 14.34 14.58 16.3C14.39 14.34 13.39 13.34 11.43 13.15C13.39 12.96 14.39 11.96 14.58 10Z" stroke="#48484A" stroke-width="1.5" stroke-linejoin="round"/>
4
+ <path d="M3.18 13.67C3.28 14.7 3.8 15.22 4.83 15.32C3.8 15.42 3.28 15.94 3.18 16.97C3.08 15.94 2.56 15.42 1.53 15.32C2.56 15.22 3.08 14.7 3.18 13.67Z" fill="#48484A"/>
5
+ </svg>
@@ -0,0 +1,3 @@
1
+ <svg preserveAspectRatio="none" overflow="visible" style="display: block;" width="6" height="6" viewBox="0 0 6 6" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <path id="Vector" d="M3 5.5C4.38071 5.5 5.5 4.38071 5.5 3C5.5 1.61929 4.38071 0.5 3 0.5C1.61929 0.5 0.5 1.61929 0.5 3C0.5 4.38071 1.61929 5.5 3 5.5Z" stroke="#48484A" stroke-linecap="round" stroke-linejoin="round"/>
3
+ </svg>
@@ -0,0 +1,3 @@
1
+ <svg preserveAspectRatio="none" overflow="visible" style="display: block;" width="17.6667" height="17.6667" viewBox="0 0 17.6667 17.6667" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <path id="Path" d="M15.1853 7.49616L14.2706 5.28733L15.5 3.83333L13.8333 2.16667L12.3873 3.40246L10.1315 2.47478L9.61278 0.5H7.98415L7.45757 2.50094L5.25368 3.42997L3.83333 2.16667L2.16667 3.83333L3.37781 5.32404L2.47708 7.53861L0.5 8V9.66667L2.50093 10.2129L3.42979 12.4164L2.16667 13.8333L3.83333 15.5L5.32597 14.2836L7.49751 15.1769L8 17.1667H9.66667L10.1704 15.1777L12.3793 14.263C12.7474 14.5261 13.8333 15.5 13.8333 15.5L15.5 13.8333L14.2633 12.3745L15.1782 10.165L17.1666 9.64765L17.1667 8L15.1853 7.49616Z" stroke="#48484A" stroke-linecap="round" stroke-linejoin="round"/>
3
+ </svg>
@@ -0,0 +1,10 @@
1
+ <svg preserveAspectRatio="none" overflow="visible" style="display: block;" width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <g id="copy" clip-path="url(#clip0_0_50)">
3
+ <path id="Vector" d="M3.3328 13.3336C2.41606 13.3336 1.666 12.5835 1.666 11.6668V3.3328C1.666 2.41606 2.41606 1.666 3.3328 1.666H11.6668C12.5835 1.666 13.3336 2.41606 13.3336 3.3328M8.3332 6.6664H16.6672C17.5877 6.6664 18.334 7.41265 18.334 8.3332V16.6672C18.334 17.5877 17.5877 18.334 16.6672 18.334H8.3332C7.41265 18.334 6.6664 17.5877 6.6664 16.6672V8.3332C6.6664 7.41265 7.41265 6.6664 8.3332 6.6664Z" stroke="#48484A" stroke-width="1.5" stroke-linecap="round"/>
4
+ </g>
5
+ <defs>
6
+ <clipPath id="clip0_0_50">
7
+ <rect width="20" height="20" fill="white"/>
8
+ </clipPath>
9
+ </defs>
10
+ </svg>
@@ -0,0 +1,4 @@
1
+ <svg width="24" height="24" viewBox="0 0 24 24" stroke-width="1.5" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <path d="M20 9L18.005 20.3463C17.8369 21.3026 17.0062 22 16.0353 22H7.96474C6.99379 22 6.1631 21.3026 5.99496 20.3463L4 9" stroke="#48484A" stroke-linecap="round" stroke-linejoin="round"/>
3
+ <path d="M21 6L15.375 6M3 6L8.625 6M8.625 6V4C8.625 2.89543 9.52043 2 10.625 2H13.375C14.4796 2 15.375 2.89543 15.375 4V6M8.625 6L15.375 6" stroke="#48484A" stroke-linecap="round" stroke-linejoin="round"/>
4
+ </svg>
@@ -0,0 +1,6 @@
1
+ <svg width="24" height="24" viewBox="0 0 24 24" stroke-width="1.5" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <path d="M19.5 16L17.0248 12.6038" stroke="#48484A" stroke-linecap="round" stroke-linejoin="round"/>
3
+ <path d="M12 17.5V14" stroke="#48484A" stroke-linecap="round" stroke-linejoin="round"/>
4
+ <path d="M4.5 16L6.96895 12.6124" stroke="#48484A" stroke-linecap="round" stroke-linejoin="round"/>
5
+ <path d="M3 8C6.6 16 17.4 16 21 8" stroke="#48484A" stroke-linecap="round" stroke-linejoin="round"/>
6
+ </svg>
@@ -0,0 +1,3 @@
1
+ <svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <path d="M10 3.333v13.334M10 16.667l5.417-5.417M10 16.667 4.583 11.25" stroke="#48484A" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
3
+ </svg>
@@ -0,0 +1,3 @@
1
+ <svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <path d="M10 16.667V3.333M10 3.333L4.583 8.75M10 3.333l5.417 5.417" stroke="#48484A" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
3
+ </svg>
@@ -0,0 +1,4 @@
1
+ <svg width="24" height="24" viewBox="0 0 24 24" stroke-width="1.5" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <path d="M3 12C3 12 6.6 6 12 6C17.4 6 21 12 21 12C21 12 17.4 18 12 18C6.6 18 3 12 3 12Z" stroke="#48484A" stroke-linecap="round" stroke-linejoin="round"/>
3
+ <path d="M12 14.5C13.3807 14.5 14.5 13.3807 14.5 12C14.5 10.6193 13.3807 9.5 12 9.5C10.6193 9.5 9.5 10.6193 9.5 12C9.5 13.3807 10.6193 14.5 12 14.5Z" stroke="#48484A" stroke-linecap="round" stroke-linejoin="round"/>
4
+ </svg>
@@ -0,0 +1,16 @@
1
+ import { type Component } from 'vue';
2
+ import type { BlockOptions, PageRegion } from '#toaster-site-runtime/types/page';
3
+ type __VLS_Props = {
4
+ blockComponent: Component;
5
+ blockId: string;
6
+ blockIndex: number;
7
+ builderReady: boolean;
8
+ enabled: boolean;
9
+ options: BlockOptions;
10
+ placementId: string;
11
+ placementCount: number;
12
+ region: PageRegion;
13
+ };
14
+ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
15
+ declare const _default: typeof __VLS_export;
16
+ export default _default;
@@ -0,0 +1,418 @@
1
+ <script setup>
2
+ import { computed } from "vue";
3
+ import addBlockIcon from "../assets/editor/add-block.svg";
4
+ import aiAssistantIcon from "../assets/editor/ai-assistant.svg";
5
+ import blockSettingsCenterIcon from "../assets/editor/block-settings-center.svg";
6
+ import blockSettingsPathIcon from "../assets/editor/block-settings-path.svg";
7
+ import copyBlockIcon from "../assets/editor/copy-block.svg";
8
+ import deleteBlockIcon from "../assets/editor/delete-block.svg";
9
+ import hideBlockIcon from "../assets/editor/hide-block.svg";
10
+ import moveBlockDownIcon from "../assets/editor/move-block-down.svg";
11
+ import moveBlockUpIcon from "../assets/editor/move-block-up.svg";
12
+ import showBlockIcon from "../assets/editor/show-block.svg";
13
+ import BlockPlacementProvider from "#toaster-site-runtime/components/BlockPlacementProvider.vue";
14
+ import { useBuilderEventService } from "#toaster-site-runtime/composables/useBuilderEventService";
15
+ const props = defineProps({
16
+ blockComponent: { type: null, required: true },
17
+ blockId: { type: String, required: true },
18
+ blockIndex: { type: Number, required: true },
19
+ builderReady: { type: Boolean, required: true },
20
+ enabled: { type: Boolean, required: true },
21
+ options: { type: Object, required: true },
22
+ placementId: { type: String, required: true },
23
+ placementCount: { type: Number, required: true },
24
+ region: { type: null, required: true }
25
+ });
26
+ const builderEvents = useBuilderEventService();
27
+ const blockVersionLabel = computed(() => {
28
+ const [name, variant = ""] = props.blockId.split("/");
29
+ const formattedVariant = /^v\d+$/i.test(variant) ? variant.toUpperCase() : variant;
30
+ return [name, formattedVariant].filter(Boolean).join(" ");
31
+ });
32
+ function postBuilderEvent(event, payload = {}) {
33
+ builderEvents.sendBlockEvent(event, {
34
+ blockId: props.blockId,
35
+ placementId: props.placementId,
36
+ region: props.region
37
+ }, payload);
38
+ }
39
+ </script>
40
+
41
+ <template>
42
+ <div
43
+ class="block-editor-frame"
44
+ :class="{
45
+ 'block-editor-frame--builder-ready': builderReady,
46
+ 'block-editor-frame--disabled': !enabled
47
+ }"
48
+ :data-toaster-block-id="blockId"
49
+ :data-toaster-placement-id="placementId"
50
+ :data-toaster-region="region"
51
+ >
52
+ <div class="block-editor-frame__content">
53
+ <BlockPlacementProvider :placement-id="placementId">
54
+ <component
55
+ :is="blockComponent"
56
+ :options="options"
57
+ />
58
+ </BlockPlacementProvider>
59
+ </div>
60
+
61
+ <template v-if="builderReady">
62
+ <div class="block-editor-frame__toolbar">
63
+ <button
64
+ class="block-editor-frame__control block-editor-frame__version"
65
+ type="button"
66
+ :aria-label="`\u0421\u043C\u0435\u043D\u0438\u0442\u044C \u0432\u0435\u0440\u0441\u0438\u044E \u0431\u043B\u043E\u043A\u0430 ${blockVersionLabel}`"
67
+ data-tooltip="Сменить версию блока"
68
+ @click.stop="postBuilderEvent('change-block-version')"
69
+ >
70
+ {{ blockVersionLabel }}
71
+ </button>
72
+
73
+ <button
74
+ class="block-editor-frame__control block-editor-frame__icon-button"
75
+ type="button"
76
+ :aria-label="`\u041F\u0435\u0440\u0435\u043D\u0435\u0441\u0442\u0438 \u0432\u0432\u0435\u0440\u0445 \u0431\u043B\u043E\u043A ${blockVersionLabel}`"
77
+ data-tooltip="Перенести вверх"
78
+ :disabled="blockIndex === 0"
79
+ @click.stop="postBuilderEvent('move-block', { direction: 'up', index: blockIndex })"
80
+ >
81
+ <img
82
+ :src="moveBlockUpIcon"
83
+ alt=""
84
+ aria-hidden="true"
85
+ >
86
+ </button>
87
+
88
+ <button
89
+ class="block-editor-frame__control block-editor-frame__icon-button"
90
+ type="button"
91
+ :aria-label="`\u041F\u0435\u0440\u0435\u043D\u0435\u0441\u0442\u0438 \u0432\u043D\u0438\u0437 \u0431\u043B\u043E\u043A ${blockVersionLabel}`"
92
+ data-tooltip="Перенести вниз"
93
+ :disabled="blockIndex === placementCount - 1"
94
+ @click.stop="postBuilderEvent('move-block', { direction: 'down', index: blockIndex })"
95
+ >
96
+ <img
97
+ :src="moveBlockDownIcon"
98
+ alt=""
99
+ aria-hidden="true"
100
+ >
101
+ </button>
102
+
103
+ <button
104
+ class="block-editor-frame__control block-editor-frame__icon-button"
105
+ type="button"
106
+ :aria-label="`\u041A\u043E\u043F\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u0431\u043B\u043E\u043A ${blockVersionLabel}`"
107
+ data-tooltip="Копировать блок"
108
+ @click.stop="postBuilderEvent('copy-block', { enable: enabled })"
109
+ >
110
+ <img
111
+ :src="copyBlockIcon"
112
+ alt=""
113
+ aria-hidden="true"
114
+ >
115
+ </button>
116
+
117
+ <button
118
+ class="block-editor-frame__control block-editor-frame__icon-button"
119
+ type="button"
120
+ :aria-label="`\u041D\u0430\u0441\u0442\u0440\u043E\u0439\u043A\u0438 \u0431\u043B\u043E\u043A\u0430 ${blockVersionLabel}`"
121
+ data-tooltip="Настройки блока"
122
+ @click.stop="postBuilderEvent('open-setting-block')"
123
+ >
124
+ <span
125
+ class="block-editor-frame__settings-icon"
126
+ aria-hidden="true"
127
+ >
128
+ <img
129
+ class="block-editor-frame__settings-path"
130
+ :src="blockSettingsPathIcon"
131
+ alt=""
132
+ >
133
+ <img
134
+ class="block-editor-frame__settings-center"
135
+ :src="blockSettingsCenterIcon"
136
+ alt=""
137
+ >
138
+ </span>
139
+ </button>
140
+
141
+ <button
142
+ class="block-editor-frame__control block-editor-frame__icon-button"
143
+ type="button"
144
+ :aria-label="`\u041E\u0442\u043A\u0440\u044B\u0442\u044C AI-\u0430\u0441\u0441\u0438\u0441\u0442\u0435\u043D\u0442\u0430 \u0434\u043B\u044F \u0431\u043B\u043E\u043A\u0430 ${blockVersionLabel}`"
145
+ data-tooltip="AI-ассистент"
146
+ @click.stop="postBuilderEvent('open-assistant-block')"
147
+ >
148
+ <img
149
+ :src="aiAssistantIcon"
150
+ alt=""
151
+ aria-hidden="true"
152
+ >
153
+ </button>
154
+
155
+ <button
156
+ class="block-editor-frame__control block-editor-frame__icon-button"
157
+ type="button"
158
+ :aria-label="enabled ? `\u0412\u0440\u0435\u043C\u0435\u043D\u043D\u043E \u0441\u043A\u0440\u044B\u0442\u044C \u0431\u043B\u043E\u043A ${blockVersionLabel}` : `\u041F\u043E\u043A\u0430\u0437\u0430\u0442\u044C \u0431\u043B\u043E\u043A ${blockVersionLabel}`"
159
+ :data-tooltip="enabled ? '\u0412\u0440\u0435\u043C\u0435\u043D\u043D\u043E \u0441\u043A\u0440\u044B\u0442\u044C \u0431\u043B\u043E\u043A' : '\u041F\u043E\u043A\u0430\u0437\u0430\u0442\u044C \u0431\u043B\u043E\u043A'"
160
+ @click.stop="postBuilderEvent('hide-block', { enable: !enabled })"
161
+ >
162
+ <img
163
+ :src="enabled ? hideBlockIcon : showBlockIcon"
164
+ alt=""
165
+ aria-hidden="true"
166
+ >
167
+ </button>
168
+
169
+ <button
170
+ class="block-editor-frame__control block-editor-frame__icon-button"
171
+ type="button"
172
+ :aria-label="`\u0423\u0434\u0430\u043B\u0438\u0442\u044C \u0431\u043B\u043E\u043A ${blockVersionLabel}`"
173
+ data-tooltip="Удалить блок"
174
+ @click.stop="postBuilderEvent('delete-block')"
175
+ >
176
+ <img
177
+ :src="deleteBlockIcon"
178
+ alt=""
179
+ aria-hidden="true"
180
+ >
181
+ </button>
182
+ </div>
183
+
184
+ <button
185
+ class="block-editor-frame__control block-editor-frame__add block-editor-frame__add--after"
186
+ type="button"
187
+ aria-label="Добавить блок снизу"
188
+ data-tooltip="Добавить блок"
189
+ @click.stop="postBuilderEvent('add-block', { position: 'after' })"
190
+ >
191
+ <img
192
+ :src="addBlockIcon"
193
+ alt=""
194
+ aria-hidden="true"
195
+ >
196
+ </button>
197
+
198
+ <button
199
+ class="block-editor-frame__control block-editor-frame__add-ai"
200
+ type="button"
201
+ :aria-label="`\u0421\u043E\u0437\u0434\u0430\u0442\u044C \u0431\u043B\u043E\u043A \u0447\u0435\u0440\u0435\u0437 AI \u043F\u043E\u0441\u043B\u0435 \u0431\u043B\u043E\u043A\u0430 ${blockVersionLabel}`"
202
+ data-tooltip="Создать блок через AI"
203
+ @click.stop="postBuilderEvent('open-create-block-assistant')"
204
+ >
205
+ <img
206
+ :src="aiAssistantIcon"
207
+ alt=""
208
+ aria-hidden="true"
209
+ >
210
+ </button>
211
+ </template>
212
+ </div>
213
+ </template>
214
+
215
+ <style scoped>
216
+ .block-editor-frame {
217
+ position: relative;
218
+ }
219
+ .block-editor-frame::after {
220
+ position: absolute;
221
+ z-index: 2147483645;
222
+ border: 1px dashed transparent;
223
+ content: "";
224
+ inset: 0;
225
+ pointer-events: none;
226
+ transition: border-color 120ms ease;
227
+ }
228
+ .block-editor-frame--builder-ready:hover::after, .block-editor-frame--builder-ready:focus-within::after {
229
+ border-color: #ff0099;
230
+ }
231
+
232
+ .block-editor-frame--disabled .block-editor-frame__content {
233
+ filter: grayscale(1);
234
+ opacity: 0.42;
235
+ }
236
+
237
+ .block-editor-frame__content {
238
+ transition: filter 180ms ease, opacity 180ms ease;
239
+ }
240
+
241
+ .block-editor-frame__toolbar,
242
+ .block-editor-frame__add,
243
+ .block-editor-frame__add-ai {
244
+ z-index: 2147483647;
245
+ opacity: 0;
246
+ pointer-events: none;
247
+ transition: opacity 120ms ease, transform 120ms ease;
248
+ }
249
+
250
+ .block-editor-frame__toolbar {
251
+ position: absolute;
252
+ display: flex;
253
+ gap: 4px;
254
+ align-items: center;
255
+ inset: 12px 12px auto auto;
256
+ transform: translateY(-4px);
257
+ }
258
+
259
+ .block-editor-frame__control {
260
+ position: relative;
261
+ box-sizing: border-box;
262
+ margin: 0;
263
+ color: #000;
264
+ font-family: Inter, Arial, sans-serif;
265
+ font-size: 11px;
266
+ font-style: normal;
267
+ font-weight: 400;
268
+ line-height: normal;
269
+ background: #fff;
270
+ border: 1px solid rgba(27, 67, 50, 0.12);
271
+ box-shadow: 0 1px 4px rgba(0, 0, 0, 0.1);
272
+ cursor: pointer;
273
+ appearance: none;
274
+ }
275
+ .block-editor-frame__control::after {
276
+ position: absolute;
277
+ z-index: 1;
278
+ padding: 6px 12px;
279
+ color: #fff;
280
+ font: 400 11px/normal Inter, Arial, sans-serif;
281
+ white-space: nowrap;
282
+ visibility: hidden;
283
+ background: #202020;
284
+ border-radius: 6px;
285
+ box-shadow: 0 4px 4px rgba(0, 0, 0, 0.25);
286
+ content: attr(data-tooltip);
287
+ opacity: 0;
288
+ pointer-events: none;
289
+ transition: opacity 100ms ease, visibility 100ms ease;
290
+ }
291
+ .block-editor-frame__control:hover::after, .block-editor-frame__control:focus-visible::after {
292
+ visibility: visible;
293
+ opacity: 1;
294
+ }
295
+ .block-editor-frame__control:focus-visible {
296
+ outline: 2px solid #0c8ce9;
297
+ outline-offset: 2px;
298
+ }
299
+ .block-editor-frame__control:disabled {
300
+ cursor: default;
301
+ opacity: 0.42;
302
+ }
303
+
304
+ .block-editor-frame__settings-icon {
305
+ position: relative;
306
+ display: block;
307
+ width: 20px;
308
+ height: 20px;
309
+ }
310
+ .block-editor-frame__settings-icon img {
311
+ position: absolute;
312
+ display: block;
313
+ }
314
+
315
+ .block-editor-frame__icon-button .block-editor-frame__settings-path {
316
+ inset: 1.16665px;
317
+ width: 17.6667px;
318
+ height: 17.6667px;
319
+ }
320
+
321
+ .block-editor-frame__icon-button .block-editor-frame__settings-center {
322
+ inset: 7px;
323
+ width: 6px;
324
+ height: 6px;
325
+ }
326
+
327
+ .block-editor-frame__toolbar .block-editor-frame__control::after {
328
+ top: calc(100% + 8px);
329
+ right: 0;
330
+ }
331
+
332
+ .block-editor-frame__version {
333
+ min-height: 32px;
334
+ padding: 8px 10px;
335
+ border-radius: 6px;
336
+ box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
337
+ }
338
+
339
+ .block-editor-frame__icon-button {
340
+ display: grid;
341
+ width: 32px;
342
+ height: 32px;
343
+ padding: 5px;
344
+ border-radius: 6px;
345
+ place-items: center;
346
+ }
347
+ .block-editor-frame__icon-button img {
348
+ display: block;
349
+ width: 20px;
350
+ height: 20px;
351
+ }
352
+
353
+ .block-editor-frame__add,
354
+ .block-editor-frame__add-ai {
355
+ position: absolute;
356
+ left: 50%;
357
+ display: grid;
358
+ width: 28px;
359
+ height: 28px;
360
+ padding: 6px;
361
+ border-radius: 50%;
362
+ box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
363
+ place-items: center;
364
+ }
365
+ .block-editor-frame__add img,
366
+ .block-editor-frame__add-ai img {
367
+ display: block;
368
+ width: 14px;
369
+ height: 14px;
370
+ }
371
+
372
+ .block-editor-frame__add-ai {
373
+ bottom: 0;
374
+ transform: translate(calc(-50% + 32px), 50%);
375
+ }
376
+ .block-editor-frame__add-ai::after {
377
+ bottom: calc(100% + 8px);
378
+ left: 50%;
379
+ transform: translateX(-50%);
380
+ }
381
+
382
+ .block-editor-frame__add--after {
383
+ bottom: 0;
384
+ transform: translate(-50%, 50%);
385
+ }
386
+ .block-editor-frame__add--after::after {
387
+ bottom: calc(100% + 8px);
388
+ left: 50%;
389
+ transform: translateX(-50%);
390
+ }
391
+
392
+ .block-editor-frame--builder-ready:hover .block-editor-frame__toolbar,
393
+ .block-editor-frame--builder-ready:focus-within .block-editor-frame__toolbar,
394
+ .block-editor-frame--builder-ready:hover .block-editor-frame__add,
395
+ .block-editor-frame--builder-ready:focus-within .block-editor-frame__add,
396
+ .block-editor-frame--builder-ready:hover .block-editor-frame__add-ai,
397
+ .block-editor-frame--builder-ready:focus-within .block-editor-frame__add-ai {
398
+ opacity: 1;
399
+ pointer-events: auto;
400
+ }
401
+
402
+ .block-editor-frame--builder-ready:hover .block-editor-frame__toolbar,
403
+ .block-editor-frame--builder-ready:focus-within .block-editor-frame__toolbar {
404
+ transform: translateY(0);
405
+ }
406
+
407
+ @media (max-width: 499px) {
408
+ .block-editor-frame--builder-ready:hover::after,
409
+ .block-editor-frame--builder-ready:focus-within::after {
410
+ border-color: transparent;
411
+ }
412
+ .block-editor-frame__toolbar,
413
+ .block-editor-frame__add,
414
+ .block-editor-frame__add-ai {
415
+ display: none;
416
+ }
417
+ }
418
+ </style>
@@ -0,0 +1,16 @@
1
+ import { type Component } from 'vue';
2
+ import type { BlockOptions, PageRegion } from '#toaster-site-runtime/types/page';
3
+ type __VLS_Props = {
4
+ blockComponent: Component;
5
+ blockId: string;
6
+ blockIndex: number;
7
+ builderReady: boolean;
8
+ enabled: boolean;
9
+ options: BlockOptions;
10
+ placementId: string;
11
+ placementCount: number;
12
+ region: PageRegion;
13
+ };
14
+ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
15
+ declare const _default: typeof __VLS_export;
16
+ export default _default;
@@ -0,0 +1,16 @@
1
+ type __VLS_Props = {
2
+ placementId: string;
3
+ };
4
+ declare var __VLS_1: {};
5
+ type __VLS_Slots = {} & {
6
+ default?: (props: typeof __VLS_1) => any;
7
+ };
8
+ declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
9
+ declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
10
+ declare const _default: typeof __VLS_export;
11
+ export default _default;
12
+ type __VLS_WithSlots<T, S> = T & {
13
+ new (): {
14
+ $slots: S;
15
+ };
16
+ };
@@ -0,0 +1,12 @@
1
+ <script setup>
2
+ import { provide, toRef } from "vue";
3
+ import { blockPlacementIdKey } from "#toaster-site-runtime/utils/block-placement";
4
+ const props = defineProps({
5
+ placementId: { type: String, required: true }
6
+ });
7
+ provide(blockPlacementIdKey, toRef(props, "placementId"));
8
+ </script>
9
+
10
+ <template>
11
+ <slot />
12
+ </template>
@@ -0,0 +1,16 @@
1
+ type __VLS_Props = {
2
+ placementId: string;
3
+ };
4
+ declare var __VLS_1: {};
5
+ type __VLS_Slots = {} & {
6
+ default?: (props: typeof __VLS_1) => any;
7
+ };
8
+ declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
9
+ declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
10
+ declare const _default: typeof __VLS_export;
11
+ export default _default;
12
+ type __VLS_WithSlots<T, S> = T & {
13
+ new (): {
14
+ $slots: S;
15
+ };
16
+ };
@@ -0,0 +1,16 @@
1
+ import { type Component } from 'vue';
2
+ import type { BlockOptions, BlockPlacement, PageRegion } from '#toaster-site-runtime/types/page';
3
+ type __VLS_Props = {
4
+ builderReady: boolean;
5
+ isPlacementEnabled: (placement: BlockPlacement) => boolean;
6
+ pagePlacements: (region: PageRegion) => BlockPlacement[];
7
+ placementKey: (region: PageRegion, placement: BlockPlacement) => string;
8
+ region: PageRegion;
9
+ resolveBlock: (id: string) => Component;
10
+ resolveBlockOptions: (placement: BlockPlacement & {
11
+ options?: BlockOptions;
12
+ }) => BlockOptions;
13
+ };
14
+ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
15
+ declare const _default: typeof __VLS_export;
16
+ export default _default;