@toototech/webbuilder-plugins 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 (193) hide show
  1. package/LICENSE +1 -0
  2. package/README.md +3 -0
  3. package/dist/basic/cssScope.d.ts +3 -0
  4. package/dist/basic/index.d.ts +81 -0
  5. package/dist/basic/injectStyle.d.ts +20 -0
  6. package/dist/basic/plugin.d.ts +19 -0
  7. package/dist/basic/publisher.d.ts +4 -0
  8. package/dist/basic/registries/interactive/accordion/index.d.ts +3 -0
  9. package/dist/basic/registries/interactive/backButton/index.d.ts +3 -0
  10. package/dist/basic/registries/interactive/button/index.d.ts +10 -0
  11. package/dist/basic/registries/interactive/countUp/index.d.ts +9 -0
  12. package/dist/basic/registries/interactive/customCode/index.d.ts +3 -0
  13. package/dist/basic/registries/interactive/index.d.ts +2 -0
  14. package/dist/basic/registries/interactive/inquiryForm/index.d.ts +3 -0
  15. package/dist/basic/registries/interactive/klaviyoSubscribe/index.d.ts +3 -0
  16. package/dist/basic/registries/interactive/popup/index.d.ts +5 -0
  17. package/dist/basic/registries/interactive/salesmartlyChatButton/index.d.ts +10 -0
  18. package/dist/basic/registries/interactive/search/index.d.ts +10 -0
  19. package/dist/basic/registries/interactive/socialShare/index.d.ts +33 -0
  20. package/dist/basic/registries/interactive/tabs/index.d.ts +3 -0
  21. package/dist/basic/registries/layout/container/index.d.ts +19 -0
  22. package/dist/basic/registries/layout/divider/index.d.ts +7 -0
  23. package/dist/basic/registries/layout/grid/index.d.ts +11 -0
  24. package/dist/basic/registries/layout/index.d.ts +2 -0
  25. package/dist/basic/registries/layout/layoutBase/index.d.ts +10 -0
  26. package/dist/basic/registries/layout/section/index.d.ts +3 -0
  27. package/dist/basic/registries/layout/sectionGridBlock/index.d.ts +3 -0
  28. package/dist/basic/registries/layout/spacer/index.d.ts +7 -0
  29. package/dist/basic/registries/media/banner/index.d.ts +11 -0
  30. package/dist/basic/registries/media/carousel/index.d.ts +6 -0
  31. package/dist/basic/registries/media/flipbook/index.d.ts +5 -0
  32. package/dist/basic/registries/media/icon/index.d.ts +3 -0
  33. package/dist/basic/registries/media/image/index.d.ts +3 -0
  34. package/dist/basic/registries/media/index.d.ts +2 -0
  35. package/dist/basic/registries/media/industryTabs/index.d.ts +3 -0
  36. package/dist/basic/registries/media/marquee/index.d.ts +4 -0
  37. package/dist/basic/registries/media/ourSolutions/helpers.d.ts +289 -0
  38. package/dist/basic/registries/media/ourSolutions/index.d.ts +4 -0
  39. package/dist/basic/registries/media/ourSolutions/script.d.ts +1 -0
  40. package/dist/basic/registries/media/ourSolutions/style.d.ts +1 -0
  41. package/dist/basic/registries/media/pdfViewer/index.d.ts +3 -0
  42. package/dist/basic/registries/media/productCategories/index.d.ts +4 -0
  43. package/dist/basic/registries/media/tabMediaGallery/index.d.ts +3 -0
  44. package/dist/basic/registries/media/video/index.d.ts +12 -0
  45. package/dist/basic/registries/navigation/footer/index.d.ts +10 -0
  46. package/dist/basic/registries/navigation/index.d.ts +2 -0
  47. package/dist/basic/registries/navigation/languageSwitcher/index.d.ts +6 -0
  48. package/dist/basic/registries/navigation/logo/index.d.ts +9 -0
  49. package/dist/basic/registries/navigation/navbar/constants.d.ts +38 -0
  50. package/dist/basic/registries/navigation/navbar/factories.d.ts +848 -0
  51. package/dist/basic/registries/navigation/navbar/helpers.d.ts +12 -0
  52. package/dist/basic/registries/navigation/navbar/index.d.ts +4 -0
  53. package/dist/basic/registries/navigation/navbar/registerMegaTypes.d.ts +2 -0
  54. package/dist/basic/registries/navigation/navbar/registerMenuTypes.d.ts +2 -0
  55. package/dist/basic/registries/navigation/navbar/registerRootTypes.d.ts +2 -0
  56. package/dist/basic/registries/navigation/navbar/script.d.ts +1 -0
  57. package/dist/basic/registries/navigation/navbar/style.d.ts +1 -0
  58. package/dist/basic/registries/navigation/socialLinks/index.d.ts +3 -0
  59. package/dist/basic/registries/section/allApplications/index.d.ts +3 -0
  60. package/dist/basic/registries/section/cardCarouselSection/index.d.ts +3 -0
  61. package/dist/basic/registries/section/caseSpotlight/index.d.ts +3 -0
  62. package/dist/basic/registries/section/companyScale/index.d.ts +3 -0
  63. package/dist/basic/registries/section/customizationGrid/index.d.ts +3 -0
  64. package/dist/basic/registries/section/factoryMap/index.d.ts +3 -0
  65. package/dist/basic/registries/section/focaHistoryTimeline/index.d.ts +3 -0
  66. package/dist/basic/registries/section/historyTimeline/index.d.ts +3 -0
  67. package/dist/basic/registries/section/homeBannerCarousel/index.d.ts +4 -0
  68. package/dist/basic/registries/section/hotspotShowcase/index.d.ts +30 -0
  69. package/dist/basic/registries/section/index.d.ts +2 -0
  70. package/dist/basic/registries/section/map/index.d.ts +4 -0
  71. package/dist/basic/registries/section/milestoneCardStrip/index.d.ts +3 -0
  72. package/dist/basic/registries/section/moreCardCarousel/index.d.ts +3 -0
  73. package/dist/basic/registries/section/ourAdvantages/index.d.ts +4 -0
  74. package/dist/basic/registries/section/overviewSplit/index.d.ts +3 -0
  75. package/dist/basic/registries/section/processTimeline/index.d.ts +3 -0
  76. package/dist/basic/registries/section/productCardStrip/index.d.ts +3 -0
  77. package/dist/basic/registries/section/resourceSection/index.d.ts +6 -0
  78. package/dist/basic/registries/section/responsiveHeroCarousel/index.d.ts +4 -0
  79. package/dist/basic/registries/section/serviceIconGrid/index.d.ts +4 -0
  80. package/dist/basic/registries/section/servicesCarousel/index.d.ts +4 -0
  81. package/dist/basic/registries/section/servicesShowcase/index.d.ts +4 -0
  82. package/dist/basic/registries/section/servicesThb/index.d.ts +4 -0
  83. package/dist/basic/registries/section/solutionList/index.d.ts +4 -0
  84. package/dist/basic/registries/section/staticPinMap/index.d.ts +4 -0
  85. package/dist/basic/registries/section/statsCards/index.d.ts +3 -0
  86. package/dist/basic/registries/section/swiperRuntime.d.ts +3 -0
  87. package/dist/basic/registries/shared/sharedTraits.d.ts +37 -0
  88. package/dist/basic/registries/types.d.ts +5 -0
  89. package/dist/basic/registries/typography/heading/index.d.ts +8 -0
  90. package/dist/basic/registries/typography/index.d.ts +2 -0
  91. package/dist/basic/registries/typography/textEditor/index.d.ts +6 -0
  92. package/dist/basic/registryManifest.d.ts +9 -0
  93. package/dist/basic/styleHelpers.d.ts +29 -0
  94. package/dist/basic/svgIcon.d.ts +11 -0
  95. package/dist/basic/traitBridge.d.ts +20 -0
  96. package/dist/basic/traitFactory.d.ts +106 -0
  97. package/dist/basic.js +1146 -0
  98. package/dist/cms/cmsFactory.d.ts +164 -0
  99. package/dist/cms/dynamicRenderPipeline.d.ts +12 -0
  100. package/dist/cms/index.d.ts +31 -0
  101. package/dist/cms/plugin.d.ts +12 -0
  102. package/dist/cms/publisher.d.ts +7 -0
  103. package/dist/cms/registries/dynamic/cms/constants.d.ts +16 -0
  104. package/dist/cms/registries/dynamic/cms/dynamicField/bindings.d.ts +78 -0
  105. package/dist/cms/registries/dynamic/cms/dynamicField/blocks/breadcrumbBlock.d.ts +1 -0
  106. package/dist/cms/registries/dynamic/cms/dynamicField/blocks/conditionalBlock.d.ts +1 -0
  107. package/dist/cms/registries/dynamic/cms/dynamicField/blocks/datetimeBlock.d.ts +1 -0
  108. package/dist/cms/registries/dynamic/cms/dynamicField/blocks/htmlBlock.d.ts +1 -0
  109. package/dist/cms/registries/dynamic/cms/dynamicField/blocks/imageBlock.d.ts +1 -0
  110. package/dist/cms/registries/dynamic/cms/dynamicField/blocks/linkBlock.d.ts +1 -0
  111. package/dist/cms/registries/dynamic/cms/dynamicField/blocks/seoBlock.d.ts +1 -0
  112. package/dist/cms/registries/dynamic/cms/dynamicField/blocks/textBlock.d.ts +1 -0
  113. package/dist/cms/registries/dynamic/cms/dynamicField/blocks/tocBlock.d.ts +1 -0
  114. package/dist/cms/registries/dynamic/cms/dynamicField/constants.d.ts +19 -0
  115. package/dist/cms/registries/dynamic/cms/dynamicField/helpers.d.ts +52 -0
  116. package/dist/cms/registries/dynamic/cms/dynamicField/registerBlock.d.ts +57 -0
  117. package/dist/cms/registries/dynamic/cms/dynamicField/styles.d.ts +7 -0
  118. package/dist/cms/registries/dynamic/cms/media/previewMediaTrait.d.ts +7 -0
  119. package/dist/cms/registries/dynamic/cms/menu/siteMenuAttrs.d.ts +11 -0
  120. package/dist/cms/registries/dynamic/cms/menuTree/menuTreeAttrs.d.ts +8 -0
  121. package/dist/cms/registries/dynamic/cms/post/styles.d.ts +6 -0
  122. package/dist/cms/registries/dynamic/cms/product/detail.styles.d.ts +1 -0
  123. package/dist/cms/registries/dynamic/cms/product/detailV2.styles.d.ts +1 -0
  124. package/dist/cms/registries/dynamic/cms/product/previewProductTrait.d.ts +6 -0
  125. package/dist/cms/registries/dynamic/cms/product/styles.d.ts +6 -0
  126. package/dist/cms/registries/dynamic/dataProvider.d.ts +45 -0
  127. package/dist/cms/registries/dynamic/loopGrid/paginationStyles.d.ts +5 -0
  128. package/dist/cms/registries/dynamic/loopGrid/preview.d.ts +16 -0
  129. package/dist/cms/registries/dynamic/loopGrid/publisher.d.ts +3 -0
  130. package/dist/cms/registries/dynamic/loopGrid/types.d.ts +97 -0
  131. package/dist/cms/registries/navigation/navbarThb/index.d.ts +3 -0
  132. package/dist/cms/registries/navigation/navbarThb/script.d.ts +1 -0
  133. package/dist/cms/registries/navigation/navbarThb/style.d.ts +1 -0
  134. package/dist/cms.js +4535 -0
  135. package/dist/global-settings/components/FontFamilySelect.vue.d.ts +29 -0
  136. package/dist/global-settings/components/FontManagerPanel.vue.d.ts +37 -0
  137. package/dist/global-settings/index.d.ts +8 -0
  138. package/dist/global-settings/plugin.d.ts +3 -0
  139. package/dist/global-settings/publisher.d.ts +15 -0
  140. package/dist/global-settings/runtime/canvasInjection.d.ts +13 -0
  141. package/dist/global-settings/runtime/panelDraftSave.d.ts +17 -0
  142. package/dist/global-settings/runtime/settingsSource.d.ts +4 -0
  143. package/dist/global-settings/useFontManager.d.ts +38 -0
  144. package/dist/global-settings/useGoogleFonts.d.ts +20 -0
  145. package/dist/global-settings/vue.d.ts +1 -0
  146. package/dist/global-settings.js +66 -0
  147. package/dist/i18n/I18nPanel.vue.d.ts +23 -0
  148. package/dist/i18n/i18n.d.ts +25 -0
  149. package/dist/i18n/index.d.ts +7 -0
  150. package/dist/i18n/languageOrder.d.ts +9 -0
  151. package/dist/i18n/plugin.d.ts +21 -0
  152. package/dist/i18n/types.d.ts +101 -0
  153. package/dist/i18n/useWebBuilderI18n.d.ts +164 -0
  154. package/dist/i18n/vue.d.ts +1 -0
  155. package/dist/i18n-BYR3l48y.js +959 -0
  156. package/dist/i18n.js +929 -0
  157. package/dist/index-CxJlLwvG.js +35378 -0
  158. package/dist/index-DWfJ4PBm.js +5724 -0
  159. package/dist/index.d.ts +9 -0
  160. package/dist/index.js +12 -0
  161. package/dist/layout-template/components/LayoutPanel.vue.d.ts +37 -0
  162. package/dist/layout-template/components/TemplateRulesPanel.vue.d.ts +41 -0
  163. package/dist/layout-template/config/layoutSharedResources.d.ts +9 -0
  164. package/dist/layout-template/config/templateSharedResources.d.ts +28 -0
  165. package/dist/layout-template/index.d.ts +9 -0
  166. package/dist/layout-template/plugin.d.ts +13 -0
  167. package/dist/layout-template/runtime/storageAdapter.d.ts +49 -0
  168. package/dist/layout-template/utils/layoutProjectData.d.ts +15 -0
  169. package/dist/layout-template/utils/layoutRulePages.d.ts +19 -0
  170. package/dist/layout-template/utils/layoutSettings.d.ts +45 -0
  171. package/dist/layout-template/utils/templateRules.d.ts +52 -0
  172. package/dist/layout-template/vue.d.ts +2 -0
  173. package/dist/layout-template.js +435 -0
  174. package/dist/layoutSettings-D4SYUMri.js +252 -0
  175. package/dist/plugin-BPA8qlaC.js +40 -0
  176. package/dist/plugin-C0PrxrIe.js +228 -0
  177. package/dist/plugin-DQshk1sY.js +361 -0
  178. package/dist/plugin-DebyCjXx.js +191 -0
  179. package/dist/plugin-Dr6TOtyH.js +73 -0
  180. package/dist/publisher/index.d.ts +5 -0
  181. package/dist/publisher/publisherAssets.d.ts +9 -0
  182. package/dist/publisher/publisherComponents.d.ts +7 -0
  183. package/dist/publisher/publisherPlugins.d.ts +12 -0
  184. package/dist/publisher-C6VWXq8u.js +25 -0
  185. package/dist/publisher.js +1711 -0
  186. package/dist/solar-BsElUqfQ.js +29843 -0
  187. package/dist/style.css +1181 -0
  188. package/dist/templateSharedResources-D1u7eFIs.js +89 -0
  189. package/dist/types-DNbok59z.js +2359 -0
  190. package/dist/useFontManager-CdrLq1eG.js +336 -0
  191. package/dist/vue.d.ts +3 -0
  192. package/dist/vue.js +2171 -0
  193. package/package.json +77 -0
@@ -0,0 +1,1711 @@
1
+ import { createWebBuilderPluginManager, collectPublisherContributions, collectProjectDataComponentTypes } from "@toototech/webbuilder/core";
2
+ import { collectPublisherContributions as collectPublisherContributions2 } from "@toototech/webbuilder/core";
3
+ import { c as createCmsComponentsPlugin } from "./plugin-C0PrxrIe.js";
4
+ import { c as createGlobalSettingsPlugin } from "./plugin-DQshk1sY.js";
5
+ import { r as registerBasicPublisherComponents } from "./publisher-C6VWXq8u.js";
6
+ import { e as encodeLoopGridSchema, L as LOOP_GRID_PAGINATION_STYLE, a as LOOP_GRID_PREV_ICON, b as LOOP_GRID_NEXT_ICON, c as LOOP_GRID_PAGINATION_SCRIPT, p as parseNumber, D as DEFAULT_LOOP_GRID_SCHEMA, d as parseCsvList, W as WB_CMS_MENU_TREE_TYPE, f as DEFAULT_MENU_TREE_CODE, r as registerDynamicTextBlock, g as registerDynamicHtmlBlock, h as registerDynamicImageBlock, i as registerDynamicLinkBlock, j as registerDynamicDatetimeBlock, k as registerDynamicConditionalBlock, l as registerDynamicBreadcrumbBlock, m as registerDynamicTocBlock, n as registerDynamicSeoBlock } from "./types-DNbok59z.js";
7
+ const appendAssetFragment = (left, right) => {
8
+ const fragments = [left, right].filter(
9
+ (fragment) => typeof fragment === "string" && fragment.trim() !== ""
10
+ );
11
+ return fragments.length > 0 ? fragments.join("\n") : void 0;
12
+ };
13
+ const isRecord = (value) => Boolean(value) && typeof value === "object" && !Array.isArray(value);
14
+ const mergePublisherMetadata = (left, right) => {
15
+ if (!left && !right)
16
+ return void 0;
17
+ if (!left)
18
+ return { ...right };
19
+ if (!right)
20
+ return { ...left };
21
+ const merged = { ...left };
22
+ Object.entries(right).forEach(([key, value]) => {
23
+ const previous = merged[key];
24
+ merged[key] = isRecord(previous) && isRecord(value) ? { ...previous, ...value } : value;
25
+ });
26
+ return merged;
27
+ };
28
+ const mergePublisherAssets = (left, right) => {
29
+ const metadata = mergePublisherMetadata(left.metadata, right.metadata);
30
+ return {
31
+ css: appendAssetFragment(left.css, right.css),
32
+ headHtml: appendAssetFragment(left.headHtml, right.headHtml),
33
+ bodyStartHtml: appendAssetFragment(left.bodyStartHtml, right.bodyStartHtml),
34
+ bodyEndHtml: appendAssetFragment(left.bodyEndHtml, right.bodyEndHtml),
35
+ ...metadata ? { metadata } : {}
36
+ };
37
+ };
38
+ const renderWebBuilderPublisherAssets = async (contributions, context) => {
39
+ var _a;
40
+ let assets = {};
41
+ for (const contribution of contributions) {
42
+ const rendered = await ((_a = contribution.render) == null ? void 0 : _a.call(contribution, context));
43
+ if (!rendered)
44
+ continue;
45
+ assets = mergePublisherAssets(assets, rendered);
46
+ }
47
+ return assets;
48
+ };
49
+ const createWebBuilderPublisherPluginRegistry = (options) => {
50
+ const activePlugins = createWebBuilderPluginManager(options.plugins).resolve(
51
+ options.resolveContext
52
+ );
53
+ const publisherContributions = collectPublisherContributions(activePlugins);
54
+ return {
55
+ activePlugins,
56
+ publisherContributions,
57
+ renderPublisherAssets: (context) => renderWebBuilderPublisherAssets(publisherContributions, context)
58
+ };
59
+ };
60
+ const createPublisherTenantContext = (tenant = {}) => ({
61
+ roles: tenant.roles ?? [],
62
+ permissions: tenant.permissions ?? /* @__PURE__ */ new Set(),
63
+ tenantId: tenant.tenantId,
64
+ userId: tenant.userId,
65
+ getAccessToken: tenant.getAccessToken,
66
+ getEffectiveTenantId: tenant.getEffectiveTenantId
67
+ });
68
+ const WEB_BUILDER_PUBLISHER_FEATURE_PLUGINS = [
69
+ createGlobalSettingsPlugin(),
70
+ createCmsComponentsPlugin()
71
+ ];
72
+ const createWebBuilderPublisherRuntimeRegistry = (options) => {
73
+ const projectData = options.projectData ?? null;
74
+ const usedComponentTypes = collectProjectDataComponentTypes(projectData);
75
+ return createWebBuilderPublisherPluginRegistry({
76
+ plugins: WEB_BUILDER_PUBLISHER_FEATURE_PLUGINS,
77
+ resolveContext: {
78
+ resource: options.resource ?? {},
79
+ projectData,
80
+ usedComponentTypes,
81
+ capabilityIds: new Set(options.capabilityIds ?? []),
82
+ tenant: createPublisherTenantContext(options.tenant)
83
+ }
84
+ });
85
+ };
86
+ const renderWebBuilderPublisherPluginAssets = async (options) => createWebBuilderPublisherRuntimeRegistry(options).renderPublisherAssets({
87
+ projectData: options.projectData ?? null,
88
+ globalSettings: options.globalSettings ?? null
89
+ });
90
+ const WB_LOOP_GRID_TYPE = "wb-loop-grid";
91
+ const LOOP_GRID_CSS = `
92
+ [data-wb-component="loop-grid"]{display:block;width:100%;min-height:180px;}
93
+ .wb-loop-grid{display:block;width:100%;overflow-x:visible;}
94
+ .wb-loop-grid__grid{display:grid;width:100%;align-items:stretch;}
95
+ .wb-loop-grid__item{display:flex;flex-direction:column;min-width:0;}
96
+ .wb-loop-grid__fallback-card{gap:10px;color:#0f172a;}
97
+ .wb-loop-grid__fallback-media{aspect-ratio:4/3;width:100%;object-fit:cover;background:#f3f4f6;}
98
+ .wb-loop-grid__fallback-title{margin:0;color:#041038;font-size:20px;line-height:1.2;font-weight:700;}
99
+ .wb-loop-grid__fallback-text{margin:0;color:#4b5563;font-size:14px;line-height:1.6;}
100
+ .wb-loop-grid__fallback-link{color:#264faa;text-decoration:none;font-weight:700;}
101
+ `;
102
+ const escapeAttr = (value) => String(value ?? "").replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
103
+ const normalizeLoopItemType = (value) => {
104
+ const raw = String(value ?? "").trim();
105
+ return raw || DEFAULT_LOOP_GRID_SCHEMA.loopItemType;
106
+ };
107
+ const resolveCmsComponentType = (loopItemType) => {
108
+ if (loopItemType === "product" || loopItemType === "productCategory")
109
+ return "product-list";
110
+ if (loopItemType === "media" || loopItemType === "mediaCategory")
111
+ return "media-list";
112
+ if (loopItemType === "productCategoryFaq")
113
+ return "product-category-faq";
114
+ return "post-list";
115
+ };
116
+ const resolvePaginationMode = (value) => String(value ?? "").trim() === "none" ? "none" : "numbers";
117
+ const resolveFallbackBindings = (loopItemType) => {
118
+ if (loopItemType === "product" || loopItemType === "productCategory") {
119
+ return {
120
+ prefix: "product",
121
+ title: "Product title",
122
+ excerpt: "Product description",
123
+ image: "https://dummyimage.com/640x480/f3f4f6/0f172a&text=Product"
124
+ };
125
+ }
126
+ if (loopItemType === "media" || loopItemType === "mediaCategory") {
127
+ return {
128
+ prefix: "media",
129
+ title: "Media title",
130
+ excerpt: "Media description",
131
+ image: "https://dummyimage.com/640x480/f3f4f6/0f172a&text=Media"
132
+ };
133
+ }
134
+ return {
135
+ prefix: "post",
136
+ title: "Post title",
137
+ excerpt: "Post excerpt",
138
+ image: "https://dummyimage.com/640x480/f3f4f6/0f172a&text=Post"
139
+ };
140
+ };
141
+ const renderFallbackLoopItem = (loopItemType) => {
142
+ const bindings = resolveFallbackBindings(loopItemType);
143
+ return `
144
+ <article class="wb-loop-grid__item wb-loop-grid__fallback-card">
145
+ <img class="wb-loop-grid__fallback-media" src="${escapeAttr(bindings.image)}" alt="" data-cms-bind-src="${bindings.prefix}.image" data-cms-bind-alt="${bindings.prefix}.name">
146
+ <h3 class="wb-loop-grid__fallback-title" data-cms-bind="${bindings.prefix}.name">${escapeAttr(bindings.title)}</h3>
147
+ <p class="wb-loop-grid__fallback-text" data-cms-bind="${bindings.prefix}.description">${escapeAttr(bindings.excerpt)}</p>
148
+ <a class="wb-loop-grid__fallback-link" href="#" data-cms-bind-href="${bindings.prefix}.url">Learn more</a>
149
+ </article>
150
+ `;
151
+ };
152
+ const buildLoopGridStyle = (schema) => {
153
+ const columns = parseNumber(schema.layout.columns, DEFAULT_LOOP_GRID_SCHEMA.layout.columns, {
154
+ min: 1,
155
+ max: 6
156
+ });
157
+ const columnGap = parseNumber(
158
+ schema.layout.columnGap,
159
+ DEFAULT_LOOP_GRID_SCHEMA.layout.columnGap,
160
+ { min: 0, max: 120 }
161
+ );
162
+ const rowGap = parseNumber(schema.layout.rowGap, DEFAULT_LOOP_GRID_SCHEMA.layout.rowGap, {
163
+ min: 0,
164
+ max: 120
165
+ });
166
+ return [
167
+ `grid-template-columns:repeat(${columns},minmax(0,1fr))`,
168
+ `column-gap:${columnGap}px`,
169
+ `row-gap:${rowGap}px`
170
+ ].join(";");
171
+ };
172
+ const buildLoopGridSchema = (model) => {
173
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q;
174
+ const attrs = ((_a = model.getAttributes) == null ? void 0 : _a.call(model)) || {};
175
+ const loopItemType = normalizeLoopItemType(
176
+ ((_b = model.get) == null ? void 0 : _b.call(model, "loopItemType")) ?? attrs["data-loop-item-type"]
177
+ );
178
+ const itemsPerPage = parseNumber(
179
+ ((_c = model.get) == null ? void 0 : _c.call(model, "itemsPerPage")) ?? attrs["data-page-size"] ?? attrs["data-wb-page-size"],
180
+ DEFAULT_LOOP_GRID_SCHEMA.layout.itemsPerPage,
181
+ { min: 1, max: 60 }
182
+ );
183
+ return {
184
+ ...DEFAULT_LOOP_GRID_SCHEMA,
185
+ gridId: String(
186
+ ((_d = model.get) == null ? void 0 : _d.call(model, "gridId")) ?? attrs["data-wb-grid-id"] ?? ((_e = model.getId) == null ? void 0 : _e.call(model)) ?? model.cid ?? DEFAULT_LOOP_GRID_SCHEMA.gridId
187
+ ),
188
+ filterKey: String(((_f = model.get) == null ? void 0 : _f.call(model, "filterKey")) ?? attrs["data-wb-filter-key"] ?? ""),
189
+ providerKey: String(
190
+ ((_g = model.get) == null ? void 0 : _g.call(model, "providerKey")) ?? attrs["data-wb-provider-key"] ?? DEFAULT_LOOP_GRID_SCHEMA.providerKey
191
+ ),
192
+ itemTemplateId: String(
193
+ ((_h = model.get) == null ? void 0 : _h.call(model, "itemTemplateId")) ?? attrs["data-wb-item-template-id"] ?? DEFAULT_LOOP_GRID_SCHEMA.itemTemplateId
194
+ ),
195
+ loopItemType,
196
+ loopItemTemplateResourceId: String(
197
+ ((_i = model.get) == null ? void 0 : _i.call(model, "loopItemTemplateResourceId")) ?? attrs["data-loop-item-template-resource-id"] ?? ""
198
+ ),
199
+ query: {
200
+ ...DEFAULT_LOOP_GRID_SCHEMA.query,
201
+ category: parseCsvList(
202
+ ((_j = model.get) == null ? void 0 : _j.call(model, "categoryFilter")) ?? attrs["data-category-id"] ?? attrs["data-wb-category-id"] ?? ""
203
+ ),
204
+ orderBy: String(((_k = model.get) == null ? void 0 : _k.call(model, "orderBy")) ?? attrs["data-wb-sort-field"] ?? "date"),
205
+ order: ((_l = model.get) == null ? void 0 : _l.call(model, "order")) ?? (attrs["data-wb-sort-asc"] === "true" || attrs["data-sort-asc"] === "true" ? "asc" : DEFAULT_LOOP_GRID_SCHEMA.query.order)
206
+ },
207
+ layout: {
208
+ ...DEFAULT_LOOP_GRID_SCHEMA.layout,
209
+ columns: parseNumber((_m = model.get) == null ? void 0 : _m.call(model, "columns"), DEFAULT_LOOP_GRID_SCHEMA.layout.columns, {
210
+ min: 1,
211
+ max: 6
212
+ }),
213
+ itemsPerPage,
214
+ columnGap: parseNumber(
215
+ (_n = model.get) == null ? void 0 : _n.call(model, "columnGap"),
216
+ DEFAULT_LOOP_GRID_SCHEMA.layout.columnGap,
217
+ { min: 0, max: 120 }
218
+ ),
219
+ rowGap: parseNumber((_o = model.get) == null ? void 0 : _o.call(model, "rowGap"), DEFAULT_LOOP_GRID_SCHEMA.layout.rowGap, {
220
+ min: 0,
221
+ max: 120
222
+ })
223
+ },
224
+ pagination: {
225
+ ...DEFAULT_LOOP_GRID_SCHEMA.pagination,
226
+ mode: resolvePaginationMode(
227
+ ((_p = model.get) == null ? void 0 : _p.call(model, "paginationType")) ?? attrs["data-pagination"] ?? attrs["data-wb-pagination"]
228
+ ),
229
+ pageLimit: parseNumber(
230
+ ((_q = model.get) == null ? void 0 : _q.call(model, "pageLimit")) ?? attrs["data-max-pages"] ?? attrs["data-wb-max-pages"],
231
+ DEFAULT_LOOP_GRID_SCHEMA.pagination.pageLimit,
232
+ { min: 1, max: 50 }
233
+ )
234
+ }
235
+ };
236
+ };
237
+ const buildCmsRenderAttrs = (schema) => {
238
+ const loopItemType = normalizeLoopItemType(schema.loopItemType);
239
+ const cmsComponent = resolveCmsComponentType(loopItemType);
240
+ const categoryId = schema.query.category[0] || "";
241
+ return {
242
+ class: "wb-loop-grid",
243
+ "data-cms-component": cmsComponent,
244
+ "data-page-size": String(schema.layout.itemsPerPage),
245
+ "data-wb-page-size": String(schema.layout.itemsPerPage),
246
+ "data-pagination": resolvePaginationMode(schema.pagination.mode),
247
+ "data-wb-pagination": resolvePaginationMode(schema.pagination.mode),
248
+ "data-max-pages": String(schema.pagination.pageLimit),
249
+ "data-wb-max-pages": String(schema.pagination.pageLimit),
250
+ "data-category-id": categoryId,
251
+ "data-wb-category-id": categoryId,
252
+ "data-loop-item-type": loopItemType,
253
+ "data-loop-item-template-resource-id": schema.loopItemTemplateResourceId
254
+ };
255
+ };
256
+ const renderLoopGridPublishHtml = (schema) => {
257
+ const loopItemType = normalizeLoopItemType(schema.loopItemType);
258
+ const cmsComponent = resolveCmsComponentType(loopItemType);
259
+ const paginationClass = cmsComponent === "product-list" ? "wb-product-list-pagination" : cmsComponent === "media-list" ? "wb-cms-media-pagination" : "wb-post-list-pagination";
260
+ const pageBtnClass = cmsComponent === "product-list" ? "wb-product-list-page-btn" : cmsComponent === "media-list" ? "wb-cms-media-page-btn" : "wb-post-list-page-btn";
261
+ const pagination = resolvePaginationMode(schema.pagination.mode) === "none" ? "" : `
262
+ ${LOOP_GRID_PAGINATION_STYLE}
263
+ <nav data-cms-pagination class="${paginationClass} wb-loop-grid-pagination">
264
+ <span class="${pageBtnClass} wb-loop-grid-pagination__btn" aria-label="上一页">${LOOP_GRID_PREV_ICON}</span>
265
+ <span class="${pageBtnClass} wb-loop-grid-pagination__number active">1</span>
266
+ <span class="${pageBtnClass} wb-loop-grid-pagination__number">2</span>
267
+ <span class="${pageBtnClass} wb-loop-grid-pagination__number">3</span>
268
+ <span class="${pageBtnClass} wb-loop-grid-pagination__btn" aria-label="下一页">${LOOP_GRID_NEXT_ICON}</span>
269
+ </nav>
270
+ ${LOOP_GRID_PAGINATION_SCRIPT}
271
+ `;
272
+ return `
273
+ <div class="wb-loop-grid__grid" data-wb-loop-grid-cards="${escapeAttr(schema.gridId)}" style="${escapeAttr(buildLoopGridStyle(schema))}">
274
+ ${renderFallbackLoopItem(loopItemType)}
275
+ </div>
276
+ ${pagination}
277
+ `;
278
+ };
279
+ function registerLoopGridPublisherComponent(editor) {
280
+ const domComponents = editor == null ? void 0 : editor.DomComponents;
281
+ if (!domComponents || domComponents.getType(WB_LOOP_GRID_TYPE))
282
+ return;
283
+ domComponents.addType(WB_LOOP_GRID_TYPE, {
284
+ isComponent: (el) => {
285
+ var _a;
286
+ if (!(el == null ? void 0 : el.getAttribute))
287
+ return false;
288
+ return el.getAttribute("data-wb-component") === "loop-grid" || el.getAttribute("data-cms-component") === "loop-grid" || ((_a = el.classList) == null ? void 0 : _a.contains("wb-loop-grid")) ? { type: WB_LOOP_GRID_TYPE } : false;
289
+ },
290
+ model: {
291
+ defaults: {
292
+ name: "Loop Grid",
293
+ tagName: "section",
294
+ draggable: "*",
295
+ droppable: false,
296
+ selectable: true,
297
+ editable: false,
298
+ stylable: true,
299
+ attributes: {
300
+ "data-wb-component": "loop-grid",
301
+ "data-cms-component": "post-list",
302
+ class: "wb-loop-grid"
303
+ },
304
+ styles: LOOP_GRID_CSS,
305
+ style: {
306
+ width: "100%",
307
+ display: "block"
308
+ }
309
+ },
310
+ init() {
311
+ var _a;
312
+ const schema = buildLoopGridSchema(this);
313
+ this.addAttributes({
314
+ ...buildCmsRenderAttrs(schema),
315
+ "data-wb-component": "loop-grid",
316
+ "data-wb-instance-id": String(((_a = this.getId) == null ? void 0 : _a.call(this)) || this.cid || ""),
317
+ "data-wb-loop-grid-version": String(schema.version),
318
+ "data-wb-grid-id": schema.gridId,
319
+ "data-wb-filter-key": schema.filterKey,
320
+ "data-wb-source-type": schema.query.sourceType,
321
+ "data-wb-query-mode": schema.query.queryMode,
322
+ "data-wb-item-template-id": schema.itemTemplateId,
323
+ "data-wb-provider-key": schema.providerKey,
324
+ "data-wb-loop-grid-schema": encodeLoopGridSchema(schema)
325
+ });
326
+ },
327
+ getInnerHTML() {
328
+ return renderLoopGridPublishHtml(buildLoopGridSchema(this));
329
+ }
330
+ }
331
+ });
332
+ }
333
+ const navbarThbScript = function() {
334
+ const root = this;
335
+ if (root.__thbNavInit)
336
+ return;
337
+ root.__thbNavInit = true;
338
+ const hamburger = root.querySelector(".site-header__hamburger");
339
+ const navMobile = root.querySelector(".nav-mobile");
340
+ const navMobileContent = navMobile ? navMobile.querySelector(".nav-mobile__content") : null;
341
+ const mobileSearchBtn = root.querySelector(".site-header__mobile-search");
342
+ const logo = root.querySelector(".site-header__logo-img, .site-header__logo img");
343
+ const siteSearch = root.querySelector(".site-search");
344
+ const headerSearchInput = root.querySelector(".site-header__search input");
345
+ const siteSearchInput = siteSearch ? siteSearch.querySelector(".site-search__input") : null;
346
+ const siteSearchClose = siteSearch ? siteSearch.querySelector(".site-search__close") : null;
347
+ const siteSearchClear = siteSearch ? siteSearch.querySelector(".site-search__clear") : null;
348
+ const siteSearchForm = siteSearch ? siteSearch.querySelector(".site-search__form") : null;
349
+ (function prepareMobilePanels() {
350
+ if (!navMobileContent)
351
+ return;
352
+ const panels = Array.from(navMobileContent.querySelectorAll(".nav-mobile__panel"));
353
+ let index = 0;
354
+ panels.forEach(function(panel) {
355
+ if (!panel.dataset.panel) {
356
+ panel.dataset.panel = panel.classList.contains("is-active") ? "root" : "panel-" + ++index;
357
+ }
358
+ });
359
+ Array.from(navMobileContent.querySelectorAll(".nav-mobile__expand")).forEach(function(button) {
360
+ var _a;
361
+ const trigger = button;
362
+ if (trigger.dataset.target)
363
+ return;
364
+ const siblingPanel = (_a = trigger.parentElement) == null ? void 0 : _a.querySelector(":scope > .nav-mobile__panel");
365
+ if (siblingPanel == null ? void 0 : siblingPanel.dataset.panel)
366
+ trigger.dataset.target = siblingPanel.dataset.panel;
367
+ });
368
+ })();
369
+ (function flattenMobilePanels() {
370
+ if (!navMobileContent)
371
+ return;
372
+ const panels = Array.from(navMobileContent.querySelectorAll(".nav-mobile__panel"));
373
+ panels.forEach(function(panel) {
374
+ const ancestor = panel.parentElement && panel.parentElement.closest(".nav-mobile__panel");
375
+ if (ancestor && ancestor.dataset.panel) {
376
+ panel.dataset.parent = ancestor.dataset.panel || "";
377
+ }
378
+ });
379
+ panels.forEach(function(panel) {
380
+ if (panel.parentElement !== navMobileContent) {
381
+ navMobileContent.appendChild(panel);
382
+ }
383
+ });
384
+ })();
385
+ const mobilePanels = navMobile ? Array.from(navMobile.querySelectorAll("[data-panel]")) : [];
386
+ const panelStack = ["root"];
387
+ let isPanelTransitioning = false;
388
+ let isMenuClosing = false;
389
+ function syncLogo(scrolled) {
390
+ if (!logo)
391
+ return;
392
+ const defaultLogo = logo.getAttribute("data-default-logo") || "";
393
+ const scrolledLogo = logo.getAttribute("data-scrolled-logo") || "";
394
+ const nextLogo = scrolled && scrolledLogo ? scrolledLogo : defaultLogo || scrolledLogo;
395
+ if (nextLogo && logo.getAttribute("src") !== nextLogo) {
396
+ logo.setAttribute("src", nextLogo);
397
+ }
398
+ }
399
+ function onScroll() {
400
+ const scrolled = window.scrollY > 10;
401
+ root.classList.toggle("site-header--scrolled", scrolled);
402
+ syncLogo(scrolled);
403
+ }
404
+ function getPanel(panelName) {
405
+ return mobilePanels.find(function(panel) {
406
+ return panel.dataset.panel === panelName;
407
+ });
408
+ }
409
+ function waitForTransition(element, fallback) {
410
+ return new Promise(function(resolve) {
411
+ let settled = false;
412
+ const done = function() {
413
+ if (settled)
414
+ return;
415
+ settled = true;
416
+ element.removeEventListener("transitionend", onEnd);
417
+ resolve();
418
+ };
419
+ const onEnd = function(event) {
420
+ if (event.target === element)
421
+ done();
422
+ };
423
+ element.addEventListener("transitionend", onEnd);
424
+ window.setTimeout(done, fallback || 360);
425
+ });
426
+ }
427
+ function resetPanelStates() {
428
+ mobilePanels.forEach(function(panel) {
429
+ panel.classList.remove("is-active", "is-entering-from-right", "is-entering-from-left", "is-exiting-to-left", "is-exiting-to-right");
430
+ });
431
+ const rootPanel = getPanel("root");
432
+ if (rootPanel)
433
+ rootPanel.classList.add("is-active");
434
+ }
435
+ async function transitionMobilePanel(fromPanelName, toPanelName, direction) {
436
+ if (isPanelTransitioning)
437
+ return;
438
+ const currentPanel = getPanel(fromPanelName);
439
+ const nextPanel = getPanel(toPanelName);
440
+ if (!currentPanel || !nextPanel || currentPanel === nextPanel)
441
+ return;
442
+ isPanelTransitioning = true;
443
+ nextPanel.classList.remove("is-active", "is-exiting-to-left", "is-exiting-to-right");
444
+ nextPanel.classList.add(direction === "back" ? "is-entering-from-left" : "is-entering-from-right");
445
+ requestAnimationFrame(function() {
446
+ currentPanel.classList.add(direction === "back" ? "is-exiting-to-right" : "is-exiting-to-left");
447
+ currentPanel.classList.remove("is-active");
448
+ nextPanel.classList.add("is-active");
449
+ nextPanel.classList.remove("is-entering-from-left", "is-entering-from-right");
450
+ });
451
+ await Promise.all([waitForTransition(currentPanel), waitForTransition(nextPanel)]);
452
+ currentPanel.classList.remove("is-exiting-to-left", "is-exiting-to-right");
453
+ nextPanel.classList.remove("is-entering-from-left", "is-entering-from-right");
454
+ isPanelTransitioning = false;
455
+ }
456
+ function openMobileMenu() {
457
+ if (!navMobile || !hamburger)
458
+ return;
459
+ panelStack.length = 1;
460
+ panelStack[0] = "root";
461
+ resetPanelStates();
462
+ navMobile.classList.add("nav-mobile--open");
463
+ navMobile.setAttribute("aria-hidden", "false");
464
+ hamburger.classList.add("site-header__hamburger--open");
465
+ hamburger.setAttribute("aria-expanded", "true");
466
+ document.body.classList.add("nav-mobile-open");
467
+ }
468
+ async function closeMobileMenu() {
469
+ if (!navMobile || !hamburger)
470
+ return;
471
+ if (isMenuClosing)
472
+ return;
473
+ isMenuClosing = true;
474
+ navMobile.classList.remove("nav-mobile--open");
475
+ navMobile.setAttribute("aria-hidden", "true");
476
+ hamburger.classList.remove("site-header__hamburger--open");
477
+ hamburger.setAttribute("aria-expanded", "false");
478
+ document.body.classList.remove("nav-mobile-open");
479
+ await waitForTransition(navMobile, 340);
480
+ panelStack.length = 1;
481
+ panelStack[0] = "root";
482
+ resetPanelStates();
483
+ isMenuClosing = false;
484
+ }
485
+ async function pushPanel(panelName) {
486
+ if (!getPanel(panelName))
487
+ return;
488
+ const current = panelStack[panelStack.length - 1];
489
+ panelStack.push(panelName);
490
+ await transitionMobilePanel(current, panelName, "forward");
491
+ }
492
+ async function popPanel() {
493
+ if (panelStack.length <= 1)
494
+ return;
495
+ const current = panelStack.pop();
496
+ const previous = panelStack[panelStack.length - 1];
497
+ if (!current || !previous)
498
+ return;
499
+ await transitionMobilePanel(current, previous, "back");
500
+ }
501
+ function openSiteSearch() {
502
+ if (!siteSearch)
503
+ return;
504
+ if (navMobile && navMobile.classList.contains("nav-mobile--open"))
505
+ closeMobileMenu();
506
+ siteSearch.classList.add("site-search--open");
507
+ siteSearch.setAttribute("aria-hidden", "false");
508
+ if (mobileSearchBtn)
509
+ mobileSearchBtn.setAttribute("aria-expanded", "true");
510
+ document.body.classList.add("site-search-open");
511
+ window.setTimeout(function() {
512
+ if (siteSearchInput)
513
+ siteSearchInput.focus();
514
+ }, 120);
515
+ }
516
+ function closeSiteSearch() {
517
+ if (!siteSearch)
518
+ return;
519
+ siteSearch.classList.remove("site-search--open");
520
+ siteSearch.setAttribute("aria-hidden", "true");
521
+ if (mobileSearchBtn)
522
+ mobileSearchBtn.setAttribute("aria-expanded", "false");
523
+ document.body.classList.remove("site-search-open");
524
+ if (siteSearchInput)
525
+ siteSearchInput.blur();
526
+ }
527
+ function updateSiteSearchClear() {
528
+ if (!siteSearchClear || !siteSearchInput)
529
+ return;
530
+ siteSearchClear.hidden = siteSearchInput.value.length === 0;
531
+ }
532
+ function submitSearch(input) {
533
+ var _a;
534
+ const keyword = ((_a = input == null ? void 0 : input.value) == null ? void 0 : _a.trim()) || "";
535
+ if (!keyword)
536
+ return;
537
+ const searchUrl = new URL("/search", window.location.origin);
538
+ searchUrl.searchParams.set("q", keyword);
539
+ window.location.assign(searchUrl.toString());
540
+ }
541
+ onScroll();
542
+ window.addEventListener("scroll", onScroll, { passive: true });
543
+ if (hamburger) {
544
+ hamburger.addEventListener("click", async function() {
545
+ if (navMobile && navMobile.classList.contains("nav-mobile--open")) {
546
+ await closeMobileMenu();
547
+ } else {
548
+ openMobileMenu();
549
+ }
550
+ });
551
+ }
552
+ if (navMobile) {
553
+ navMobile.addEventListener("click", async function(event) {
554
+ const target = event.target;
555
+ const backButton = target.closest("[data-back]");
556
+ if (backButton) {
557
+ await popPanel();
558
+ return;
559
+ }
560
+ const panelButton = target.closest("[data-target]");
561
+ if (panelButton) {
562
+ await pushPanel(panelButton.dataset.target || "");
563
+ return;
564
+ }
565
+ const link = target.closest("a");
566
+ if (link)
567
+ await closeMobileMenu();
568
+ });
569
+ }
570
+ window.addEventListener("keydown", async function(event) {
571
+ if (event.key !== "Escape")
572
+ return;
573
+ if (siteSearch && siteSearch.classList.contains("site-search--open")) {
574
+ closeSiteSearch();
575
+ return;
576
+ }
577
+ if (navMobile && navMobile.classList.contains("nav-mobile--open"))
578
+ await closeMobileMenu();
579
+ });
580
+ window.addEventListener("resize", async function() {
581
+ if (window.innerWidth > 767) {
582
+ if (navMobile && navMobile.classList.contains("nav-mobile--open"))
583
+ await closeMobileMenu();
584
+ if (siteSearch && siteSearch.classList.contains("site-search--open"))
585
+ closeSiteSearch();
586
+ }
587
+ });
588
+ if (headerSearchInput) {
589
+ headerSearchInput.addEventListener("keydown", function(event) {
590
+ if (event.key !== "Enter")
591
+ return;
592
+ event.preventDefault();
593
+ submitSearch(headerSearchInput);
594
+ });
595
+ }
596
+ if (mobileSearchBtn)
597
+ mobileSearchBtn.addEventListener("click", openSiteSearch);
598
+ if (siteSearchClose)
599
+ siteSearchClose.addEventListener("click", closeSiteSearch);
600
+ if (siteSearchInput)
601
+ siteSearchInput.addEventListener("input", updateSiteSearchClear);
602
+ if (siteSearchClear) {
603
+ siteSearchClear.addEventListener("click", function() {
604
+ if (!siteSearchInput)
605
+ return;
606
+ siteSearchInput.value = "";
607
+ updateSiteSearchClear();
608
+ siteSearchInput.focus();
609
+ });
610
+ }
611
+ if (siteSearchForm) {
612
+ siteSearchForm.addEventListener("submit", function(event) {
613
+ event.preventDefault();
614
+ submitSearch(siteSearchInput);
615
+ });
616
+ }
617
+ };
618
+ const NAVBAR_THB_STYLES = `
619
+ /* ── CSS Variables ─────────────────────────────────────── */
620
+ .site-header {
621
+ --primary-blue: #3C53E8;
622
+ --dark-blue: #080E2B;
623
+ --text-dark: #0C1029;
624
+ --text-gray: #666;
625
+ --transition: 0.2s ease-in-out;
626
+ --header-height: 64px;
627
+ --thb-mobile-header-height: 60px;
628
+ --thb-header-bg: transparent;
629
+ --thb-header-scroll-bg: #fff;
630
+ --thb-header-link-color: var(--text-dark);
631
+ --thb-header-scroll-link-color: var(--text-dark);
632
+ --thb-logo-height: 36px;
633
+ --thb-mobile-logo-height: 32px;
634
+ --thb-gutter: 40px;
635
+ --thb-mobile-gutter: 20px;
636
+ --thb-nav-gap: 40px;
637
+ --dropdown-menu-offset: 8px;
638
+ --megamenu-offset: 8px;
639
+ --dropdown-menu-radius: 8px;
640
+ --megamenu-radius: 8px;
641
+ }
642
+
643
+ /* ── Page Width Grid ────────────────────────────────────── */
644
+ .site-header .page-width {
645
+ --content-max: 1240px;
646
+ --gutter: var(--thb-gutter);
647
+ display: grid;
648
+ grid-template-columns:
649
+ minmax(var(--gutter), 1fr)
650
+ minmax(0, var(--content-max))
651
+ minmax(var(--gutter), 1fr);
652
+ }
653
+ .site-header .page-width > * {
654
+ grid-column: 2;
655
+ }
656
+
657
+ /* ── Links ──────────────────────────────────────────────── */
658
+ .site-header a {
659
+ text-decoration: none;
660
+ }
661
+ .site-header input {
662
+ min-width: 0;
663
+ }
664
+
665
+ /* ── Logo ───────────────────────────────────────────────── */
666
+ .site-header__logo {
667
+ display: flex;
668
+ align-items: center;
669
+ gap: 2px;
670
+ }
671
+ .site-header__logo a {
672
+ display: flex;
673
+ align-items: center;
674
+ }
675
+ .site-header__logo img {
676
+ height: var(--thb-logo-height);
677
+ width: auto;
678
+ display: block;
679
+ }
680
+
681
+ /* ── Header Base ────────────────────────────────────────── */
682
+ .site-header {
683
+ background: var(--thb-header-scroll-bg);
684
+ position: sticky;
685
+ top: 0;
686
+ left: 0;
687
+ right: 0;
688
+ z-index: 1000;
689
+ transition: background var(--transition), box-shadow var(--transition);
690
+ }
691
+ .site-header--fixed-transparent {
692
+ background: var(--thb-header-bg);
693
+ position: fixed;
694
+ }
695
+ .site-header--sticky {
696
+ background: var(--thb-header-scroll-bg);
697
+ position: sticky;
698
+ }
699
+ .site-header--scrolled {
700
+ background: var(--thb-header-scroll-bg);
701
+ box-shadow: 0 0 0 1px rgba(2, 5, 27, 0.09);
702
+ }
703
+
704
+ /* ── Primary Nav ────────────────────────────────────────── */
705
+ .site-header__nav {
706
+ display: flex;
707
+ height: var(--header-height);
708
+ align-items: center;
709
+ justify-content: space-between;
710
+ gap: 24px;
711
+ }
712
+ .site-header__nav-list {
713
+ display: flex;
714
+ gap: var(--thb-nav-gap);
715
+ list-style: none;
716
+ margin: 0;
717
+ padding: 0;
718
+ }
719
+ .site-header__nav-list.wb-menu-tree {
720
+ width: auto;
721
+ }
722
+ .site-header__nav-list.wb-menu-tree .wb-menu-tree-nav {
723
+ width: auto;
724
+ }
725
+ .site-header__nav-list.wb-menu-tree .wb-menu-tree-list {
726
+ display: flex;
727
+ flex-direction: row;
728
+ gap: var(--thb-nav-gap);
729
+ list-style: none;
730
+ margin: 0;
731
+ padding: 0;
732
+ }
733
+ .site-header__nav-list.wb-menu-tree .wb-menu-tree-item {
734
+ position: relative;
735
+ }
736
+ .site-header__nav-list.wb-menu-tree .wb-menu-tree-list > .wb-menu-tree-item > .wb-menu-tree-submenu {
737
+ position: absolute;
738
+ left: 50%;
739
+ top: 100%;
740
+ transform: translate(-50%, 8px);
741
+ min-width: 200px;
742
+ background: #fff;
743
+ border-radius: var(--megamenu-radius);
744
+ padding: 10px;
745
+ box-shadow: 0 8px 30px rgba(12, 16, 41, 0.08);
746
+ display: grid;
747
+ gap: 4px;
748
+ opacity: 0;
749
+ visibility: hidden;
750
+ pointer-events: none;
751
+ transition: opacity var(--transition), visibility var(--transition), transform var(--transition);
752
+ z-index: 1200;
753
+ }
754
+ .site-header__nav-list.wb-menu-tree .wb-menu-tree-list > .wb-menu-tree-item:hover > .wb-menu-tree-submenu,
755
+ .site-header__nav-list.wb-menu-tree .wb-menu-tree-list > .wb-menu-tree-item:focus-within > .wb-menu-tree-submenu {
756
+ opacity: 1;
757
+ visibility: visible;
758
+ pointer-events: auto;
759
+ transform: translate(-50%, 0);
760
+ }
761
+ .site-header__nav-list.wb-menu-tree .wb-menu-tree-list > .wb-menu-tree-item > .wb-menu-tree-submenu:has(.wb-menu-tree-submenu) {
762
+ width: 790px;
763
+ min-width: 0;
764
+ padding: 20px;
765
+ grid-template-columns: repeat(3, minmax(0, 1fr));
766
+ gap: 28px;
767
+ }
768
+ .site-header__nav-list.wb-menu-tree .wb-menu-tree-list > .wb-menu-tree-item > .wb-menu-tree-submenu:has(.wb-menu-tree-submenu) > .wb-menu-tree-item:first-child {
769
+ grid-column: span 2;
770
+ }
771
+ .site-header__nav-list.wb-menu-tree .wb-menu-tree-list > .wb-menu-tree-item > .wb-menu-tree-submenu:has(.wb-menu-tree-submenu) > .wb-menu-tree-item:first-child > .wb-menu-tree-submenu {
772
+ grid-template-columns: repeat(2, minmax(0, 1fr));
773
+ column-gap: 28px;
774
+ }
775
+ .site-header__nav-list.wb-menu-tree .wb-menu-tree-submenu .wb-menu-tree-submenu {
776
+ position: static;
777
+ display: grid;
778
+ gap: 4px;
779
+ margin-top: 12px;
780
+ padding: 0;
781
+ background: transparent;
782
+ box-shadow: none;
783
+ }
784
+ .site-header__nav-list.wb-menu-tree .wb-menu-tree-link {
785
+ font-size: 14px;
786
+ display: block;
787
+ line-height: var(--header-height);
788
+ color: var(--thb-header-link-color);
789
+ font-weight: 400;
790
+ transition: color var(--transition);
791
+ white-space: nowrap;
792
+ text-decoration: none;
793
+ }
794
+ .site-header__nav-list.wb-menu-tree .wb-menu-tree-submenu .wb-menu-tree-link {
795
+ line-height: 1.2;
796
+ padding: 10px;
797
+ border-radius: 6px;
798
+ color: #1d1d1d;
799
+ }
800
+ .site-header__nav-list.wb-menu-tree .wb-menu-tree-submenu .wb-menu-tree-link:hover {
801
+ background: #F3F3F3;
802
+ color: #1d1d1d;
803
+ opacity: 1;
804
+ }
805
+ .site-header--scrolled .site-header__nav-list.wb-menu-tree .wb-menu-tree-link {
806
+ color: var(--thb-header-scroll-link-color);
807
+ }
808
+ .site-header__nav-list.wb-menu-tree .wb-menu-tree-link:hover {
809
+ color: var(--thb-header-link-color);
810
+ opacity: 0.82;
811
+ }
812
+ .site-header--scrolled .site-header__nav-list.wb-menu-tree .wb-menu-tree-link:hover {
813
+ color: var(--thb-header-scroll-link-color);
814
+ }
815
+ .site-header__nav-list.wb-menu-tree .wb-menu-tree-icon {
816
+ display: none;
817
+ }
818
+ .site-header__nav-list.wb-menu-tree .wb-menu-tree-list > .wb-menu-tree-item > .wb-menu-tree-submenu:has(.wb-menu-tree-submenu) > .wb-menu-tree-item > .wb-menu-tree-link {
819
+ display: flex;
820
+ align-items: center;
821
+ justify-content: space-between;
822
+ flex-wrap: wrap;
823
+ gap: 16px;
824
+ padding-inline: 16px 4px;
825
+ margin-bottom: 20px;
826
+ font-size: 16px;
827
+ font-weight: 700;
828
+ line-height: 24px;
829
+ background: transparent;
830
+ }
831
+ .site-header__nav-list.wb-menu-tree .wb-menu-tree-list > .wb-menu-tree-item > .wb-menu-tree-submenu:has(.wb-menu-tree-submenu) > .wb-menu-tree-item > .wb-menu-tree-link::after {
832
+ content: '›';
833
+ margin-left: auto;
834
+ color: #666;
835
+ font-size: 28px;
836
+ line-height: 1;
837
+ font-weight: 300;
838
+ }
839
+ .site-header__nav-list.wb-menu-tree .wb-menu-tree-list > .wb-menu-tree-item > .wb-menu-tree-submenu:has(.wb-menu-tree-submenu) > .wb-menu-tree-item > .wb-menu-tree-link .wb-menu-tree-text {
840
+
841
+ }
842
+ .site-header__nav-list.wb-menu-tree .wb-menu-tree-list > .wb-menu-tree-item > .wb-menu-tree-submenu:has(.wb-menu-tree-submenu) > .wb-menu-tree-item > .wb-menu-tree-link .wb-menu-tree-icon {
843
+ order: 3;
844
+ display: block;
845
+ width: 100%;
846
+ height: auto;
847
+ max-height: 448px;
848
+ aspect-ratio: 1 / 1;
849
+ object-fit: contain;
850
+ padding: 28px;
851
+ margin-top: 18px;
852
+ background: #F3F3F3;
853
+ border-radius: 10px;
854
+ }
855
+ .site-header__nav-list.wb-menu-tree .wb-menu-tree-list > .wb-menu-tree-item > .wb-menu-tree-submenu:has(.wb-menu-tree-submenu) > .wb-menu-tree-item > .wb-menu-tree-link .wb-menu-tree-icon[src=''],
856
+ .site-header__nav-list.wb-menu-tree .wb-menu-tree-list > .wb-menu-tree-item > .wb-menu-tree-submenu:has(.wb-menu-tree-submenu) > .wb-menu-tree-item > .wb-menu-tree-link .wb-menu-tree-icon:not([src]) {
857
+ display: none;
858
+ }
859
+ .site-header__nav-item--has-dropdown {
860
+ position: relative;
861
+ }
862
+ .site-header__nav-link {
863
+ font-size: 14px;
864
+ display: block;
865
+ line-height: var(--header-height);
866
+ color: var(--thb-header-link-color);
867
+ font-weight: 400;
868
+ transition: color var(--transition);
869
+ white-space: nowrap;
870
+ }
871
+ .site-header--scrolled .site-header__nav-link {
872
+ color: var(--thb-header-scroll-link-color);
873
+ }
874
+ .site-header__nav-link:hover {
875
+ color: var(--thb-header-link-color);
876
+ opacity: 0.82;
877
+ }
878
+ .site-header--scrolled .site-header__nav-link:hover {
879
+ color: var(--thb-header-scroll-link-color);
880
+ }
881
+ .site-header--menu-left .site-header__nav-list {
882
+ margin-right: auto;
883
+ }
884
+ .site-header--menu-right .site-header__nav-list {
885
+ margin-left: auto;
886
+ }
887
+ .site-header__nav-link--active {
888
+ color: var(--thb-header-link-color);
889
+ font-weight: 600;
890
+ }
891
+ .site-header--scrolled .site-header__nav-link--active {
892
+ color: var(--thb-header-scroll-link-color);
893
+ }
894
+
895
+ /* ── Dropdown Wrap ──────────────────────────────────────── */
896
+ .site-header__dropdown-wrap {
897
+ position: absolute;
898
+ left: 50%;
899
+ top: 100%;
900
+ transform: translate(-50%, 8px);
901
+ padding-top: var(--dropdown-menu-offset);
902
+ opacity: 0;
903
+ visibility: hidden;
904
+ pointer-events: none;
905
+ transition: opacity var(--transition), visibility var(--transition), transform var(--transition);
906
+ z-index: 1200;
907
+ }
908
+ .site-header__nav-item--has-dropdown:hover > .site-header__dropdown-wrap,
909
+ .site-header__nav-item--has-dropdown:focus-within > .site-header__dropdown-wrap {
910
+ opacity: 1;
911
+ visibility: visible;
912
+ pointer-events: auto;
913
+ transform: translate(-50%, 0);
914
+ }
915
+
916
+ /* ── Dropdown ───────────────────────────────────────────── */
917
+ .site-header__dropdown {
918
+ min-width: 200px;
919
+ background: #fff;
920
+ border-radius: var(--megamenu-radius);
921
+ padding: 10px;
922
+ box-shadow: 0 8px 30px rgba(12, 16, 41, 0.08);
923
+ display: grid;
924
+ gap: 4px;
925
+ }
926
+ .site-header__dropdown--right {
927
+ min-width: 180px;
928
+ }
929
+ .site-header__dropdown-link {
930
+ display: block;
931
+ white-space: nowrap;
932
+ padding: 10px;
933
+ border-radius: 6px;
934
+ font-size: 14px;
935
+ font-weight: 400;
936
+ color: #1d1d1d;
937
+ line-height: 1.2;
938
+ transition: background var(--transition), color var(--transition);
939
+ }
940
+ .site-header__dropdown-link--active,
941
+ .site-header__dropdown-link:hover {
942
+ background: #F3F3F3;
943
+ }
944
+
945
+ /* ── Mega Menu ──────────────────────────────────────────── */
946
+ .site-header__dropdown--mega {
947
+ width: 790px;
948
+ min-width: 0;
949
+ padding: 0;
950
+ }
951
+ .site-header__mega {
952
+ display: grid;
953
+ align-items: stretch;
954
+ gap: 28px;
955
+ padding: 20px;
956
+ grid-template-columns: minmax(0, 1.15fr) 240px;
957
+ }
958
+ .site-header__mega-col {
959
+ flex: 1 1 0;
960
+ min-width: 0;
961
+ }
962
+ .site-header__mega-col--right {
963
+ padding-left: 0;
964
+ }
965
+ .site-header__mega-head {
966
+ display: flex;
967
+ align-items: center;
968
+ justify-content: space-between;
969
+ font-size: 16px;
970
+ font-weight: 700;
971
+ color: #1d1d1d;
972
+ line-height: 24px;
973
+ margin-bottom: 32px;
974
+ padding-inline: 16px 4px;
975
+ }
976
+ .site-header__mega-head--empty {
977
+ height: 24px;
978
+ margin-bottom: 32px;
979
+ }
980
+ .site-header__mega-head i {
981
+ font-size: 30px;
982
+ color: #1d1d1d;
983
+ opacity: 0.75;
984
+ font-weight: normal;
985
+ font-style: normal;
986
+ }
987
+ .site-header__mega-list {
988
+ display: grid;
989
+ row-gap: 10px;
990
+ }
991
+ .site-header__mega-list--split {
992
+ grid-template-columns: repeat(2, minmax(0, 1fr));
993
+ column-gap: 16px;
994
+ }
995
+ .site-header__mega-item {
996
+ display: block;
997
+ padding: 10px;
998
+ border-radius: 4px;
999
+ font-size: 14px;
1000
+ font-weight: normal;
1001
+ color: #222222;
1002
+ line-height: 1.32;
1003
+ transition: background var(--transition), color var(--transition);
1004
+ }
1005
+ .site-header__mega-item--active,
1006
+ .site-header__mega-item:hover {
1007
+ background: #F3F3F3;
1008
+ color: #1d1d1d;
1009
+ }
1010
+ .site-header__mega-media {
1011
+ border-radius: 6px;
1012
+ background: #F3F4F6;
1013
+ overflow: hidden;
1014
+ display: flex;
1015
+ align-items: center;
1016
+ justify-content: center;
1017
+ aspect-ratio: 1 / 1;
1018
+ min-height: 0;
1019
+ padding: 0;
1020
+ margin-inline: 16px 0;
1021
+ }
1022
+ .site-header__mega-media img {
1023
+ width: 100%;
1024
+ height: 100%;
1025
+ display: block;
1026
+ object-fit: contain;
1027
+ }
1028
+
1029
+ /* ── Actions ────────────────────────────────────────────── */
1030
+ .site-header__actions {
1031
+ display: flex;
1032
+ align-items: center;
1033
+ gap: 10px;
1034
+ flex-shrink: 0;
1035
+ }
1036
+ .site-header__search {
1037
+ background: #fff;
1038
+ border-radius: 20px;
1039
+ padding: 0 14px;
1040
+ display: flex;
1041
+ align-items: center;
1042
+ width: 160px;
1043
+ height: 36px;
1044
+ box-shadow: 0 0 0 1px #CDCDCD inset;
1045
+ gap: 8px;
1046
+ color: #999;
1047
+ transition: all var(--transition);
1048
+ }
1049
+ .site-header__search:has(:focus-within) {
1050
+ box-shadow: 0 0 0 1px var(--primary-blue) inset;
1051
+ }
1052
+ .site-header__search svg {
1053
+ flex: 0 0 auto;
1054
+ }
1055
+ .site-header__search input {
1056
+ flex: 1;
1057
+ border: none;
1058
+ background: transparent;
1059
+ outline: none;
1060
+ font-size: 13px;
1061
+ font-family: inherit;
1062
+ color: var(--text-dark);
1063
+ }
1064
+
1065
+ /* ── CTA Button ─────────────────────────────────────────── */
1066
+ .site-header .btn--consult {
1067
+ background: var(--primary-blue);
1068
+ color: #fff;
1069
+ border-radius: 999px;
1070
+ font-size: 14px;
1071
+ height: 36px;
1072
+ padding: 0 20px;
1073
+ display: inline-flex;
1074
+ align-items: center;
1075
+ justify-content: center;
1076
+ white-space: nowrap;
1077
+ transition: background var(--transition), transform var(--transition);
1078
+ font-family: inherit;
1079
+ font-weight: 500;
1080
+ cursor: pointer;
1081
+ border: none;
1082
+ text-decoration: none;
1083
+ }
1084
+ .site-header .btn--consult:hover {
1085
+ background: #2a3fc9;
1086
+ }
1087
+
1088
+ /* ── Hamburger ──────────────────────────────────────────── */
1089
+ .site-header__hamburger {
1090
+ display: none;
1091
+ flex-direction: column;
1092
+ gap: 3px;
1093
+ background: none;
1094
+ border: none;
1095
+ cursor: pointer;
1096
+ padding: 4px;
1097
+ }
1098
+ .site-header__hamburger span {
1099
+ display: block;
1100
+ width: 17px;
1101
+ height: 3px;
1102
+ transform: scaleY(0.5);
1103
+ background: var(--thb-header-link-color);
1104
+ border-radius: 2px;
1105
+ transition: all var(--transition);
1106
+ transform-origin: center;
1107
+ }
1108
+ .site-header--scrolled .site-header__hamburger span {
1109
+ background: var(--thb-header-scroll-link-color);
1110
+ }
1111
+ .site-header__hamburger--open span:nth-child(1) {
1112
+ transform: translateY(6px) rotate(45deg) scaleY(0.5);
1113
+ }
1114
+ .site-header__hamburger--open span:nth-child(2) {
1115
+ opacity: 0;
1116
+ }
1117
+ .site-header__hamburger--open span:nth-child(3) {
1118
+ transform: translateY(-6px) rotate(-45deg) scaleY(0.5);
1119
+ }
1120
+
1121
+ /* ── Mobile Search Trigger ──────────────────────────────── */
1122
+ .site-header__mobile-search {
1123
+ display: none;
1124
+ }
1125
+
1126
+ /* ── Site Search Overlay (mobile only) ──────────────────── */
1127
+ .site-header .site-search {
1128
+ display: none;
1129
+ }
1130
+
1131
+ /* ── Mobile Nav (hidden by default) ────────────────────── */
1132
+ .site-header .nav-mobile {
1133
+ display: none;
1134
+ }
1135
+ .site-header .nav-mobile--open {
1136
+ display: flex;
1137
+ }
1138
+
1139
+ /* ── Tablet (≤ 1024px) ──────────────────────────────────── */
1140
+ @media (max-width: 1024px) {
1141
+ .site-header .page-width {
1142
+ --gutter: min(28px, var(--thb-gutter));
1143
+ }
1144
+ .site-header__nav-list {
1145
+ gap: 24px;
1146
+ }
1147
+ }
1148
+
1149
+ /* ── Mobile (≤ 767px) ───────────────────────────────────── */
1150
+ @media (max-width: 767px) {
1151
+ .site-header .page-width {
1152
+ --gutter: var(--thb-mobile-gutter);
1153
+ }
1154
+ .site-header {
1155
+ z-index: 1500;
1156
+ }
1157
+ .site-header__nav {
1158
+ height: var(--thb-mobile-header-height);
1159
+ gap: 12px;
1160
+ }
1161
+ .site-header__nav-list {
1162
+ display: none;
1163
+ }
1164
+ .site-header__nav-list.wb-menu-tree {
1165
+ display: none !important;
1166
+ }
1167
+ .site-header__search {
1168
+ display: none;
1169
+ }
1170
+ .site-header .btn--consult {
1171
+ display: none;
1172
+ }
1173
+ .site-header__dropdown-wrap {
1174
+ display: none;
1175
+ }
1176
+ .site-header__actions {
1177
+ order: 1;
1178
+ width: 40px;
1179
+ flex: 0 0 40px;
1180
+ display: flex;
1181
+ align-items: center;
1182
+ justify-content: flex-start;
1183
+ gap: 0;
1184
+ }
1185
+ .site-header__logo {
1186
+ order: 2;
1187
+ flex: 1 1 auto;
1188
+ display: flex;
1189
+ justify-content: center;
1190
+ }
1191
+ .site-header__logo img {
1192
+ width: auto;
1193
+ height: var(--thb-mobile-logo-height);
1194
+ }
1195
+ .site-header__hamburger {
1196
+ display: flex;
1197
+ margin: 0;
1198
+ }
1199
+ .site-header__mobile-search {
1200
+ order: 3;
1201
+ width: 40px;
1202
+ height: 40px;
1203
+ flex: 0 0 40px;
1204
+ display: inline-flex;
1205
+ align-items: center;
1206
+ justify-content: center;
1207
+ border: 0;
1208
+ padding: 0;
1209
+ background: transparent;
1210
+ color: var(--thb-header-link-color);
1211
+ cursor: pointer;
1212
+ }
1213
+ .site-header--scrolled .site-header__mobile-search {
1214
+ color: var(--thb-header-scroll-link-color);
1215
+ }
1216
+ .site-header__mobile-search svg,
1217
+ .site-header .nav-mobile__back svg {
1218
+ width: 24px;
1219
+ height: 24px;
1220
+ display: block;
1221
+ stroke: currentColor;
1222
+ }
1223
+
1224
+ /* ── Mobile Nav ───────────────────────────────────────── */
1225
+ .site-header .nav-mobile {
1226
+ position: fixed;
1227
+ top: var(--thb-mobile-header-height);
1228
+ right: 0;
1229
+ bottom: 0;
1230
+ left: 0;
1231
+ z-index: 1400;
1232
+ background: rgba(255, 255, 255, 0.98);
1233
+ opacity: 0;
1234
+ visibility: hidden;
1235
+ pointer-events: none;
1236
+ transform: translateY(-12px);
1237
+ transition: opacity 0.26s ease, transform 0.32s cubic-bezier(0.22, 1, 0.36, 1), visibility 0s linear 0.32s;
1238
+ will-change: opacity, transform;
1239
+ flex-direction: column;
1240
+ }
1241
+ .site-header .nav-mobile--open {
1242
+ display: flex;
1243
+ opacity: 1;
1244
+ visibility: visible;
1245
+ pointer-events: auto;
1246
+ transform: translateY(0);
1247
+ transition: opacity 0.26s ease, transform 0.32s cubic-bezier(0.22, 1, 0.36, 1), visibility 0s;
1248
+ }
1249
+ .site-header .nav-mobile__content {
1250
+ position: relative;
1251
+ height: 100%;
1252
+ overflow: hidden;
1253
+ isolation: isolate;
1254
+ }
1255
+ .site-header .nav-mobile__panel {
1256
+ position: absolute;
1257
+ inset: 0;
1258
+ overflow-y: auto;
1259
+ -webkit-overflow-scrolling: touch;
1260
+ display: grid;
1261
+ align-content: start;
1262
+ gap: 28px;
1263
+ padding: 44px 20px 56px;
1264
+ background: #fff;
1265
+ opacity: 0;
1266
+ visibility: hidden;
1267
+ pointer-events: none;
1268
+ transform: translateX(0);
1269
+ transition: transform 0.34s cubic-bezier(0.22, 1, 0.36, 1), opacity 0.22s ease, visibility 0s linear 0.34s;
1270
+ will-change: transform, opacity;
1271
+ }
1272
+ .site-header .nav-mobile__panel.is-active {
1273
+ opacity: 1;
1274
+ visibility: visible;
1275
+ pointer-events: auto;
1276
+ transform: translateX(0);
1277
+ transition: transform 0.34s cubic-bezier(0.22, 1, 0.36, 1), opacity 0.22s ease, visibility 0s;
1278
+ }
1279
+ .site-header .nav-mobile__panel.is-entering-from-right {
1280
+ opacity: 0;
1281
+ visibility: visible;
1282
+ pointer-events: none;
1283
+ transform: translateX(44px);
1284
+ }
1285
+ .site-header .nav-mobile__panel.is-entering-from-left {
1286
+ opacity: 0;
1287
+ visibility: visible;
1288
+ pointer-events: none;
1289
+ transform: translateX(-44px);
1290
+ }
1291
+ .site-header .nav-mobile__panel.is-exiting-to-left {
1292
+ opacity: 0;
1293
+ visibility: visible;
1294
+ pointer-events: none;
1295
+ transform: translateX(-36px);
1296
+ }
1297
+ .site-header .nav-mobile__panel.is-exiting-to-right {
1298
+ opacity: 0;
1299
+ visibility: visible;
1300
+ pointer-events: none;
1301
+ transform: translateX(36px);
1302
+ }
1303
+ .site-header .nav-mobile__heading {
1304
+ margin: 0;
1305
+ color: #0f172a;
1306
+ font-size: 26px;
1307
+ line-height: 1.15;
1308
+ font-weight: 700;
1309
+ }
1310
+ .site-header .nav-mobile__heading-row {
1311
+ display: flex;
1312
+ align-items: center;
1313
+ gap: 8px;
1314
+ }
1315
+ .site-header .nav-mobile__back {
1316
+ width: 40px;
1317
+ height: 40px;
1318
+ display: inline-flex;
1319
+ align-items: center;
1320
+ justify-content: center;
1321
+ border: 0;
1322
+ padding: 0;
1323
+ background: transparent;
1324
+ color: #111827;
1325
+ cursor: pointer;
1326
+ }
1327
+ .site-header .nav-mobile__list {
1328
+ display: grid;
1329
+ gap: 8px;
1330
+ list-style: none;
1331
+ margin: 0;
1332
+ padding: 0;
1333
+ }
1334
+ .site-header .nav-mobile__list > li {
1335
+ display: flex;
1336
+ align-items: stretch;
1337
+ gap: 8px;
1338
+ }
1339
+ .site-header .nav-mobile__link,
1340
+ .site-header .nav-mobile__viewall,
1341
+ .site-header .nav-mobile__feature-link {
1342
+ color: #111827;
1343
+ text-decoration: none;
1344
+ }
1345
+ .site-header .nav-mobile__link {
1346
+ flex: 1;
1347
+ min-height: 52px;
1348
+ display: flex;
1349
+ align-items: center;
1350
+ gap: 16px;
1351
+ padding: 0;
1352
+ font-size: 18px;
1353
+ line-height: 1.35;
1354
+ font-weight: 400;
1355
+ }
1356
+ .site-header .nav-mobile__expand {
1357
+ flex: 0 0 44px;
1358
+ min-height: 52px;
1359
+ display: inline-flex;
1360
+ align-items: center;
1361
+ justify-content: center;
1362
+ border: 0;
1363
+ padding: 0;
1364
+ background: transparent;
1365
+ color: #111827;
1366
+ cursor: pointer;
1367
+ }
1368
+ .site-header .nav-mobile__entry-icon {
1369
+ flex: 0 0 auto;
1370
+ font-size: 20px;
1371
+ line-height: 1;
1372
+ transition: transform 0.22s ease;
1373
+ }
1374
+ .site-header .nav-mobile img,
1375
+ .site-header .nav-mobile [data-cms-bind-src] {
1376
+ display: none !important;
1377
+ }
1378
+ .site-header .nav-mobile__expand:hover .nav-mobile__entry-icon,
1379
+ .site-header .nav-mobile__expand:focus-visible .nav-mobile__entry-icon {
1380
+ transform: rotate(90deg);
1381
+ }
1382
+ .site-header .nav-mobile__viewall,
1383
+ .site-header .nav-mobile__feature-link {
1384
+ display: inline-flex;
1385
+ align-items: center;
1386
+ gap: 8px;
1387
+ font-size: 16px;
1388
+ font-weight: 500;
1389
+ }
1390
+ .site-header .nav-mobile__feature {
1391
+ display: grid;
1392
+ gap: 14px;
1393
+ }
1394
+ .site-header .nav-mobile__feature-card {
1395
+ display: block;
1396
+ overflow: hidden;
1397
+ border-radius: 14px;
1398
+ background: #f3f4f6;
1399
+ }
1400
+ .site-header .nav-mobile__feature-card img {
1401
+ width: 100%;
1402
+ height: auto;
1403
+ display: block;
1404
+ }
1405
+
1406
+ /* ── Site Search Overlay ────────────────────────────── */
1407
+ .site-header .site-search {
1408
+ position: fixed;
1409
+ inset: 0;
1410
+ z-index: 1600;
1411
+ display: flex;
1412
+ flex-direction: column;
1413
+ background: #fff;
1414
+ opacity: 0;
1415
+ visibility: hidden;
1416
+ pointer-events: none;
1417
+ transform: translateY(-8px);
1418
+ transition: opacity 0.22s ease, transform 0.22s ease, visibility 0s linear 0.22s;
1419
+ }
1420
+ .site-header .site-search--open {
1421
+ opacity: 1;
1422
+ visibility: visible;
1423
+ pointer-events: auto;
1424
+ transform: translateY(0);
1425
+ transition: opacity 0.22s ease, transform 0.22s ease, visibility 0s;
1426
+ }
1427
+ .site-header .site-search__bar {
1428
+ display: flex;
1429
+ align-items: center;
1430
+ gap: 8px;
1431
+ height: var(--thb-mobile-header-height);
1432
+ padding: 0 12px 0 16px;
1433
+ border-bottom: 1px solid #e8e8e8;
1434
+ background: #fff;
1435
+ }
1436
+ .site-header .site-search__form {
1437
+ flex: 1;
1438
+ display: flex;
1439
+ align-items: center;
1440
+ gap: 10px;
1441
+ height: 40px;
1442
+ padding: 0 12px;
1443
+ border-radius: 999px;
1444
+ background: #f2f3f5;
1445
+ }
1446
+ .site-header .site-search__icon {
1447
+ color: #999;
1448
+ font-size: 15px;
1449
+ flex: 0 0 auto;
1450
+ }
1451
+ .site-header .site-search__input {
1452
+ flex: 1;
1453
+ min-width: 0;
1454
+ border: 0;
1455
+ outline: 0;
1456
+ background: transparent;
1457
+ font-size: 15px;
1458
+ font-family: inherit;
1459
+ color: var(--text-dark);
1460
+ padding: 0;
1461
+ height: 100%;
1462
+ }
1463
+ .site-header .site-search__input::placeholder {
1464
+ color: #999;
1465
+ }
1466
+ .site-header .site-search__clear {
1467
+ flex: 0 0 auto;
1468
+ width: 24px;
1469
+ height: 24px;
1470
+ display: inline-flex;
1471
+ align-items: center;
1472
+ justify-content: center;
1473
+ border: 0;
1474
+ padding: 0;
1475
+ background: transparent;
1476
+ color: #666;
1477
+ cursor: pointer;
1478
+ }
1479
+ .site-header .site-search__clear svg {
1480
+ width: 20px;
1481
+ height: 20px;
1482
+ }
1483
+ .site-header .site-search__close {
1484
+ flex: 0 0 auto;
1485
+ height: 40px;
1486
+ padding: 0 6px;
1487
+ border: 0;
1488
+ background: transparent;
1489
+ color: var(--primary-blue);
1490
+ font: inherit;
1491
+ font-size: 15px;
1492
+ cursor: pointer;
1493
+ }
1494
+ .site-header .site-search__body {
1495
+ flex: 1 1 auto;
1496
+ overflow-y: auto;
1497
+ -webkit-overflow-scrolling: touch;
1498
+ padding: 16px 20px 40px;
1499
+ }
1500
+ }
1501
+ `;
1502
+ const WB_NAVBAR_THB_TYPE = "navbar-thb";
1503
+ const SEARCH_SVG = `<svg viewBox="0 0 1024 1024" width="18" fill="currentColor"><path d="M497.810286 146.249143C303.652571 146.249143 146.285714 300.141714 146.285714 489.947429c0 189.842286 157.366857 343.771429 351.524572 343.771428 83.017143 0 159.305143-28.16 219.428571-75.227428l114.285714 111.433142 3.035429 2.56c10.605714 7.68 25.6 6.802286 35.218286-2.56a26.075429 26.075429 0 0 0-0.036572-37.485714l-112.932571-110.116571a338.358857 338.358857 0 0 0 92.525714-232.374857C849.298286 300.141714 691.931429 146.285714 497.773714 146.285714z m0 52.955428c164.205714 0 297.325714 130.194286 297.325714 290.742858 0 160.621714-133.12 290.816-297.325714 290.816-164.242286 0-297.398857-130.194286-297.398857-290.779429 0-160.621714 133.12-290.779429 297.398857-290.779429z"/></svg>`;
1504
+ const CLEAR_SVG = `<svg viewBox="0 0 24 24" fill="none" aria-hidden="true"><circle cx="12" cy="12" r="9" fill="currentColor" opacity="0.15"></circle><path d="M9 9L15 15M15 9L9 15" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"></path></svg>`;
1505
+ const MOBILE_BACK_SVG = `<svg viewBox="0 0 24 24" fill="none" aria-hidden="true"><path d="M15 5L8 12L15 19" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"></path></svg>`;
1506
+ function createNavbarMenuTreeHtml() {
1507
+ return `
1508
+ <div
1509
+ data-gjs-type="${WB_CMS_MENU_TREE_TYPE}"
1510
+ data-wb-component="cms-menu-tree"
1511
+ data-cms-component="menu-tree"
1512
+ data-menu-code="${DEFAULT_MENU_TREE_CODE}"
1513
+ data-render-mode="tree"
1514
+ class="wb-menu-tree site-header__nav-list"
1515
+ >
1516
+ <nav class="wb-menu-tree-nav" aria-label="Primary menu">
1517
+ <ul class="wb-menu-tree-list">
1518
+ <li class="wb-menu-tree-item" data-cms-repeat="menuItem@menu.items" data-cms-bind-classappend="menuItem.hasChildrenClass">
1519
+ <a class="wb-menu-tree-link" href="#" data-cms-bind-href="menuItem.url" data-cms-bind-target="menuItem.target">
1520
+ <span data-cms-bind="menuItem.title">Menu Item</span>
1521
+ <img class="wb-menu-tree-icon" src="" alt="" data-cms-bind-src="menuItem.icon" data-cms-bind-alt="menuItem.title">
1522
+ </a>
1523
+ <ul class="wb-menu-tree-submenu" data-cms-if="menuItem.hasChildren">
1524
+ <li class="wb-menu-tree-item" data-cms-repeat="child@menuItem.children" data-cms-bind-classappend="child.hasChildrenClass">
1525
+ <a class="wb-menu-tree-link" href="#" data-cms-bind-href="child.url" data-cms-bind-target="child.target">
1526
+ <span data-cms-bind="child.title">Sub Menu Item</span>
1527
+ <img class="wb-menu-tree-icon" src="" alt="" data-cms-bind-src="child.icon" data-cms-bind-alt="child.title">
1528
+ </a>
1529
+ <ul class="wb-menu-tree-submenu" data-cms-if="child.hasChildren">
1530
+ <li class="wb-menu-tree-item" data-cms-repeat="grandchild@child.children">
1531
+ <a class="wb-menu-tree-link" href="#" data-cms-bind-href="grandchild.url" data-cms-bind-target="grandchild.target">
1532
+ <span data-cms-bind="grandchild.title">Sub Menu Item</span>
1533
+ </a>
1534
+ </li>
1535
+ </ul>
1536
+ </li>
1537
+ </ul>
1538
+ </li>
1539
+ </ul>
1540
+ </nav>
1541
+ </div>`;
1542
+ }
1543
+ function createNavbarThbHtml() {
1544
+ return `
1545
+ <div class="site-header__inner page-width">
1546
+ <nav class="site-header__nav" aria-label="Primary navigation">
1547
+ <div class="site-header__logo">
1548
+ <a class="site-header__logo-link" href="/">
1549
+ <img class="site-header__logo-img" src="" alt="Logo" width="120" height="36" data-default-logo="" data-scrolled-logo="">
1550
+ </a>
1551
+ </div>
1552
+
1553
+ ${createNavbarMenuTreeHtml()}
1554
+
1555
+ <div class="site-header__actions">
1556
+ <div class="site-header__search">
1557
+ ${SEARCH_SVG}
1558
+ <input type="search" name="q" placeholder="Search..." aria-label="Search" autocomplete="off">
1559
+ </div>
1560
+ <a href="#" class="btn btn--consult">Consult THB</a>
1561
+ <button class="site-header__hamburger" type="button" aria-label="Toggle menu" aria-expanded="false">
1562
+ <span></span><span></span><span></span>
1563
+ </button>
1564
+ </div>
1565
+
1566
+ <button class="site-header__mobile-search" type="button" aria-label="Search" aria-expanded="false">
1567
+ ${SEARCH_SVG}
1568
+ </button>
1569
+ </nav>
1570
+ </div>
1571
+
1572
+ <div class="site-search" role="dialog" aria-modal="true" aria-label="Search" aria-hidden="true">
1573
+ <div class="site-search__bar">
1574
+ <form class="site-search__form" role="search" action="/search" method="get">
1575
+ <i class="site-search__icon" aria-hidden="true">${SEARCH_SVG}</i>
1576
+ <input class="site-search__input" type="search" name="q" placeholder="Search products, insights..." aria-label="Search query" autocomplete="off">
1577
+ <button class="site-search__clear" type="button" aria-label="Clear search" hidden>${CLEAR_SVG}</button>
1578
+ </form>
1579
+ <button class="site-search__close" type="button" aria-label="Close search">Cancel</button>
1580
+ </div>
1581
+ </div>
1582
+
1583
+ <nav class="nav-mobile" aria-label="Mobile navigation" aria-hidden="true">
1584
+ <div class="nav-mobile__content">
1585
+ <section class="nav-mobile__panel is-active" data-panel="root">
1586
+ <h2 class="nav-mobile__heading">Menu</h2>
1587
+ <ul class="nav-mobile__list">
1588
+ <li data-cms-repeat="menuItem@menu.items" data-cms-bind-classappend="menuItem.hasChildrenClass">
1589
+ <a class="nav-mobile__link" href="#" data-cms-bind-href="menuItem.url" data-cms-bind-target="menuItem.target">
1590
+ <span data-cms-bind="menuItem.title">Menu Item</span>
1591
+ </a>
1592
+ <button class="nav-mobile__expand" type="button" data-cms-if="menuItem.hasChildren" aria-label="Open submenu">
1593
+ <span class="nav-mobile__entry-icon" aria-hidden="true">+</span>
1594
+ </button>
1595
+ <section class="nav-mobile__panel" data-cms-if="menuItem.hasChildren">
1596
+ <div class="nav-mobile__heading-row">
1597
+ <button class="nav-mobile__back" type="button" data-back aria-label="Back">${MOBILE_BACK_SVG}</button>
1598
+ <h2 class="nav-mobile__heading" data-cms-bind="menuItem.title">Menu Item</h2>
1599
+ </div>
1600
+ <ul class="nav-mobile__list">
1601
+ <li data-cms-repeat="child@menuItem.children" data-cms-bind-classappend="child.hasChildrenClass">
1602
+ <a class="nav-mobile__link" href="#" data-cms-bind-href="child.url" data-cms-bind-target="child.target">
1603
+ <span data-cms-bind="child.title">Sub Menu Item</span>
1604
+ </a>
1605
+ </li>
1606
+ </ul>
1607
+ <a class="nav-mobile__viewall" href="#" data-cms-bind-href="menuItem.url" data-cms-bind-target="menuItem.target">View All <span aria-hidden="true">»</span></a>
1608
+ </section>
1609
+ </li>
1610
+ </ul>
1611
+ </section>
1612
+ </div>
1613
+ </nav>`;
1614
+ }
1615
+ function registerMenuTreePublisherComponent(editor) {
1616
+ const domComponents = editor == null ? void 0 : editor.DomComponents;
1617
+ if (!domComponents || domComponents.getType(WB_CMS_MENU_TREE_TYPE))
1618
+ return;
1619
+ domComponents.addType(WB_CMS_MENU_TREE_TYPE, {
1620
+ isComponent: (el) => {
1621
+ var _a, _b;
1622
+ return ((_a = el == null ? void 0 : el.getAttribute) == null ? void 0 : _a.call(el, "data-cms-component")) === "menu-tree" || ((_b = el == null ? void 0 : el.getAttribute) == null ? void 0 : _b.call(el, "data-wb-component")) === "cms-menu-tree" ? { type: WB_CMS_MENU_TREE_TYPE } : false;
1623
+ },
1624
+ model: {
1625
+ defaults: {
1626
+ tagName: "div",
1627
+ droppable: true,
1628
+ attributes: {
1629
+ "data-wb-component": "cms-menu-tree",
1630
+ "data-cms-component": "menu-tree",
1631
+ "data-menu-code": DEFAULT_MENU_TREE_CODE,
1632
+ "data-render-mode": "tree",
1633
+ class: "wb-menu-tree"
1634
+ }
1635
+ }
1636
+ }
1637
+ });
1638
+ }
1639
+ function registerNavbarThbPublisherComponent(editor) {
1640
+ const domComponents = editor == null ? void 0 : editor.DomComponents;
1641
+ if (!domComponents || domComponents.getType(WB_NAVBAR_THB_TYPE))
1642
+ return;
1643
+ registerMenuTreePublisherComponent(editor);
1644
+ domComponents.addType(WB_NAVBAR_THB_TYPE, {
1645
+ isComponent: (el) => {
1646
+ var _a;
1647
+ return (el == null ? void 0 : el.tagName) === "HEADER" && ((_a = el.classList) == null ? void 0 : _a.contains("site-header")) ? { type: WB_NAVBAR_THB_TYPE } : false;
1648
+ },
1649
+ model: {
1650
+ defaults: {
1651
+ name: "Navbar THB",
1652
+ tagName: "header",
1653
+ classes: ["site-header", "site-header--fixed-transparent"],
1654
+ droppable: false,
1655
+ draggable: true,
1656
+ copyable: false,
1657
+ script: navbarThbScript,
1658
+ "script-export": navbarThbScript,
1659
+ styles: NAVBAR_THB_STYLES,
1660
+ components: createNavbarThbHtml()
1661
+ }
1662
+ }
1663
+ });
1664
+ }
1665
+ const CMS_PUBLISHER_REGISTRIES = [
1666
+ { id: "cmsDynamicText", register: registerDynamicTextBlock },
1667
+ { id: "cmsDynamicHtml", register: registerDynamicHtmlBlock },
1668
+ { id: "cmsDynamicImage", register: registerDynamicImageBlock },
1669
+ { id: "cmsDynamicLink", register: registerDynamicLinkBlock },
1670
+ { id: "cmsDynamicDatetime", register: registerDynamicDatetimeBlock },
1671
+ { id: "cmsDynamicConditional", register: registerDynamicConditionalBlock },
1672
+ { id: "cmsDynamicBreadcrumb", register: registerDynamicBreadcrumbBlock },
1673
+ { id: "cmsDynamicToc", register: registerDynamicTocBlock },
1674
+ { id: "cmsDynamicSeo", register: registerDynamicSeoBlock },
1675
+ { id: "loopGrid", register: registerLoopGridPublisherComponent },
1676
+ { id: "navbarThb", register: registerNavbarThbPublisherComponent }
1677
+ ];
1678
+ function registerCmsPublisherComponents(editor) {
1679
+ for (const registry of CMS_PUBLISHER_REGISTRIES) {
1680
+ try {
1681
+ registry.register(editor);
1682
+ } catch (error) {
1683
+ const message = error instanceof Error ? error.message : String(error);
1684
+ throw new Error(`[WebBuilder Publisher] Failed to register cms:${registry.id}: ${message}`);
1685
+ }
1686
+ }
1687
+ }
1688
+ const WEB_BUILDER_PUBLISHER_COMPONENT_REGISTRARS = [
1689
+ { id: "basic", register: registerBasicPublisherComponents },
1690
+ { id: "cms", register: registerCmsPublisherComponents }
1691
+ ];
1692
+ function registerWebBuilderPublisherComponents(editor) {
1693
+ for (const registrar of WEB_BUILDER_PUBLISHER_COMPONENT_REGISTRARS) {
1694
+ try {
1695
+ registrar.register(editor);
1696
+ } catch (error) {
1697
+ const message = error instanceof Error ? error.message : String(error);
1698
+ throw new Error(`[WebBuilder Publisher] Failed to register ${registrar.id}: ${message}`);
1699
+ }
1700
+ }
1701
+ }
1702
+ export {
1703
+ WEB_BUILDER_PUBLISHER_COMPONENT_REGISTRARS,
1704
+ WEB_BUILDER_PUBLISHER_FEATURE_PLUGINS,
1705
+ collectPublisherContributions2 as collectPublisherContributions,
1706
+ createWebBuilderPublisherPluginRegistry,
1707
+ createWebBuilderPublisherRuntimeRegistry,
1708
+ registerWebBuilderPublisherComponents,
1709
+ renderWebBuilderPublisherAssets,
1710
+ renderWebBuilderPublisherPluginAssets
1711
+ };