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