Error executing template "Designs/Swift/Swift_Branding.cshtml"
System.NullReferenceException: Object reference not set to an instance of an object.
at CompiledRazorTemplates.Dynamic.RazorEngine_a999cfc76b2447f786a67604543e76c3.ExecuteAsync()
at RazorEngine.Templating.TemplateBase.Run(ExecuteContext context, TextWriter reader)
at RazorEngine.Templating.RazorEngineCore.RunTemplate(ICompiledTemplate template, TextWriter writer, Object model, DynamicViewBag viewBag)
at RazorEngine.Templating.RazorEngineService.Run(ITemplateKey key, TextWriter writer, Type modelType, Object model, DynamicViewBag viewBag)
at RazorEngine.Templating.DynamicWrapperService.Run(ITemplateKey key, TextWriter writer, Type modelType, Object model, DynamicViewBag viewBag)
at RazorEngine.Templating.RazorEngineServiceExtensions.Run(IRazorEngineService service, String name, TextWriter writer, Type modelType, Object model, DynamicViewBag viewBag)
at RazorEngine.Templating.RazorEngineServiceExtensions.<>c__DisplayClass23_0.<Run>b__0(TextWriter writer)
at RazorEngine.Templating.RazorEngineServiceExtensions.WithWriter(Action`1 withWriter)
at RazorEngine.Templating.RazorEngineServiceExtensions.Run(IRazorEngineService service, String name, Type modelType, Object model, DynamicViewBag viewBag)
at Dynamicweb.Rendering.RazorTemplateRenderingProvider.Render(Template template) in /_/src/Application/Providers/Dynamicweb.Rendering.Providers.NetCore/Razor/RazorTemplateRenderingProvider.cs:line 99
at Dynamicweb.Rendering.TemplateRenderingService.Render(Template template) in E:\A10\_w\2\s\src\Core\Dynamicweb.Core\Rendering\TemplateRenderingService.cs:line 21
at Dynamicweb.Rendering.Template.RenderRazorTemplate() in E:\A10\_w\2\s\src\Core\Dynamicweb.Core\Rendering\Template.cs:line 749
1 @inherits Dynamicweb.Rendering.ViewModelTemplate<Dynamicweb.Frontend.PageViewModel>
2 @using Dynamicweb
3 @using Dynamicweb.Environment
4
5 @functions {
6 string GetCookieOptInPermission(string category)
7 {
8 bool categoryOrAllGranted = false;
9
10 if (CookieManager.IsCookieManagementActive)
11 {
12 var cookieOptInLevel = CookieManager.GetCookieOptInLevel();
13 var cookieOptInCategories = CookieManager.GetCookieOptInCategories();
14 categoryOrAllGranted = cookieOptInCategories.Contains(category) || cookieOptInLevel == CookieOptInLevel.All;
15 }
16
17 return categoryOrAllGranted ? "granted" : "denied";
18 }
19
20 bool AllowTracking()
21 {
22 bool allowTracking = true;
23 if (CookieManager.IsCookieManagementActive)
24 {
25 var cookieOptInLevel = CookieManager.GetCookieOptInLevel();
26 var cookieOptInCategories = CookieManager.GetCookieOptInCategories();
27
28 bool consentEither = (cookieOptInCategories.Contains("Statistical") || cookieOptInCategories.Contains("Marketing"));
29 bool consentFunctional = cookieOptInLevel == CookieOptInLevel.Functional;
30 bool consentAtLeastOne = cookieOptInLevel == CookieOptInLevel.All || (consentFunctional && consentEither);
31
32 allowTracking = consentAtLeastOne;
33 }
34 return allowTracking;
35 }
36 }
37
38 @{
39 string swiftVersion = ReadFile("/Files/Templates/Designs/Swift/swift_version.txt");
40 @* Branding Themes Fonts *@
41 var brandingPageId = Model.Area.Item.GetLink("BrandingPage") != null ? Model.Area.Item.GetLink("BrandingPage").PageId : 0;
42 var themePageId = Model.Area.Item.GetLink("ThemesPage") != null ? Model.Area.Item.GetLink("ThemesPage").PageId : 0;
43
44 var disableWideBreakpoints = Model.Area?.Item?.GetRawValueString("DisableWideBreakpoints", "default");
45
46 string customHeaderInclude = Model.Area.Item.GetRawValueString("CustomHeaderInclude").Replace("/Files/Templates/Designs/Swift/", "");
47 if (Model.Area.Item.GetFile("CustomHeaderInclude") != null)
48 {
49 customHeaderInclude = Model.Area.Item.GetFile("CustomHeaderInclude").Path.Replace("/Files/Templates/Designs/Swift/", "");
50 }
51
52 string masterTheme = !string.IsNullOrWhiteSpace(Model.Area.Item.GetRawValueString("Theme")) ? " theme " + Model.Area.Item.GetRawValueString("Theme").Replace(" ", "").Trim().ToLower() : "";
53
54 string favicon = Model.Area.Item.GetFile("Favicon") != null ? Model.Area.Item.GetFile("Favicon").Path : "/Files/Templates/Designs/Swift/Assets/Images/favicon.png";
55
56 var brandingPage = Dynamicweb.Content.Services.Pages?.GetPage(brandingPageId) ?? null;
57 var themesParagraphLastChanged = Dynamicweb.Content.Services.Paragraphs.GetParagraphsByPageId(themePageId).OrderByDescending(p => p.Audit.LastModifiedAt).FirstOrDefault();
58 var cssLastModified = brandingPage.Audit.LastModifiedAt > themesParagraphLastChanged.Audit.LastModifiedAt ? brandingPage.Audit.LastModifiedAt : themesParagraphLastChanged.Audit.LastModifiedAt;
59
60 var cssStyleFileInfo = new System.IO.FileInfo(Dynamicweb.Core.SystemInformation.MapPath("/Files/Templates/Designs/Swift/Assets/css/styles.css"));
61 var jsFileInfo = new System.IO.FileInfo(Dynamicweb.Core.SystemInformation.MapPath("/Files/Templates/Designs/Swift/Assets/js/scripts.js"));
62
63 string googleTagManagerID = Model.Area.Item.GetString("GoogleTagManagerID");
64 string googleAnalyticsMeasurementID = Pageview.AreaSettings.GetString("GoogleAnalyticsMeasurementID");
65
66 bool allowTracking = AllowTracking();
67
68 // Schema.org details for PDP
69 string productId = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.QueryString.Get("ProductID")) ? Dynamicweb.Context.Current.Request.QueryString.Get("ProductID") : "";
70 bool isProductDetailsPage = !string.IsNullOrEmpty(productId);
71 bool isArticlePage = Model.ItemType == "Swift_Article";
72 string schemaOrgType = string.Empty;
73
74 if (isProductDetailsPage)
75 {
76 schemaOrgType = "itemscope=\"\" itemtype=\"https://schema.org/Product\"";
77 }
78
79 if (isArticlePage)
80 {
81 schemaOrgType = "itemscope=\"\" itemtype=\"https://schema.org/Article\"";
82 }
83 }
84
85 <!doctype html>
86 <html lang="@Pageview.Area.CultureInfo.TwoLetterISOLanguageName">
87 <head>
88 <!-- @swiftVersion -->
89 @* Required meta tags *@
90 <meta charset="utf-8">
91 <meta name="viewport" content="height=device-height, width=device-width, initial-scale=1.0">
92 <link rel="preload" href="/Files/Templates/Designs/Swift/Assets/css/styles.css?@cssStyleFileInfo.LastWriteTime.Ticks" as="style">
93 <link rel="preload" href="/Files/Templates/Designs/Swift/Assets/js/scripts.js?@jsFileInfo.LastWriteTime.Ticks" as="script">
94
95 <link rel="shortcut icon" href="@favicon">
96 <link rel="apple-touch-icon" href="/Files/Templates/Designs/Swift/Assets/Images/logo_transparent.png">
97 <meta http-equiv="X-UA-Compatible" content="ie=edge">
98 <meta name="googlebot-news" content="nosnippet">
99
100 @Model.MetaTags
101
102 <title>@Model.Title</title>
103
104 @* Bootstrap + Swift stylesheet *@
105 <link href="/Files/Templates/Designs/Swift/Assets/css/styles.css?@cssStyleFileInfo.LastWriteTime.Ticks" rel="stylesheet" media="all" type="text/css">
106
107 @if (disableWideBreakpoints != "disableBoth")
108 {
109 <style>
110 @@media ( min-width: 1600px ) {
111 .container-xxl,
112 .container-xl,
113 .container-lg,
114 .container-md,
115 .container-sm,
116 .container {
117 max-width: 1520px;
118 }
119 }
120 </style>
121
122 if (disableWideBreakpoints != "disableUltraWideOnly")
123 {
124 <style>
125 @@media ( min-width: 1920px ) {
126 .container-xxl,
127 .container-xl,
128 .container-lg,
129 .container-md,
130 .container-sm,
131 .container {
132 max-width: 1820px;
133 }
134 }
135 </style>
136 }
137 }
138
139 @* Branding and Themes min stylesheet *@
140 <link href="/Files/Templates/Designs/Swift/_parsed/Swift_css/Swift_styles_@(Model.Area.ID).min.css?@cssLastModified.Ticks" rel="stylesheet" media="all" type="text/css" data-last-modified-content="@cssLastModified">
141 <script src="/Files/Templates/Designs/Swift/Assets/js/scripts.js?@jsFileInfo.LastWriteTime.Ticks"></script>
142
143 <script type="module">
144 swift.Scroll.hideHeadersOnScroll();
145 swift.Scroll.handleAlternativeTheme();
146
147 //Only load if AOS
148 const aosColumns = document.querySelectorAll('[data-aos]');
149 if (aosColumns.length > 0) {
150 swift.AssetLoader.Load('/Files/Templates/Designs/Swift/Assets/js/aos.js?@jsFileInfo.LastWriteTime.Ticks', 'js');
151 document.addEventListener('load.swift.assetloader', function () {
152 AOS.init({ duration: 400, delay: 100, easing: 'ease-in-out', mirror: false, disable: window.matchMedia('(prefers-reduced-motion: reduce)') });
153 });
154 }
155 </script>
156
157 @* Google gtag method - always include even if it is not used for anything *@
158 <script>
159 window.dataLayer = window.dataLayer || [];
160 function gtag() { dataLayer.push(arguments); }
161 </script>
162 @* Google tag manager *@
163 @if (!string.IsNullOrWhiteSpace(googleTagManagerID))
164 {
165 <script>
166 gtag('consent', 'default', {
167 'ad_storage': 'denied',
168 'ad_user_data': 'denied',
169 'ad_personalization': 'denied',
170 'analytics_storage': 'denied'
171 });
172 </script>
173 <script>
174 (function (w, d, s, l, i) {
175 w[l] = w[l] || []; w[l].push({
176 'gtm.start':
177 new Date().getTime(), event: 'gtm.js'
178 }); var f = d.getElementsByTagName(s)[0],
179 j = d.createElement(s), dl = l != 'dataLayer' ? '&l=' + l : ''; j.async = true; j.src =
180 'https://www.googletagmanager.com/gtm.js?id=' + i + dl; f.parentNode.insertBefore(j, f);
181 })(window, document, 'script', 'dataLayer', '@(googleTagManagerID)');
182 </script>
183 if (allowTracking)
184 {
185 string adConsent = GetCookieOptInPermission("Marketing");
186 string analyticsConsent = GetCookieOptInPermission("Statistical");
187 <script>
188 gtag('consent', 'update', {
189 'ad_storage': '@adConsent',
190 'ad_user_data': '@adConsent',
191 'ad_personalization': '@adConsent',
192 'analytics_storage': '@analyticsConsent'
193 });
194 </script>
195 }
196 }
197
198 @if (!string.IsNullOrWhiteSpace(googleAnalyticsMeasurementID) && allowTracking)
199 {
200 var GoogleAnalyticsDebugMode = "";
201
202 if (Model.Area.Item.GetBoolean("EnableGoogleAnalyticsDebugMode"))
203 {
204 GoogleAnalyticsDebugMode = ", {'debug_mode': true}";
205 }
206
207 <script async src="https://www.googletagmanager.com/gtag/js?id=@googleAnalyticsMeasurementID"></script>
208 <script>
209 gtag('js', new Date());
210 gtag('config', '@googleAnalyticsMeasurementID'@GoogleAnalyticsDebugMode);
211 </script>
212 }
213
214 @if (!string.IsNullOrWhiteSpace(customHeaderInclude))
215 {
216 @RenderPartial(customHeaderInclude)
217 }
218 </head>
219
220 <body class="brand @(masterTheme)">
221
222 @* Google tag manager *@
223 @if (!string.IsNullOrWhiteSpace(googleTagManagerID) && allowTracking)
224 {
225 <noscript>
226 <iframe src="https://www.googletagmanager.com/ns.html?id=@(googleTagManagerID)"
227 height="0" width="0" style="display:none;visibility:hidden"></iframe>
228 </noscript>
229 }
230
231 <div data-intersect></div>
232
233 <main id="content" @(schemaOrgType)>
234 @inherits Dynamicweb.Rendering.ViewModelTemplate<Dynamicweb.Frontend.PageViewModel>
235 @using Dynamicweb.Frontend
236 @using System.Text.RegularExpressions
237
238
239 @functions {
240
241 private GoogleFontViewModel GetViewModelValue(object value)
242 {
243 Dynamicweb.Content.Items.Editors.GoogleFont font = default;
244
245 if (value is object)
246 {
247 font = Dynamicweb.Core.Converter.Deserialize<Dynamicweb.Content.Items.Editors.GoogleFont>(value.ToString());
248
249 if (string.IsNullOrWhiteSpace(font?.Family))
250 {
251 font = default;
252 }
253 }
254
255 return CreateGoogleFontViewModel(font);
256 }
257
258 private GoogleFontViewModel CreateGoogleFontViewModel(Dynamicweb.Content.Items.Editors.GoogleFont font)
259 {
260 GoogleFontViewModel model = null;
261 if (font is object)
262 {
263 model = new GoogleFontViewModel
264 {
265 Family = font.Family,
266 Version = font.Version,
267 Weight = font.SelectedVariant,
268 File = font.Files[font.SelectedVariant]
269 };
270 }
271
272 return model;
273 }
274
275 private ItemViewModel GetCustomFont(string fieldName)
276 {
277 var id = Dynamicweb.Core.Converter.ToInt32(Model.Item.GetRawValueString(fieldName));
278 var font = id > 0 ? Dynamicweb.Frontend.ContentViewModelFactory.CreateParagraphInfoViewModel(Dynamicweb.Content.Services.Paragraphs.GetParagraph(id))?.Item : null;
279 return font;
280 }
281
282 private string GetFontType(string fieldName)
283 {
284 var fontType = Model.Item.GetRawValueString(fieldName);
285 return fontType;
286 }
287
288 private string GetFontValue(string regex, string value)
289 {
290 var fontValue = string.Empty;
291 fontValue = System.Text.RegularExpressions.Regex.Replace(value, regex, string.Empty);
292 return fontValue;
293 }
294 }
295
296 @{
297 List<string> fontList = new List<string>();
298
299 GoogleFontViewModel headerFont = null;
300 ItemViewModel headerFontCustom = null;
301 string headerFontFamily = "Roboto";
302 string headerFontWeight = "normal";
303 string headerFontStyle = "normal";
304 string headerCasing = "inherit";
305 string headerLineHeight = "1.2";
306 string headerLetterSpacing = "0";
307 GoogleFontViewModel displayFont = null;
308 ItemViewModel displayFontCustom = null;
309 string displayFontFamily = "Roboto";
310 string displayFontWeight = "normal";
311 string displayFontStyle = "normal";
312 string displayCasing = "inherit";
313 string displayLineHeight = "1.2";
314 string displayLetterSpacing = "0";
315 GoogleFontViewModel bodyFont = null;
316 ItemViewModel bodyFontCustom = null;
317 string bodyFontFamily = "Roboto";
318 string bodyFontWeight = "normal";
319 string bodyFontStyle = "normal";
320 string bodyLineHeight = "1.5";
321 string bodyLetterSpacing = "0";
322
323 string primaryButtonFontWeight = "normal";
324 string primaryButtonCasing = "inherit";
325 string primaryButtonShape = "0";
326 string primaryButtonXpadding = "0.75";
327 string primaryButtonYpadding = "0.375";
328
329 string secondaryButtonFontWeight = "normal";
330 string secondaryButtonCasing = "inherit";
331 string secondaryButtonShape = "0";
332 string secondaryButtonXpadding = "0.75";
333 string secondaryButtonYpadding = "0.375";
334
335 string linkButtonFontWeight = "inherit";
336 string linkButtonCasing = "inherit";
337
338 if (Model.Item != null)
339 {
340 @* HEADER font*@
341 headerFont = Model.Item.GetGoogleFont("HeaderFont");
342 headerFont = GetViewModelValue(Model.Item.GetRawValueString("HeaderFont"));
343 headerFontCustom = GetCustomFont("HeaderFontCustom");
344 if (GetFontType("HeaderFontType") == "custom" && headerFontCustom is object)
345 {
346 headerFontFamily = headerFontCustom.GetString("FontFamilyName");
347 headerFontWeight = headerFontCustom.GetRawValueString("FontWeight");
348 headerFontStyle = headerFontCustom.GetRawValueString("FontStyle");
349 }
350
351 if (GetFontType("HeaderFontType") != "custom" && headerFont != null)
352 {
353 headerFontFamily = headerFont.Family;
354 headerFontWeight = !string.IsNullOrEmpty(GetFontValue("([^0-9])", headerFont.Weight)) ? GetFontValue("([^0-9])", headerFont.Weight) : headerFontWeight;
355 headerFontStyle = !string.IsNullOrEmpty(GetFontValue("([0-9])", headerFont.Weight)) ? GetFontValue("([0-9])", headerFont.Weight) : headerFontStyle;
356
357 fontList.Add(System.Net.WebUtility.UrlEncode(headerFontFamily) + ":ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900");
358 }
359
360 headerCasing = Model.Item.GetRawValueString("HeaderCasing");
361 headerLineHeight = Model.Item.GetDouble("HeaderLineHeight").ToString(System.Globalization.CultureInfo.GetCultureInfo("en-US"));
362 headerLetterSpacing = Model.Item.GetDouble("HeaderLetterSpacing").ToString(System.Globalization.CultureInfo.GetCultureInfo("en-US"));
363
364 @* DISPLAY font*@
365 displayFont = Model.Item.GetGoogleFont("DisplayFont");
366 displayFont = GetViewModelValue(Model.Item.GetRawValueString("DisplayFont"));
367 displayFontCustom = GetCustomFont("DisplayFontCustom");
368 if (GetFontType("DisplayFontType") == "custom" && displayFontCustom is object)
369 {
370 displayFontFamily = displayFontCustom.GetString("FontFamilyName");
371 displayFontWeight = displayFontCustom.GetRawValueString("FontWeight");
372 displayFontStyle = displayFontCustom.GetRawValueString("FontStyle");
373 }
374
375 if (GetFontType("DisplayFontType") != "custom" && displayFont != null)
376 {
377 displayFontFamily = displayFont.Family;
378 displayFontWeight = !string.IsNullOrEmpty(GetFontValue("([^0-9])", displayFont.Weight)) ? GetFontValue("([^0-9])", displayFont.Weight) : displayFontWeight;
379 displayFontStyle = !string.IsNullOrEmpty(GetFontValue("([0-9])", displayFont.Weight)) ? GetFontValue("([0-9])", displayFont.Weight) : displayFontStyle;
380 fontList.Add(System.Net.WebUtility.UrlEncode(displayFontFamily) + ":ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900");
381 }
382
383 displayCasing = Model.Item.GetRawValueString("DisplayCasing");
384 displayLineHeight = Model.Item.GetDouble("DisplayLineHeight").ToString(System.Globalization.CultureInfo.GetCultureInfo("en-US"));
385 displayLetterSpacing = Model.Item.GetDouble("DisplayLetterSpacing").ToString(System.Globalization.CultureInfo.GetCultureInfo("en-US"));
386
387 @* BODY font*@
388 bodyFont = Model.Item.GetGoogleFont("BodyFont");
389 bodyFont = GetViewModelValue(Model.Item.GetRawValueString("BodyFont"));
390 bodyFontCustom = GetCustomFont("BodyFontCustom");
391 if (GetFontType("BodyFontType") == "custom" && bodyFontCustom is object)
392 {
393 bodyFontFamily = bodyFontCustom.GetString("FontFamilyName");
394 bodyFontWeight = bodyFontCustom.GetRawValueString("FontWeight");
395 bodyFontStyle = bodyFontCustom.GetRawValueString("FontStyle");
396 }
397
398 if (GetFontType("BodyFontType") != "custom" && bodyFont != null)
399 {
400 bodyFontFamily = bodyFont.Family;
401 bodyFontWeight = !string.IsNullOrEmpty(GetFontValue("([^0-9])", bodyFont.Weight)) ? GetFontValue("([^0-9])", bodyFont.Weight) : bodyFontWeight;
402 bodyFontStyle = !string.IsNullOrEmpty(GetFontValue("([0-9])", bodyFont.Weight)) ? GetFontValue("([0-9])", bodyFont.Weight) : bodyFontStyle;
403 fontList.Add(System.Net.WebUtility.UrlEncode(bodyFontFamily) + ":ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900");
404 }
405 bodyLineHeight = Model.Item.GetDouble("BodyLineHeight").ToString(System.Globalization.CultureInfo.GetCultureInfo("en-US"));
406 bodyLetterSpacing = Model.Item.GetDouble("BodyLetterSpacing").ToString(System.Globalization.CultureInfo.GetCultureInfo("en-US"));
407
408 @* Primary button *@
409 primaryButtonFontWeight = Model.Item.GetRawValueString("PrimaryButtonFontWeight", "normal");
410 primaryButtonCasing = Model.Item.GetRawValueString("PrimaryButtonCasing", "initial");
411
412 primaryButtonShape = Model.Item.GetRawValueString("PrimaryButtonShape", "0");
413 primaryButtonShape = primaryButtonShape == "rounded" ? ".25rem" : primaryButtonShape;
414 primaryButtonShape = primaryButtonShape == "pill" ? "12.5rem" : primaryButtonShape;
415
416 if (Model.Item.GetDouble("ButtonPrimaryXPadding") != 0.0)
417 {
418 primaryButtonXpadding = Model.Item.GetDouble("ButtonPrimaryXPadding").ToString(System.Globalization.CultureInfo.GetCultureInfo("en-US"));
419 }
420 if (Model.Item.GetDouble("ButtonPrimaryYPadding") != 0.0)
421 {
422 primaryButtonYpadding = Model.Item.GetDouble("ButtonPrimaryYPadding").ToString(System.Globalization.CultureInfo.GetCultureInfo("en-US"));
423 }
424
425 @* Secondary button *@
426 secondaryButtonFontWeight = Model.Item.GetRawValueString("SecondaryButtonFontWeight", "normal");
427 secondaryButtonCasing = Model.Item.GetRawValueString("SecondaryButtonCasing", "initial");
428
429 secondaryButtonShape = Model.Item.GetRawValueString("SecondaryButtonShape", "0");
430 secondaryButtonShape = secondaryButtonShape == "rounded" ? ".25rem" : secondaryButtonShape;
431 secondaryButtonShape = secondaryButtonShape == "pill" ? "12.5rem" : secondaryButtonShape;
432
433
434 if (Model.Item.GetDouble("ButtonSecondaryXPadding") != 0.0)
435 {
436 secondaryButtonXpadding = Model.Item.GetDouble("ButtonSecondaryXPadding").ToString(System.Globalization.CultureInfo.GetCultureInfo("en-US"));
437 }
438
439 if (Model.Item.GetDouble("ButtonSecondaryYPadding") != 0.0)
440 {
441 secondaryButtonYpadding = Model.Item.GetDouble("ButtonSecondaryYPadding").ToString(System.Globalization.CultureInfo.GetCultureInfo("en-US"));
442 }
443
444 @* Link *@
445 linkButtonFontWeight = Model.Item.GetRawValueString("LinkFontWeight", "normal");
446 linkButtonCasing = Model.Item.GetRawValueString("LinkCasing", "initial");
447 }
448
449 var fontsToLink = string.Join("&", fontList.Where(x => !string.IsNullOrEmpty(x)).Distinct().Select(x => string.Format("family={0}", x)));
450 var fontLink = $"https://fonts.googleapis.com/css2?{fontsToLink}&display=swap";
451 var sb = new System.Text.StringBuilder();
452
453 async System.Threading.Tasks.Task<string> GetGoogleCss(string fonturl)
454 {
455 var client = new System.Net.Http.HttpClient();
456 client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("*/*"));
457 client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("font/woff2"));
458 client.DefaultRequestHeaders.Add("User-Agent", Dynamicweb.Context.Current.Request.UserAgent);
459
460 System.Net.Http.HttpResponseMessage response = await client.GetAsync(fonturl);
461 response.EnsureSuccessStatusCode();
462 if (response.StatusCode == System.Net.HttpStatusCode.OK)
463 {
464 return await response.Content.ReadAsStringAsync();
465 }
466 return string.Empty;
467 }
468
469 async System.Threading.Tasks.Task DownloadAndSavefont(string fontUrl, string localPath)
470 {
471 var fullPath = Dynamicweb.Core.SystemInformation.MapPath(localPath);
472 var fileinfo = new System.IO.FileInfo(fullPath);
473 var client = new System.Net.Http.HttpClient();
474 System.Net.Http.HttpResponseMessage dataResponse = await client.GetAsync(fontUrl);
475 dataResponse.EnsureSuccessStatusCode();
476 if (dataResponse.StatusCode == System.Net.HttpStatusCode.OK)
477 {
478 var data = await dataResponse.Content.ReadAsByteArrayAsync();
479 System.IO.Directory.CreateDirectory(fileinfo.DirectoryName);
480 System.IO.File.WriteAllBytes(fullPath, data);
481 }
482 }
483
484 string googleCss = string.Empty;
485
486 try
487 {
488 googleCss = GetGoogleCss(fontLink).GetAwaiter().GetResult();
489
490 Dictionary<string, string> googleFontUrls = new Dictionary<string, string>();
491 Regex cssUrlGoogleFontsRegEx = new Regex(@"url\((?<googleFontUrl>.+?)\)", RegexOptions.Compiled | RegexOptions.CultureInvariant);
492 string firstPartOfCss = googleCss.Substring(googleCss.LastIndexOf("{"), googleCss.LastIndexOf("}") - googleCss.LastIndexOf("{"));
493
494 MatchCollection matches = cssUrlGoogleFontsRegEx.Matches(googleCss);//We will only take the first URL as that is what is primarily used. If the remaining woff fonts needs loading, the browser will take care of that.
495
496 for (var i = 0; i < matches.Count; i++)
497 {
498 Match match = matches[i];
499 string url = match.Groups["googleFontUrl"].Value;
500 if (!googleFontUrls.ContainsKey(url))
501 {
502 googleFontUrls.Add(url, url);
503 }
504 }
505
506 if (googleFontUrls.Count > 0)
507 {
508 var fontSb = new System.Text.StringBuilder();
509 foreach (string url in googleFontUrls.Values)
510 {
511 var fontPathAndFilename = url.Replace("https://fonts.gstatic.com/s/", "");
512 var localUrl = $"/Files/Templates/Designs/Swift/Assets/fonts/{fontPathAndFilename}";
513
514 DownloadAndSavefont(url, localUrl).GetAwaiter().GetResult();
515
516 googleCss = googleCss.Replace(url, localUrl);
517
518 fontSb.AppendLine($"<link rel=\"preload\" href=\"{localUrl}\" as=\"font\" type=\"font/woff2\" crossorigin>");
519 }
520 string htmlPathFontPreload = Dynamicweb.Context.Current.Server.MapPath($"/Files/Templates/Designs/Swift/_parsed/Swift_css/Swift_GoogleFontUrls_{Model.Area.ID}.html");
521 Dynamicweb.Core.Helpers.TextFileHelper.WriteTextFile(fontSb.ToString(), htmlPathFontPreload, false);
522 }
523
524 sb.AppendLine(googleCss);
525 }
526 catch (Exception ex)
527 {
528 @*@ex.ToString()*@
529 }
530
531 sb.AppendLine("");
532
533 sb.AppendLine(".brand {");
534
535 sb.AppendLine($"--swift-header-font: '{headerFontFamily}';");
536 sb.AppendLine($"--swift-header-font-weight: {headerFontWeight};");
537 sb.AppendLine($"--swift-header-font-style: {headerFontStyle};");
538 sb.AppendLine($"--swift-header-casing: {headerCasing};");
539 sb.AppendLine($"--swift-header-line-height: {headerLineHeight};");
540 sb.AppendLine($"--swift-header-letter-spacing: {headerLetterSpacing}em;");
541 sb.AppendLine($"--swift-display-font: '{displayFontFamily}';");
542 sb.AppendLine($"--swift-display-font-weight: {displayFontWeight};");
543 sb.AppendLine($"--swift-display-font-style: {displayFontStyle};");
544 sb.AppendLine($"--swift-display-casing: {displayCasing};");
545 sb.AppendLine($"--swift-display-line-height: {displayLineHeight};");
546 sb.AppendLine($"--swift-display-letter-spacing: {displayLetterSpacing}em;");
547 sb.AppendLine($"--swift-body-font: '{bodyFontFamily}';");
548 sb.AppendLine($"--swift-body-font-weight: {bodyFontWeight};");
549 sb.AppendLine($"--swift-body-font-style: {bodyFontStyle};");
550 sb.AppendLine($"--swift-body-line-height: {bodyLineHeight};");
551 sb.AppendLine($"--swift-body-letter-spacing: {bodyLetterSpacing}em;");
552
553 sb.AppendLine($"--swift-button-primary-font-weight: {primaryButtonFontWeight};");
554 sb.AppendLine($"--swift-button-primary-casing: {primaryButtonCasing};");
555 sb.AppendLine($"--swift-button-primary-shape: {primaryButtonShape};");
556 sb.AppendLine($"--swift-button-primary-padding-x: {primaryButtonXpadding}rem;");
557 sb.AppendLine($"--swift-button-primary-padding-y: {primaryButtonYpadding}rem;");
558
559 sb.AppendLine($"--swift-button-secondary-font-weight: {secondaryButtonFontWeight};");
560 sb.AppendLine($"--swift-button-secondary-casing: {secondaryButtonCasing};");
561 sb.AppendLine($"--swift-button-secondary-shape: {secondaryButtonShape};");
562 sb.AppendLine($"--swift-button-secondary-padding-x: {secondaryButtonXpadding}rem;");
563 sb.AppendLine($"--swift-button-secondary-padding-y: {secondaryButtonYpadding}rem;");
564
565 sb.AppendLine($"--swift-button-link-font-weight: {linkButtonFontWeight};");
566 sb.AppendLine($"--swift-button-link-casing: {linkButtonCasing};");
567
568 sb.AppendLine($"--swift-debug-css-written: '{DateTime.Now.ToString()}';");
569 sb.AppendLine($"--swift-debug-page-changed: '{Model.UpdatedDate.ToString()}';");
570
571 sb.AppendLine("}");
572
573 string cssPathEcommerceBadges = Dynamicweb.Context.Current.Server.MapPath($"/Files/Templates/Designs/Swift/_parsed/Swift_css/Swift_ecommerce_badge_styles_{Model.Area.ID}.css");
574 string cssPathTheme = Dynamicweb.Context.Current.Server.MapPath($"/Files/Templates/Designs/Swift/_parsed/Swift_css/Swift_theme_styles_{Model.Area.ID}.css");
575 string cssPathFont = Dynamicweb.Context.Current.Server.MapPath($"/Files/Templates/Designs/Swift/_parsed/Swift_css/Swift_font_styles_{Model.Area.ID}.css");
576 string cssPathBranding = Dynamicweb.Context.Current.Server.MapPath($"/Files/Templates/Designs/Swift/_parsed/Swift_css/Swift_branding_styles_{Model.Area.ID}.css");
577 string cssPathCss = Dynamicweb.Context.Current.Server.MapPath($"/Files/Templates/Designs/Swift/_parsed/Swift_css/Swift_css_styles_{Model.Area.ID}.css");
578 string cssPathCombined = Dynamicweb.Context.Current.Server.MapPath($"/Files/Templates/Designs/Swift/_parsed/Swift_css/Swift_styles_{Model.Area.ID}.min.css");
579
580 Dynamicweb.Core.Helpers.TextFileHelper.WriteTextFile(sb.ToString(), cssPathBranding, false);
581
582 string combinedCss = Dynamicweb.Core.Helpers.TextFileHelper.ReadTextFile(cssPathBranding);
583 combinedCss += Dynamicweb.Core.Helpers.TextFileHelper.ReadTextFile(cssPathTheme);
584 combinedCss += Dynamicweb.Core.Helpers.TextFileHelper.ReadTextFile(cssPathFont);
585 combinedCss += Dynamicweb.Core.Helpers.TextFileHelper.ReadTextFile(cssPathEcommerceBadges);
586 combinedCss += Dynamicweb.Core.Helpers.TextFileHelper.ReadTextFile(cssPathCss);
587 combinedCss = System.Text.RegularExpressions.Regex.Replace(combinedCss, @"\{([\s\S]*?)\}", match =>
588 {
589 string content = match.Groups[1].Value;
590 content = System.Text.RegularExpressions.Regex.Replace(content, @"\s+", " "); // Collapse multiple spaces to a single space
591 return "{" + content.Trim() + "}";
592 });
593 combinedCss = System.Text.RegularExpressions.Regex.Replace(combinedCss, @"\t|\n|\r", "");
594 combinedCss = combinedCss.Replace("\00a0", " "); //Re-insert spaces for content text
595 Dynamicweb.Core.Helpers.TextFileHelper.WriteTextFile(combinedCss, cssPathCombined, false);
596 }
597
598 <div class="container my-5 theme light">
599 <div class="grid gap-3 mb-5 pb-3 text-center border-bottom">
600 <div class="g-col-12">
601 <h1 class="h1">@Translate("Branding") </h1>
602 <div class="lead">@Translate("Define how you appear")</div>
603 </div>
604 </div>
605
606 <div class="grid g-4">
607 <div class="g-col-12">
608 <div class="lead text-muted text-uppercase mb-3 pb-2 border-bottom">@Translate("Header font")</div>
609 </div>
610 <div class="g-col-12 g-col-lg-7">
611 <div class="fs-7 text-muted">H1</div>
612 <h1 class="h1 mb-3">@Translate("The quick, brown fox jumps over the lazy dog")</h1>
613 <div class="fs-7 text-muted">H2</div>
614 <h2 class="h2 mb-3">@Translate("The quick, brown fox jumps over the lazy dog")</h2>
615 <div class="fs-7 text-muted">H3</div>
616 <h3 class="h3 mb-3">@Translate("The quick, brown fox jumps over the lazy dog")</h3>
617 <div class="fs-7 text-muted">H4</div>
618 <h4 class="h4 mb-3">@Translate("The quick, brown fox jumps over the lazy dog")</h4>
619 <div class="fs-7 text-muted">H5</div>
620 <h5 class="h5 mb-3">@Translate("The quick, brown fox jumps over the lazy dog")</h5>
621 <div class="fs-7 text-muted">H6</div>
622 <h6 class="h6 mb-3">@Translate("The quick, brown fox jumps over the lazy dog")</h6>
623 </div>
624 <div class="g-col-12 g-col-lg-5">
625 <div class="grid fs-7">
626 <div class="g-col-12 g-col-lg-6">
627 <table class="table table-borderless table-sm w-100">
628 <tr>
629 <td colspan="2" class="fw-bold">@Translate("Parameters")</td>
630 </tr>
631 <tr>
632 <td>@Translate("Font family")</td>
633 <td><a role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@headerFontFamily');">@headerFontFamily</a></td>
634 </tr>
635 <tr>
636 <td>@Translate("Font weight")</td>
637 <td><a role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@headerFontWeight');">@headerFontWeight</a></td>
638 </tr>
639 <tr>
640 <td>@Translate("Font style")</td>
641 <td><a role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@headerFontStyle');">@headerFontStyle</a></td>
642 </tr>
643 <tr>
644 <td>@Translate("Casing")</td>
645 <td><a role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@headerCasing');">@headerCasing</a></td>
646 </tr>
647 <tr>
648 <td>@Translate("Line height")</td>
649 <td><a role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@headerLineHeight');">@headerLineHeight</a></td>
650 </tr>
651 <tr>
652 <td>@Translate("Letter spacing")</td>
653 <td><a role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@headerLetterSpacing');">@headerLetterSpacing</a></td>
654 </tr>
655 </table>
656 </div>
657 <div class="g-col-12 g-col-lg-6">
658 <table class="table table-borderless table-sm w-100">
659 <tr>
660 <td class="fw-bold">@Translate("Implementation")</td>
661 </tr>
662 <tr>
663 <td>
664 <div class="mb-2">@Translate("Simply use these css classes"):</div>
665 <div>.h1, .h2, .h3, .h4, .h5, .h6</div>
666 </td>
667 </tr>
668 </table>
669 </div>
670 </div>
671 </div>
672 <div class="g-col-12">
673 <div class="lead text-muted text-uppercase my-3 pb-2 border-bottom">@Translate("Display font")</div>
674 </div>
675 <div class="g-col-12 g-col-lg-7">
676 <div class="fs-7 text-muted">Display 1</div>
677 <h1 class="display-1 mb-4">@Translate("The quick, brown fox jumps over the lazy dog")</h1>
678 <div class="fs-7 text-muted">Display 2</div>
679 <h2 class="display-2 mb-4">@Translate("The quick, brown fox jumps over the lazy dog")</h2>
680 <div class="fs-7 text-muted">Display 3</div>
681 <h3 class="display-3 mb-4">@Translate("The quick, brown fox jumps over the lazy dog")</h3>
682 <div class="fs-7 text-muted">Display 4</div>
683 <h4 class="display-4 mb-4">@Translate("The quick, brown fox jumps over the lazy dog")</h4>
684 <div class="fs-7 text-muted">Display 5</div>
685 <h5 class="display-5 mb-4">@Translate("The quick, brown fox jumps over the lazy dog")</h5>
686 <div class="fs-7 text-muted">Display 6</div>
687 <h6 class="display-6 mb-4">@Translate("The quick, brown fox jumps over the lazy dog")</h6>
688 </div>
689 <div class="g-col-12 g-col-lg-5">
690 <div class="grid fs-7">
691 <div class="g-col-12 g-col-lg-6">
692 <table class="table table-borderless table-sm w-100">
693 <tr>
694 <td colspan="2" class="fw-bold">@Translate("Parameters")</td>
695 </tr>
696 <tr>
697 <td>@Translate("Font family")</td>
698 <td><a role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@displayFontFamily');">@displayFontFamily</a></td>
699 </tr>
700 <tr>
701 <td>@Translate("Font weight")</td>
702 <td><a role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@displayFontWeight');">@displayFontWeight</a></td>
703 </tr>
704 <tr>
705 <td>@Translate("Font style")</td>
706 <td><a role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@displayFontStyle');">@displayFontStyle</a></td>
707 </tr>
708 <tr>
709 <td>@Translate("Casing")</td>
710 <td><a role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@displayCasing');">@displayCasing</a></td>
711 </tr>
712 <tr>
713 <td>@Translate("Line height")</td>
714 <td><a role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@displayLineHeight');">@displayLineHeight</a></td>
715 </tr>
716 <tr>
717 <td>@Translate("Letter spacing")</td>
718 <td><a role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@displayLetterSpacing');">@displayLetterSpacing</a></td>
719 </tr>
720 </table>
721 </div>
722 <div class="g-col-12 g-col-lg-6">
723 <table class="table table-borderless table-sm w-100">
724 <tr>
725 <td class="fw-bold">@Translate("Implementation")</td>
726 </tr>
727 <tr>
728 <td>
729 <div class="mb-2">@Translate("Simply use these css classes"):</div>
730 <div>.display-1, .display-2, .display-3, .display-4, .display-5, .display-6</div>
731 </td>
732 </tr>
733 </table>
734 </div>
735 </div>
736 </div>
737 <div class="g-col-12">
738 <div class="lead text-muted text-uppercase mt-3 pb-2 border-bottom">@Translate("Body font")</div>
739 </div>
740 <div class="g-col-12 g-col-lg-7">
741 <p class="mb-3">@Translate("The quick, brown fox jumps over the lazy dog")</p>
742 </div>
743 <div class="g-col-12 g-col-lg-5">
744 <div class="grid fs-7">
745 <div class="g-col-12 g-col-lg-6">
746 <table class="table table-borderless table-sm w-100">
747 <tr>
748 <td colspan="2" class="fw-bold">@Translate("Parameters")</td>
749 </tr>
750 <tr>
751 <td>@Translate("Font family")</td>
752 <td><a role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@bodyFontFamily');">@bodyFontFamily</a></td>
753 </tr>
754 <tr>
755 <td>@Translate("Font weight")</td>
756 <td><a role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@bodyFontWeight');">@bodyFontWeight</a></td>
757 </tr>
758 <tr>
759 <td>@Translate("Font style")</td>
760 <td><a role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@bodyFontStyle');">@bodyFontStyle</a></td>
761 </tr>
762 <tr>
763 <td>@Translate("Line height")</td>
764 <td><a role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@bodyLineHeight');">@bodyLineHeight</a></td>
765 </tr>
766 <tr>
767 <td>@Translate("Letter spacing")</td>
768 <td><a role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@bodyLetterSpacing');">@bodyLetterSpacing</a></td>
769 </tr>
770 </table>
771 </div>
772 <div class="g-col-12 g-col-lg-6">
773 <table class="table table-borderless table-sm w-100">
774 <tr>
775 <td class="fw-bold">@Translate("Implementation")</td>
776 </tr>
777 <tr>
778 <td>
779 @Translate("Works on all text that is not styled with a heading or display class")
780 </td>
781 </tr>
782 </table>
783 </div>
784 </div>
785 </div>
786 <div class="g-col-12">
787 <div class="lead text-muted text-uppercase mt-3 pb-2 border-bottom">@Translate("Primary button")</div>
788 </div>
789 <div class="g-col-12 g-col-lg-7">
790 <button class="btn btn-primary btn-sm">@Translate("Small")</button>
791 <button class="btn btn-primary">@Translate("Normal")</button>
792 <button class="btn btn-primary btn-lg">@Translate("Large")</button>
793 </div>
794 <div class="g-col-12 g-col-lg-5">
795 <div class="grid fs-7">
796 <div class="g-col-12 g-col-lg-6">
797 <table class="table table-borderless table-sm w-100">
798 <tr>
799 <td colspan="2" class="fw-bold">@Translate("Parameters")</td>
800 </tr>
801 <tr>
802 <td>@Translate("Font weight")</td>
803 <td><a role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@primaryButtonFontWeight');">@primaryButtonFontWeight</a></td>
804 </tr>
805 <tr>
806 <td>@Translate("Casing")</td>
807 <td><a role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@primaryButtonCasing');">@primaryButtonCasing</a></td>
808 </tr>
809 <tr>
810 <td>@Translate("Shape")</td>
811 <td><a role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@primaryButtonShape');">@primaryButtonShape</a></td>
812 </tr>
813 <tr>
814 <td>@Translate("Padding X")</td>
815 <td><a role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@primaryButtonXpadding');">@(primaryButtonXpadding)rem</a></td>
816 </tr>
817 <tr>
818 <td>@Translate("Padding Y")</td>
819 <td><a role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@primaryButtonYpadding');">@(primaryButtonYpadding)rem</a></td>
820 </tr>
821 </table>
822 </div>
823 <div class="g-col-12 g-col-lg-6">
824 <table class="table table-borderless table-sm w-100">
825 <tr>
826 <td class="fw-bold">@Translate("Implementation")</td>
827 </tr>
828 <tr>
829 <td>
830 @{
831 string implementationPrimary = "<button class=\"btn btn-primary\">" + Translate("Add to cart") + "</button>";
832 }
833 <div class="text-muted">
834 <a role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('btn btn-primary');">
835 @Dynamicweb.Core.Encoders.HtmlEncoder.HtmlEncode(implementationPrimary)
836 </a>
837 </div>
838 </td>
839 </tr>
840 </table>
841 </div>
842 </div>
843 </div>
844 <div class="g-col-12">
845 <div class="lead text-muted text-uppercase mt-3 pb-2 border-bottom">@Translate("Secondary button")</div>
846 </div>
847 <div class="g-col-12 g-col-lg-7">
848 <button class="btn btn-secondary btn-sm">@Translate("Small")</button>
849 <button class="btn btn-secondary">@Translate("Normal")</button>
850 <button class="btn btn-secondary btn-lg">@Translate("Large")</button>
851 </div>
852 <div class="g-col-12 g-col-lg-5">
853 <div class="grid fs-7">
854 <div class="g-col-12 g-col-lg-6">
855 <table class="table table-borderless table-sm w-100">
856 <tr>
857 <td colspan="2" class="fw-bold">@Translate("Parameters")</td>
858 </tr>
859 <tr>
860 <td>@Translate("Font weight")</td>
861 <td><a role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@secondaryButtonFontWeight');">@secondaryButtonFontWeight</a></td>
862 </tr>
863 <tr>
864 <td>@Translate("Casing")</td>
865 <td><a role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@secondaryButtonCasing');">@secondaryButtonCasing</a></td>
866 </tr>
867 <tr>
868 <td>@Translate("Shape")</td>
869 <td><a role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@secondaryButtonShape');">@secondaryButtonShape</a></td>
870 </tr>
871 <tr>
872 <td>@Translate("Padding X")</td>
873 <td><a role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@secondaryButtonXpadding');">@(secondaryButtonXpadding)rem</a></td>
874 </tr>
875 <tr>
876 <td>@Translate("Padding Y")</td>
877 <td><a role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@secondaryButtonYpadding');">@(secondaryButtonYpadding)rem</a></td>
878 </tr>
879 </table>
880 </div>
881 <div class="g-col-12 g-col-lg-6">
882 <table class="table table-borderless table-sm w-100">
883 <tr>
884 <td class="fw-bold">@Translate("Implementation")</td>
885 </tr>
886 <tr>
887 <td>
888 @{
889 string implementationSecondary = "<button class=\"btn btn-secondary\">" + Translate("Read more") + "</button>";
890 }
891 <div class="text-muted">
892 <a role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('btn btn-secondary');">
893 @Dynamicweb.Core.Encoders.HtmlEncoder.HtmlEncode(implementationSecondary)
894 </a>
895 </div>
896 </td>
897 </tr>
898 </table>
899 </div>
900 </div>
901 </div>
902 <div class="g-col-12">
903 <div class="lead text-muted text-uppercase mt-3 pb-2 border-bottom">@Translate("Link button")</div>
904 </div>
905 <div class="g-col-12 g-col-lg-7">
906 <button class="btn btn-link btn-sm">@Translate("Small")</button>
907 <button class="btn btn-link">@Translate("Normal")</button>
908 <button class="btn btn-link btn-lg">@Translate("Large")</button>
909 </div>
910 <div class="g-col-12 g-col-lg-5">
911 <div class="grid fs-7">
912 <div class="g-col-12 g-col-lg-6">
913 <table class="table table-borderless table-sm w-100">
914 <tr>
915 <td colspan="2" class="fw-bold">@Translate("Parameters")</td>
916 </tr>
917 <tr>
918 <td>@Translate("Font weight")</td>
919 <td><a role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@linkButtonFontWeight');">@linkButtonFontWeight</a></td>
920 </tr>
921 <tr>
922 <td>@Translate("Casing")</td>
923 <td><a role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@linkButtonCasing');">@linkButtonCasing</a></td>
924 </tr>
925 </table>
926 </div>
927 <div class="g-col-12 g-col-lg-6">
928 <table class="table table-borderless table-sm w-100">
929 <tr>
930 <td class="fw-bold">@Translate("Implementation")</td>
931 </tr>
932 <tr>
933 <td>
934 @{
935 string implementationLink = "<button class=\"btn btn-link\">" + Translate("Read more") + "</button>";
936 }
937 <div class="text-muted">
938 <a role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('btn btn-link');">
939 @Dynamicweb.Core.Encoders.HtmlEncoder.HtmlEncode(implementationLink)
940 </a>
941 </div>
942 </td>
943 </tr>
944 </table>
945 </div>
946 </div>
947 </div>
948 </div>
949 </div>
950
951 <script>
952 function fallbackCopyTextToClipboard(text) {
953 var textArea = document.createElement("textarea");
954 textArea.value = text;
955
956 // Avoid scrolling to bottom
957 textArea.style.top = "0";
958 textArea.style.left = "0";
959 textArea.style.position = "fixed";
960
961 document.body.appendChild(textArea);
962 textArea.focus();
963 textArea.select();
964
965 try {
966 var successful = document.execCommand('copy');
967 var msg = successful ? 'successful' : 'unsuccessful';
968 console.log('Fallback: Copying text command was ' + msg);
969 } catch (err) {
970 console.error('Fallback: Oops, unable to copy', err);
971 }
972
973 document.body.removeChild(textArea);
974 }
975 function copyTextToClipboard(text) {
976 if (!navigator.clipboard) {
977 fallbackCopyTextToClipboard(text);
978 return;
979 }
980 navigator.clipboard.writeText(text).then(function () {
981 console.log('Async: Copying to clipboard was successful!');
982 }, function (err) {
983 console.error('Async: Could not copy text: ', err);
984 });
985 }
986 </script>
987
988 </main>
989
990 @* Render any offcanvas menu here *@
991 @RenderSnippet("offcanvas")
992 </body>
993
994 </html>
995