Themes
Take full control of all the colors
Error executing template "Designs/Swift/Paragraph/Swift_Theme.cshtml" System.Data.SqlClient.SqlException (0x80131904): STRING_AGG aggregation result exceeded the limit of 8000 bytes. Use LOB types to avoid result truncation. at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction) at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose) at System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady) at System.Data.SqlClient.SqlDataReader.TryConsumeMetaData() at System.Data.SqlClient.SqlDataReader.get_MetaData() at System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString, Boolean isInternal, Boolean forDescribeParameterEncryption, Boolean shouldCacheForAlwaysEncrypted) at System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async, Int32 timeout, Task& task, Boolean asyncWrite, Boolean inRetry, SqlDataReader ds, Boolean describeParameterEncryptionRequest) at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, TaskCompletionSource`1 completion, Int32 timeout, Task& task, Boolean& usedCache, Boolean asyncWrite, Boolean inRetry) at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method) at System.Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior behavior, String method) at Dynamicweb.Data.Database.CreateDataReader(IDbCommand command, CommandBehavior behavior) at Dynamicweb.Data.Database.CreateDataReader(String sql, IDbConnection connection, IDbTransaction transaction, CommandBehavior behavior, Int32 commandTimeout, Dictionary`2 sqlParams) at Dynamicweb.Data.Database.CreateDataReader(String sql, IDbConnection connection, IDbTransaction transaction, Int32 commandTimeout, Dictionary`2 sqlParams) at Dynamicweb.Data.Database.CreateDataReader(String sql) at CompiledRazorTemplates.Dynamic.RazorEngine_8e3f1b11eb0041ceb2ca487c2be837e6.UpdateThemeUsages(String sqlQuery, List`1 themeUsages) in E:\Dynamicweb.net\Solutions\Dynamicweb\dw2022.cloud.dynamicweb-cms.com\Files\Templates\Designs\Swift\Paragraph\Swift_Theme.cshtml:line 202 at CompiledRazorTemplates.Dynamic.RazorEngine_8e3f1b11eb0041ceb2ca487c2be837e6.GetAllThemeUsages() in E:\Dynamicweb.net\Solutions\Dynamicweb\dw2022.cloud.dynamicweb-cms.com\Files\Templates\Designs\Swift\Paragraph\Swift_Theme.cshtml:line 184 at CompiledRazorTemplates.Dynamic.RazorEngine_8e3f1b11eb0041ceb2ca487c2be837e6.GetThemeUsageById(String themeId) in E:\Dynamicweb.net\Solutions\Dynamicweb\dw2022.cloud.dynamicweb-cms.com\Files\Templates\Designs\Swift\Paragraph\Swift_Theme.cshtml:line 238 at CompiledRazorTemplates.Dynamic.RazorEngine_8e3f1b11eb0041ceb2ca487c2be837e6.Execute() in E:\Dynamicweb.net\Solutions\Dynamicweb\dw2022.cloud.dynamicweb-cms.com\Files\Templates\Designs\Swift\Paragraph\Swift_Theme.cshtml:line 617 at RazorEngine.Templating.TemplateBase.RazorEngine.Templating.ITemplate.Run(ExecuteContext context, TextWriter reader) at RazorEngine.Templating.RazorEngineService.RunCompile(ITemplateKey key, TextWriter writer, Type modelType, Object model, DynamicViewBag viewBag) at RazorEngine.Templating.RazorEngineServiceExtensions.<>c__DisplayClass16_0.<RunCompile>b__0(TextWriter writer) at RazorEngine.Templating.RazorEngineServiceExtensions.WithWriter(Action`1 withWriter) at Dynamicweb.Rendering.RazorTemplateRenderingProvider.Render(Template template) at Dynamicweb.Rendering.TemplateRenderingService.Render(Template template) at Dynamicweb.Rendering.Template.RenderRazorTemplate() ClientConnectionId:b42d1cec-597c-4eed-bdc2-e0762a41101a Error Number:9829,State:1,Class:16
1 @inherits Dynamicweb.Rendering.ViewModelTemplate<Dynamicweb.Frontend.ParagraphViewModel> 2 @using System.Globalization 3 @using System.Drawing 4 @using Dynamicweb.Core 5 6 @functions{ 7 // Get Hex Color from color picker and translate to RGB color 8 public static string HexToRGB(string hexString) 9 { 10 if (hexString.Equals("none") || string.IsNullOrEmpty(hexString)) 11 return hexString; 12 13 //replace # occurences 14 if (hexString.IndexOf('#') != -1) 15 hexString = hexString.Replace("#", ""); 16 try 17 { 18 int r, g, b = 0; 19 r = int.Parse(hexString.Substring(0, 2), NumberStyles.AllowHexSpecifier); 20 g = int.Parse(hexString.Substring(2, 2), NumberStyles.AllowHexSpecifier); 21 b = int.Parse(hexString.Substring(4, 2), NumberStyles.AllowHexSpecifier); 22 23 string rgb = r + "," + g + "," + b; 24 return rgb; 25 } 26 catch (System.Exception) 27 { 28 return hexString; 29 } 30 } 31 32 public static string GetColorSquare(string hex) 33 { 34 return $"<div class=\"swift-checkered d-inline-block me-1\" style=\"height:1.25rem;width:1.25rem;\"><div style=\"background-color: {hex};border:.0625rem solid grey\" class=\"w-100 h-100\"></div></div>"; 35 } 36 37 public class HSL 38 { 39 public double h { get; set; } 40 public double s { get; set; } 41 public double l { get; set; } 42 } 43 44 //Convert HEX to HSL 45 public static HSL HexToHsl(string hexString) 46 { 47 System.Drawing.Color color = System.Drawing.ColorTranslator.FromHtml(hexString); 48 49 float _R = (color.R / 255f); 50 float _G = (color.G / 255f); 51 float _B = (color.B / 255f); 52 53 float _Min = Math.Min(Math.Min(_R, _G), _B); 54 float _Max = Math.Max(Math.Max(_R, _G), _B); 55 float _Delta = _Max - _Min; 56 57 float S = 0; 58 float L = (float)((_Max + _Min) / 2.0f); 59 60 if (_Delta != 0) 61 { 62 if (L < 0.5f) 63 { 64 S = (float)(_Delta / (_Max + _Min)); 65 } 66 else 67 { 68 S = (float)(_Delta / (2.0f - _Max - _Min)); 69 } 70 } 71 72 HSL hsl = new HSL(); 73 hsl.h = Math.Round(color.GetHue(), 2); 74 hsl.s = Math.Round(S, 2) * 100; 75 hsl.l = Math.Round(L, 2) * 100; 76 77 return hsl; 78 } 79 80 //Find contrast color (white, black) 81 public static Color GetContrastColor(string hexString) 82 { 83 System.Drawing.Color bg = System.Drawing.ColorTranslator.FromHtml(hexString); 84 85 int nThreshold = 105; 86 int bgDelta = Convert.ToInt32((bg.R * 0.299) + (bg.G * 0.587) + 87 (bg.B * 0.114)); 88 89 Color foreColor = (255 - bgDelta < nThreshold) ? Color.Black : Color.White; 90 return foreColor; 91 } 92 93 public string GetColorVariation(string hexString) 94 { 95 var contrast = GetContrastColor(hexString); 96 HSL currentHslColor = HexToHsl(hexString); 97 HSL variantHslColor = currentHslColor; 98 99 if (contrast == Color.Black) 100 { 101 variantHslColor.l = 85; //The background is dark - Color should be light 102 } 103 else 104 { 105 variantHslColor.l = 40; //The background is light - Color should be less light 106 } 107 108 //Color is very light 109 if (currentHslColor.l > 85) 110 { 111 variantHslColor.l = 95; 112 } 113 114 string colorString = variantHslColor.h + ", " + variantHslColor.s + "%, " + variantHslColor.l + "%"; 115 return colorString; 116 } 117 118 private class ThemeDatabaseUsage 119 { 120 public string TableName { get; set; } 121 public string ColumnName { get; set; } 122 } 123 124 private class ThemeUsage 125 { 126 public string Id { get; set; } 127 public List<int> WebsiteUsages { get; set; } = new List<int>(); 128 public List<int> PageUsages { get; set; } = new List<int>(); 129 public List<int> PagePropertyUsages { get; set; } = new List<int>(); 130 public List<int> GridRowUsages { get; set; } = new List<int>(); 131 public List<int> ParagraphUsages { get; set; } = new List<int>(); 132 public int AllUsages { get; set; } = 0; 133 } 134 135 private List<ThemeDatabaseUsage> GetThemeColumnsFromSchema() 136 { 137 string cacheKey = "ThemesFromDatabase"; 138 if (Dynamicweb.Context.Current.Items.Contains(cacheKey)) 139 { 140 return (List<ThemeDatabaseUsage>)Dynamicweb.Context.Current.Items[cacheKey]; 141 } 142 var schema = Dynamicweb.Data.Database.CreateDataReader("SELECT table_name, column_name FROM information_schema.columns WHERE column_name LIKE '%Theme%'"); 143 144 var rawData = new List<ThemeDatabaseUsage>(); 145 while (schema.Read()) { 146 rawData.Add(new ThemeDatabaseUsage {TableName = schema["table_name"].ToString(), ColumnName = schema["column_name"].ToString() }); 147 } 148 Dynamicweb.Context.Current.Items[cacheKey] = rawData; 149 return rawData; 150 } 151 152 private List<ThemeUsage> GetAllThemeUsages() 153 { 154 string cacheKey = "ThemeUsages"; 155 if (Dynamicweb.Context.Current.Items.Contains(cacheKey)) 156 { 157 return (List<ThemeUsage>)Dynamicweb.Context.Current.Items[cacheKey]; 158 } 159 160 var rawData = GetThemeColumnsFromSchema(); 161 var themeUsages = new List<ThemeUsage>(); 162 163 var sqlQuery = ""; 164 foreach (var row in rawData) 165 { 166 if (!string.IsNullOrEmpty(sqlQuery)) { sqlQuery += " UNION ALL "; } 167 sqlQuery += $"SELECT '{row.TableName}' AS TableName, '{row.ColumnName}' AS ColumnName, {row.ColumnName} AS ColumnValue, Id, AreaId, Page.PageId, PageProperties.PageId as 'PagePropertiesId', GridRowId, ParagraphId" + 168 $" FROM [{row.TableName}]" + 169 $" LEFT JOIN Area ON AreaItemType = '{row.TableName.Replace("ItemType_","")}' AND AreaItemId = Id" + 170 $" LEFT JOIN Page ON PageItemType = '{row.TableName.Replace("ItemType_","")}' AND PageItemId = Id" + 171 $" LEFT JOIN Page as PageProperties ON AreaItemTypePageProperty = '{row.TableName.Replace("ItemType_","")}' AND PageProperties.PagePropertyItemId = Id" + 172 $" LEFT JOIN GridRow ON GridRowItemType = '{row.TableName.Replace("ItemType_","")}' AND GridRowItemId = Id" + 173 $" LEFT JOIN Paragraph ON ParagraphItemType = '{row.TableName.Replace("ItemType_","")}' AND ParagraphItemId = Id" + 174 $" WHERE {row.ColumnName} != '' AND {row.ColumnName} IS NOT NULL" + 175 $" AND (AreaId IS NULL OR AreaId = {Pageview.AreaID})" + 176 $" AND (Page.PageId IS NULL OR Page.PageAreaId = {Pageview.AreaID})" + 177 $" AND (PageProperties.PageId IS NULL OR PageProperties.PageAreaId = {Pageview.AreaID})" + 178 $" AND (GridRowId IS NULL OR GridRowPageId IN (SELECT value From string_split(@pageIds, ',')))" + 179 $" AND (ParagraphId IS NULL OR ParagraphPageId IN (SELECT value From string_split(@pageIds, ',')))"; 180 181 var maxMsSqlServerCharLimit = 60000; 182 if (sqlQuery.Length > maxMsSqlServerCharLimit) 183 { 184 UpdateThemeUsages(sqlQuery, themeUsages); 185 sqlQuery = ""; 186 } 187 } 188 189 if (!string.IsNullOrEmpty(sqlQuery)) 190 { 191 UpdateThemeUsages(sqlQuery, themeUsages); 192 } 193 UpdateAllUsages(themeUsages); 194 195 Dynamicweb.Context.Current.Items[cacheKey] = themeUsages; 196 return themeUsages; 197 } 198 199 private void UpdateThemeUsages(string sqlQuery, List<ThemeUsage> themeUsages) 200 { 201 sqlQuery = $"DECLARE @pageIds NVARCHAR(max) = (SELECT STRING_AGG(PageId,',') FROM Page WHERE PageAreaId = {Pageview.AreaID}) " + sqlQuery; 202 var rawData = Dynamicweb.Data.Database.CreateDataReader(sqlQuery); 203 while (rawData.Read()) 204 { 205 var themeId = rawData["ColumnValue"].ToString(); 206 var themeUsageExists = themeUsages.FirstOrDefault(t => t.Id == themeId) != null; 207 if (!themeUsageExists) 208 { 209 themeUsages.Add(new ThemeUsage { Id = themeId }); 210 } 211 212 var themeUsage = themeUsages.FirstOrDefault(t => t.Id == themeId); 213 if (themeUsage == null) continue; 214 215 if (Converter.ToInt32(rawData["AreaId"].ToString()) > 0) { themeUsage.WebsiteUsages.Add(Converter.ToInt32(rawData["AreaId"].ToString())); } 216 if (Converter.ToInt32(rawData["PageId"].ToString()) > 0) { themeUsage.PageUsages.Add(Converter.ToInt32(rawData["PageId"].ToString())); } 217 if (Converter.ToInt32(rawData["PagePropertiesId"].ToString()) > 0) { themeUsage.PagePropertyUsages.Add(Converter.ToInt32(rawData["PagePropertiesId"].ToString())); } 218 if (Converter.ToInt32(rawData["GridRowId"].ToString()) > 0) { themeUsage.GridRowUsages.Add(Converter.ToInt32(rawData["GridRowId"].ToString())); } 219 if (Converter.ToInt32(rawData["ParagraphId"].ToString()) > 0) { themeUsage.ParagraphUsages.Add(Converter.ToInt32(rawData["ParagraphId"].ToString())); } 220 } 221 } 222 223 private void UpdateAllUsages(List<ThemeUsage> themeUsages) 224 { 225 foreach (var themeUsage in themeUsages) 226 { 227 int websiteUsages = themeUsage?.WebsiteUsages.Count ?? 0; 228 int pageUsages = themeUsage?.PageUsages.Count ?? 0; 229 int pagePropertyUsages = themeUsage?.PagePropertyUsages.Count ?? 0; 230 int gridRowUsages = themeUsage?.GridRowUsages.Count ?? 0; 231 int paragraphUsages = themeUsage?.ParagraphUsages.Count ?? 0; 232 themeUsage.AllUsages = websiteUsages + pageUsages + pagePropertyUsages + gridRowUsages + paragraphUsages; 233 } 234 } 235 236 private ThemeUsage GetThemeUsageById(string themeId) 237 { 238 var themeUsages = GetAllThemeUsages(); 239 return themeUsages.FirstOrDefault(t => t.Id == themeId); 240 } 241 242 } 243 244 @{ 245 string themeName = !string.IsNullOrWhiteSpace(Model.Item.GetString("Name")) ? Model.Item.GetString("Name") : "Default"; 246 string themeClassName = !string.IsNullOrWhiteSpace(Model.Item.GetString("CSSClassName")) ? Model.Item.GetString("CSSClassName").Replace(" ", "").Trim().ToLower() : ""; 247 248 //Theme colors 249 string foregroundColor = Model.Item.GetString("ForegroundColor", "currentColor"); 250 string backgroundColor = Model.Item.GetString("BackgroundColor", "transparent"); 251 string accentColor = Model.Item.GetString("accentColor", "currentColor"); 252 string borderColor = Model.Item.GetString("BorderColor", "transparent"); 253 254 //Primary button 255 string buttonPrimaryForegroundColor = Model.Item.GetString("ButtonPrimaryForegroundColor", "currentColor"); 256 string buttonPrimaryBackgroundColor = Model.Item.GetString("ButtonPrimaryBackgroundColor", "transparent"); 257 string buttonPrimaryBorderColor = Model.Item.GetString("ButtonPrimaryBorderColor", "transparent"); 258 259 string buttonPrimaryHoverBackgroundColorAuto = "transparent"; 260 if (buttonPrimaryBackgroundColor != "transparent") 261 { 262 buttonPrimaryHoverBackgroundColorAuto = "hsl(" + GetColorVariation(buttonPrimaryBackgroundColor) + ")"; 263 } 264 string buttonPrimaryHoverForegroundColor = Model.Item.GetString("ButtonPrimaryHoverForegroundColor", buttonPrimaryForegroundColor); 265 string buttonPrimaryHoverBackgroundColor = Model.Item.GetString("ButtonPrimaryHoverBackgroundColor", buttonPrimaryHoverBackgroundColorAuto); 266 string buttonPrimaryHoverBorderColor = Model.Item.GetString("ButtonPrimaryHoverBorderColor", buttonPrimaryBorderColor); 267 268 //Secondary buton 269 string buttonSecondaryForegroundColor = Model.Item.GetString("ButtonSecondaryForegroundColor", "currentColor"); 270 string buttonSecondaryBackgroundColor = Model.Item.GetString("ButtonSecondaryBackgroundColor", "transparent"); 271 string buttonSecondaryBorderColor = Model.Item.GetString("ButtonSecondaryBorderColor", "transparent"); 272 273 string buttonSecondaryHoverBackgroundColorAuto = "transparent"; 274 if (buttonSecondaryBackgroundColor != "transparent") 275 { 276 buttonSecondaryHoverBackgroundColorAuto = "hsl(" + GetColorVariation(buttonSecondaryBackgroundColor) + ")"; 277 } 278 string buttonSecondaryHoverForegroundColor = Model.Item.GetString("ButtonSecondaryHoverForegroundColor", buttonSecondaryForegroundColor); 279 string buttonSecondaryHoverBackgroundColor = Model.Item.GetString("ButtonSecondaryHoverBackgroundColor", buttonSecondaryHoverBackgroundColorAuto); 280 string buttonSecondaryHoverBorderColor = Model.Item.GetString("ButtonSecondaryHoverBorderColor", buttonSecondaryBorderColor); 281 282 //Link buton 283 string buttonLinkColor = Model.Item.GetString("ButtonLinkColor", "currentColor"); 284 string buttonLinkHoverColorAuto = "currentColor"; 285 if (buttonLinkColor != "currentColor") 286 { 287 buttonLinkHoverColorAuto = "hsl(" + GetColorVariation(buttonLinkColor) + ")"; 288 } 289 string buttonLinkHoverColor = Model.Item.GetString("ButtonLinkHoverColor", buttonLinkHoverColorAuto); 290 291 string accessibilityOutlineColor = Model.Item.GetString("OutlineColor") != null ? Model.Item.GetString("OutlineColor") : ""; 292 293 if (!string.IsNullOrEmpty(themeClassName)) 294 { 295 var sb = new System.Text.StringBuilder(); 296 297 sb.AppendLine("." + themeClassName + "{"); 298 if (!string.IsNullOrEmpty(foregroundColor)) 299 { 300 sb.AppendLine($"--swift-foreground-color: {foregroundColor};"); 301 sb.AppendLine($"--swift-foreground-color-rgb: {HexToRGB(foregroundColor)};"); 302 } 303 if (!string.IsNullOrEmpty(backgroundColor)) 304 { 305 sb.AppendLine($"--swift-background-color: {backgroundColor};"); 306 sb.AppendLine($"--swift-background-color-rgb: {HexToRGB(backgroundColor)};"); 307 } 308 if (!string.IsNullOrEmpty(accentColor)) 309 { 310 sb.AppendLine($"--swift-accent-color: {accentColor};"); 311 sb.AppendLine($"--swift-accent-color-rgb: {HexToRGB(accentColor)};"); 312 } 313 if (!string.IsNullOrEmpty(borderColor)) 314 { 315 sb.AppendLine($"--swift-border-color: {borderColor};"); 316 sb.AppendLine($"--swift-border-color-rgb: {HexToRGB(borderColor)};"); 317 } 318 319 if (!string.IsNullOrEmpty(buttonPrimaryBackgroundColor)) 320 { 321 sb.AppendLine($"--swift-button-primary-background-color: {buttonPrimaryBackgroundColor};"); 322 sb.AppendLine($"--swift-button-primary-background-color-rgb: {HexToRGB(buttonPrimaryBackgroundColor)};"); 323 } 324 if (!string.IsNullOrEmpty(buttonPrimaryForegroundColor)) 325 { 326 sb.AppendLine($"--swift-button-primary-foreground-color: {buttonPrimaryForegroundColor};"); 327 sb.AppendLine($"--swift-button-primary-foreground-color-rgb: {HexToRGB(buttonPrimaryForegroundColor)};"); 328 } 329 if (!string.IsNullOrEmpty(buttonPrimaryBorderColor)) 330 { 331 sb.AppendLine($"--swift-button-primary-border-color: {buttonPrimaryBorderColor};"); 332 sb.AppendLine($"--swift-button-primary-border-color-rgb: {HexToRGB(buttonPrimaryBorderColor)};"); 333 } 334 335 if (!string.IsNullOrEmpty(buttonPrimaryHoverBackgroundColor)) 336 { 337 sb.AppendLine($"--swift-button-primary-hover-background-color: {buttonPrimaryHoverBackgroundColor};"); 338 sb.AppendLine($"--swift-button-primary-hover-background-color-rgb: {HexToRGB(buttonPrimaryHoverBackgroundColor)};"); 339 } 340 if (!string.IsNullOrEmpty(buttonPrimaryHoverForegroundColor)) 341 { 342 sb.AppendLine($"--swift-button-primary-hover-foreground-color: {buttonPrimaryHoverForegroundColor};"); 343 sb.AppendLine($"--swift-button-primary-hover-foreground-color-rgb: {HexToRGB(buttonPrimaryHoverForegroundColor)};"); 344 } 345 if (!string.IsNullOrEmpty(buttonPrimaryHoverBorderColor)) 346 { 347 sb.AppendLine($"--swift-button-primary-hover-border-color: {buttonPrimaryHoverBorderColor};"); 348 sb.AppendLine($"--swift-button-primary-hover-border-color-rgb: {HexToRGB(buttonPrimaryHoverBorderColor)};"); 349 } 350 351 if (!string.IsNullOrEmpty(buttonSecondaryBackgroundColor)) 352 { 353 sb.AppendLine($"--swift-button-secondary-background-color: {buttonSecondaryBackgroundColor};"); 354 sb.AppendLine($"--swift-button-secondary-background-color-rgb: {HexToRGB(buttonSecondaryBackgroundColor)};"); 355 } 356 if (!string.IsNullOrEmpty(buttonSecondaryForegroundColor)) 357 { 358 sb.AppendLine($"--swift-button-secondary-foreground-color: {buttonSecondaryForegroundColor};"); 359 sb.AppendLine($"--swift-button-secondary-foreground-color-rgb: {HexToRGB(buttonSecondaryForegroundColor)};"); 360 } 361 if (!string.IsNullOrEmpty(buttonSecondaryBorderColor)) 362 { 363 sb.AppendLine($"--swift-button-secondary-border-color: {buttonSecondaryBorderColor};"); 364 sb.AppendLine($"--swift-button-secondary-border-color-rgb: {HexToRGB(buttonSecondaryBorderColor)};"); 365 } 366 if (!string.IsNullOrEmpty(buttonSecondaryHoverBackgroundColor)) 367 { 368 sb.AppendLine($"--swift-button-secondary-hover-background-color: {buttonSecondaryHoverBackgroundColor};"); 369 sb.AppendLine($"--swift-button-secondary-hover-background-color-rgb: {HexToRGB(buttonSecondaryHoverBackgroundColor)};"); 370 } 371 if (!string.IsNullOrEmpty(buttonSecondaryHoverForegroundColor)) 372 { 373 sb.AppendLine($"--swift-button-secondary-hover-foreground-color: {buttonSecondaryHoverForegroundColor};"); 374 sb.AppendLine($"--swift-button-secondary-hover-foreground-color-rgb: {HexToRGB(buttonSecondaryHoverForegroundColor)};"); 375 } 376 if (!string.IsNullOrEmpty(buttonSecondaryHoverBorderColor)) 377 { 378 sb.AppendLine($"--swift-button-secondary-hover-border-color: {buttonSecondaryHoverBorderColor};"); 379 sb.AppendLine($"--swift-button-secondary-hover-border-color-rgb: {HexToRGB(buttonSecondaryHoverBorderColor)};"); 380 } 381 if (!string.IsNullOrEmpty(buttonLinkColor)) 382 { 383 sb.AppendLine($"--swift-button-link-color: {buttonLinkColor};"); 384 sb.AppendLine($"--swift-button-link-color-rgb: {HexToRGB(buttonLinkColor)};"); 385 } 386 if (!string.IsNullOrEmpty(buttonLinkHoverColor)) 387 { 388 sb.AppendLine($"--swift-button-link-hover-color: {buttonLinkHoverColor};"); 389 sb.AppendLine($"--swift-button-link-hover-color-rgb: {HexToRGB(buttonLinkHoverColor)};"); 390 } 391 if (!string.IsNullOrEmpty(accessibilityOutlineColor)) 392 { 393 sb.AppendLine($"--swift-a11y-outline-color: {accessibilityOutlineColor};"); 394 sb.AppendLine($"--swift-a11y-outline-color-rgb: {HexToRGB(accessibilityOutlineColor)};"); 395 } 396 sb.AppendLine("}"); 397 398 Dynamicweb.Core.Helpers.TextFileHelper.WriteTextFile(sb.ToString() + Environment.NewLine, Dynamicweb.Context.Current.Server.MapPath($"/Files/Templates/Designs/Swift/_parsed/Swift_css/Swift_theme_styles_{Dynamicweb.Content.Services.Pages.GetPage(Model.PageID).AreaId}.tmp"), true); 399 } 400 } 401 402 @if (themeClassName != "") 403 { 404 string iconPath = "/Files/Templates/Designs/Swift/Assets/icons/"; 405 406 <div class="g-col-12 g-col-lg-4"> 407 <div class="swift-checkered p-3"> 408 <div class="theme-option theme @themeClassName p-lg-3"> 409 <div class="mb-2 pb-1 border-bottom d-flex align-items-center"> 410 <span class="icon-3 me-2"> 411 @ReadFile(iconPath + "sun.svg") 412 </span> 413 <h4 class="m-0 p-0">@themeName</h4> 414 </div> 415 <div class="d-flex flex-column gap-1 mb-2"> 416 <p class="mb-0">This is the body text of the theme.</p> 417 <p class="mb-0" style="color: var(--swift-accent-color)">This is the accent color of the theme.</p> 418 </div> 419 <div> 420 <button class="btn btn-primary me-1">Primary</button> 421 <button class="btn btn-secondary">Secondary</button> 422 <button class="btn btn-link">Link</button> 423 </div> 424 </div> 425 </div> 426 </div> 427 <div class="g-col-12 g-col-lg-8 mb-4 mb-lg-0"> 428 <div class="grid fs-7"> 429 <div class="g-col-12 g-col-lg-3"> 430 <table class="table table-borderless table-sm w-100"> 431 <thead> 432 <tr> 433 <th colspan="2" class="fw-bold">@Translate("Base")</th> 434 </tr> 435 </thead> 436 <tr> 437 <td>@Translate("Foreground")</td> 438 <td>@GetColorSquare(foregroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@foregroundColor');">@foregroundColor</a></td> 439 </tr> 440 <tr> 441 <td>@Translate("Background")</td> 442 <td>@GetColorSquare(backgroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@backgroundColor');">@backgroundColor</a></td> 443 </tr> 444 <tr> 445 <td>@Translate("Accent")</td> 446 <td>@GetColorSquare(accentColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@accentColor');">@accentColor</a></td> 447 </tr> 448 <tr> 449 <td>@Translate("Border")</td> 450 <td>@GetColorSquare(borderColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@borderColor');">@borderColor</a></td> 451 </tr> 452 </table> 453 </div> 454 <div class="g-col-12 g-col-lg-3"> 455 <table class="table table-borderless table-sm w-100"> 456 <thead> 457 <tr> 458 <th colspan="2" class="fw-bold">@Translate("Primary button")</th> 459 </tr> 460 </thead> 461 <tr> 462 <td>@Translate("Foreground")</td> 463 <td>@GetColorSquare(buttonPrimaryForegroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonPrimaryForegroundColor');">@buttonPrimaryForegroundColor</a></td> 464 </tr> 465 <tr> 466 <td>@Translate("Background")</td> 467 <td>@GetColorSquare(buttonPrimaryBackgroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonPrimaryBackgroundColor');">@buttonPrimaryBackgroundColor</a></td> 468 </tr> 469 @if (!string.IsNullOrEmpty(buttonPrimaryBorderColor)) 470 { 471 <tr> 472 <td>@Translate("Border")</td> 473 <td>@GetColorSquare(buttonPrimaryBorderColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonPrimaryBorderColor');">@buttonPrimaryBorderColor</a></td> 474 </tr> 475 } 476 <thead> 477 <tr> 478 <th colspan="2" class="fw-bold">@Translate("Primary button hover")</th> 479 </tr> 480 </thead> 481 @if (!string.IsNullOrEmpty(buttonPrimaryHoverForegroundColor)) 482 { 483 <tr> 484 <td>@Translate("Foreground")</td> 485 <td>@GetColorSquare(buttonPrimaryHoverForegroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonPrimaryHoverForegroundColor');">@buttonPrimaryHoverForegroundColor</a></td> 486 </tr> 487 } 488 @if (!string.IsNullOrEmpty(buttonPrimaryHoverBackgroundColor)) 489 { 490 <tr> 491 <td>@Translate("Background")</td> 492 <td>@GetColorSquare(buttonPrimaryHoverBackgroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonPrimaryHoverBackgroundColor');">@buttonPrimaryHoverBackgroundColor</a></td> 493 </tr> 494 } 495 @if (!string.IsNullOrEmpty(buttonPrimaryHoverBorderColor)) 496 { 497 <tr> 498 <td>@Translate("Border")</td> 499 <td>@GetColorSquare(buttonPrimaryHoverBorderColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonPrimaryHoverBorderColor');">@buttonPrimaryHoverBorderColor</a></td> 500 </tr> 501 } 502 </table> 503 </div> 504 <div class="g-col-12 g-col-lg-3"> 505 <table class="table table-borderless table-sm w-100"> 506 <thead> 507 <tr> 508 <th colspan="2" class="fw-bold">@Translate("Secondary button")</th> 509 </tr> 510 </thead> 511 <tr> 512 <td>@Translate("Foreground")</td> 513 <td>@GetColorSquare(buttonSecondaryForegroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonSecondaryForegroundColor');">@buttonSecondaryForegroundColor</a></td> 514 </tr> 515 <tr> 516 <td>@Translate("Background")</td> 517 <td>@GetColorSquare(buttonSecondaryBackgroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonSecondaryBackgroundColor');">@buttonSecondaryBackgroundColor</a></td> 518 </tr> 519 @if (!string.IsNullOrEmpty(buttonSecondaryBorderColor)) 520 { 521 <tr> 522 <td>@Translate("Border")</td> 523 <td>@GetColorSquare(buttonSecondaryBorderColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonSecondaryBorderColor');">@buttonSecondaryBorderColor</a></td> 524 </tr> 525 } 526 <thead> 527 <tr> 528 <th colspan="2" class="fw-bold">@Translate("Secondary button hover")</th> 529 </tr> 530 </thead> 531 @if (!string.IsNullOrEmpty(buttonSecondaryHoverForegroundColor)) 532 { 533 <tr> 534 <td>@Translate("Foreground")</td> 535 <td>@GetColorSquare(buttonSecondaryHoverForegroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonSecondaryHoverForegroundColor');">@buttonSecondaryHoverForegroundColor</a></td> 536 </tr> 537 } 538 @if (!string.IsNullOrEmpty(buttonSecondaryHoverBackgroundColor)) 539 { 540 <tr> 541 <td>@Translate("Background")</td> 542 <td>@GetColorSquare(buttonSecondaryHoverBackgroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonSecondaryHoverBackgroundColor');">@buttonSecondaryHoverBackgroundColor</a></td> 543 </tr> 544 } 545 @if (!string.IsNullOrEmpty(buttonSecondaryHoverBorderColor)) 546 { 547 <tr> 548 <td>@Translate("Border")</td> 549 <td>@GetColorSquare(buttonSecondaryHoverBorderColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonSecondaryHoverBorderColor');">@buttonSecondaryHoverBorderColor</a></td> 550 </tr> 551 } 552 @if (!string.IsNullOrEmpty(accessibilityOutlineColor)) 553 { 554 <tr> 555 <td>@Translate("Focus outline")</td> 556 <td>@GetColorSquare(accessibilityOutlineColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@accessibilityOutlineColor');">@accessibilityOutlineColor</a></td> 557 </tr> 558 } 559 </table> 560 </div> 561 <div class="g-col-12 g-col-lg-3"> 562 <table class="table table-borderless table-sm w-100"> 563 <thead> 564 <tr> 565 <th colspan="2" class="fw-bold">@Translate("Link button")</th> 566 </tr> 567 </thead> 568 <tr> 569 <td>@Translate("Link color")</td> 570 <td>@GetColorSquare(buttonLinkColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonLinkColor');">@buttonLinkColor</a></td> 571 </tr> 572 <thead> 573 <tr> 574 <th colspan="2" class="fw-bold">@Translate("Link button hover")</th> 575 </tr> 576 </thead> 577 @if (!string.IsNullOrEmpty(buttonLinkHoverColor)) 578 { 579 <tr> 580 <td>@Translate("Link hover color")</td> 581 <td>@GetColorSquare(buttonLinkHoverColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonLinkHoverColor');">@buttonLinkHoverColor</a></td> 582 </tr> 583 } 584 585 @if (!string.IsNullOrEmpty(accessibilityOutlineColor)) 586 { 587 <tr> 588 <td>@Translate("Focus outline")</td> 589 <td>@GetColorSquare(accessibilityOutlineColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@accessibilityOutlineColor');">@accessibilityOutlineColor</a></td> 590 </tr> 591 } 592 </table> 593 </div> 594 <div class="g-col-12 g-col-lg-3"> 595 <table class="table table-borderless table-sm w-100"> 596 <tr> 597 <td class="fw-bold">@Translate("Implementation")</td> 598 </tr> 599 <tr> 600 <td> 601 @{ 602 string implementation = $"<div class=\"theme {themeClassName}\"></div>"; 603 } 604 <div class="text-muted"> 605 <code class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@themeClassName');"> 606 @Dynamicweb.Core.Encoders.HtmlEncoder.HtmlEncode(implementation) 607 </code> 608 </div> 609 </td> 610 </tr> 611 </table> 612 </div> 613 @{ 614 bool hasUsageData = Converter.ToBoolean(Dynamicweb.Context.Current.Request["auditUsages"]); 615 if (hasUsageData) 616 { 617 var themeUsage = GetThemeUsageById(themeClassName); 618 int allUsages = themeUsage?.AllUsages ?? 0; 619 string buttonAttributes = allUsages > 0 ? $"data-bs-toggle=\"modal\" data-bs-target=\"#themeUsage_{Model.ID}\"" : string.Empty; 620 string badgeStyle = allUsages > 0 ? "bg-success" : "bg-danger"; 621 622 <div class="g-col-12 g-col-lg-9 position-relative"> 623 <button type="button" class="btn btn-primary btn-sm position-absolute end-0" @buttonAttributes> 624 Usages 625 <span class="position-absolute top-0 start-100 translate-middle badge rounded-pill text-white @badgeStyle">@allUsages</span> 626 </button> 627 628 @if (allUsages > 0) 629 { 630 int websiteUsages = themeUsage?.WebsiteUsages.Count ?? 0; 631 int pageUsages = themeUsage?.PageUsages.Count ?? 0; 632 int pagePropertyUsages = themeUsage?.PagePropertyUsages.Count ?? 0; 633 int gridRowUsages = themeUsage?.GridRowUsages.Count ?? 0; 634 int paragraphUsages = themeUsage?.ParagraphUsages.Count ?? 0; 635 636 <!-- Modal --> 637 <div class="modal fade" id="themeUsage_@(Model.ID)" tabindex="-1" aria-labelledby="usagesModelLabel" aria-hidden="true"> 638 <div class="modal-dialog modal-xl modal-dialog-centered modal-dialog-scrollable"> 639 <div class="modal-content"> 640 <div class="modal-header"> 641 <h5 class="modal-title" id="usagesModelLabel">@allUsages Usages of '@(themeName)' (@(themeClassName))</h5> 642 <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> 643 </div> 644 <div class="modal-body"> 645 <div class="accordion" id="accordionWrapper"> 646 @if(websiteUsages > 0) 647 { 648 <div class="accordion-item"> 649 <h2 class="accordion-header" id="headingWebsites"> 650 <button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#collapseWebsites" aria-expanded="true" aria-controls="collapseWebsites"> 651 <span class="pe-2">Websites</span><span class="badge rounded-pill bg-secondary text-light">@websiteUsages</span> 652 </button> 653 </h2> 654 <div id="collapseWebsites" class="accordion-collapse collapse show" aria-labelledby="headingWebsites" data-bs-parent="#accordionWrapper"> 655 <div class="accordion-body"> 656 <ul> 657 @foreach (var usage in themeUsage.WebsiteUsages) 658 { 659 var website = Dynamicweb.Content.Services.Areas.GetArea(usage); 660 <li><span class="fw-bold">@website.Name</span>@($" (ID: {usage})")</li> 661 } 662 </ul> 663 </div> 664 </div> 665 </div> 666 } 667 @if (pageUsages > 0) 668 { 669 var pages = Dynamicweb.Content.Services.Pages.GetPages(themeUsage.PageUsages.ToArray()); 670 671 <div class="accordion-item"> 672 <h2 class="accordion-header" id="headingPages"> 673 <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapsePages" aria-expanded="false" aria-controls="collapsePages"> 674 <span class="pe-2">Pages</span><span class="badge rounded-pill bg-secondary text-light">@pageUsages</span> 675 </button> 676 </h2> 677 <div id="collapsePages" class="accordion-collapse collapse" aria-labelledby="headingPages" data-bs-parent="#accordionWrapper"> 678 <div class="accordion-body"> 679 <ul> 680 @foreach (var usage in themeUsage.PageUsages) 681 { 682 <li><span class="fw-bold">@pages.FirstOrDefault(p => p.ID == usage).GetDisplayName()</span>@($" (ID: {usage})")</li> 683 } 684 </ul> 685 </div> 686 </div> 687 </div> 688 } 689 @if (pagePropertyUsages > 0) 690 { 691 var pages = Dynamicweb.Content.Services.Pages.GetPages(themeUsage.PageUsages.ToArray()); 692 693 <div class="accordion-item"> 694 <h2 class="accordion-header" id="headingPageProperties"> 695 <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapsePageProperties" aria-expanded="false" aria-controls="collapsePageProperties"> 696 <span class="pe-2">Page Properties</span><span class="badge rounded-pill bg-secondary text-light">@pagePropertyUsages</span> 697 </button> 698 </h2> 699 <div id="collapsePageProperties" class="accordion-collapse collapse" aria-labelledby="headingPageProperties" data-bs-parent="#accordionWrapper"> 700 <div class="accordion-body"> 701 <ul> 702 @foreach (var usage in themeUsage.PagePropertyUsages) 703 { 704 <li><span class="fw-bold">@pages.FirstOrDefault(p => p.ID == usage).GetDisplayName()</span>@($" (ID: {usage})")</li> 705 } 706 </ul> 707 </div> 708 </div> 709 </div> 710 } 711 @if (gridRowUsages > 0) 712 { 713 var rows = Dynamicweb.Content.Services.Grids.GetGridRows().Where(r => themeUsage.GridRowUsages.Contains(r.ID)).ToList(); 714 715 <div class="accordion-item"> 716 <h2 class="accordion-header" id="headingRows"> 717 <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseRows" aria-expanded="false" aria-controls="collapseRows"> 718 <span class="pe-2">Rows</span><span class="badge rounded-pill bg-secondary text-light">@gridRowUsages</span> 719 </button> 720 </h2> 721 <div id="collapseRows" class="accordion-collapse collapse" aria-labelledby="headingRows" data-bs-parent="#accordionWrapper"> 722 <div class="accordion-body"> 723 <ul> 724 @foreach (var usage in themeUsage.GridRowUsages) 725 { 726 var row = rows.FirstOrDefault(r => r.ID == usage); 727 var page = Dynamicweb.Content.Services.Pages.GetPage(row.PageId); 728 <li>Page: <span class="fw-bold">@(page.GetDisplayName())</span>@($"( ID: {page.ID}) - Row: ")<span class="fw-bold">@(row.DefinitionId)</span>@($" (ID: {usage})")</li> 729 } 730 </ul> 731 </div> 732 </div> 733 </div> 734 } 735 @if (paragraphUsages > 0) 736 { 737 var paragraphs = Dynamicweb.Content.Services.Paragraphs.GetParagraphs().Where(p => themeUsage.ParagraphUsages.Contains(p.ID)).ToList(); 738 739 <div class="accordion-item"> 740 <h2 class="accordion-header" id="headingParagraphs"> 741 <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseParagraphs" aria-expanded="false" aria-controls="collapseParagraphs"> 742 <span class="pe-2">Paragraphs</span><span class="badge rounded-pill bg-secondary text-light">@paragraphUsages</span> 743 </button> 744 </h2> 745 <div id="collapseParagraphs" class="accordion-collapse collapse" aria-labelledby="headingParagraphs" data-bs-parent="#accordionWrapper"> 746 <div class="accordion-body"> 747 <ul> 748 @foreach (var usage in themeUsage.ParagraphUsages) 749 { 750 var paragraph = paragraphs.FirstOrDefault(p => p.ID == usage); 751 var page = Dynamicweb.Content.Services.Pages.GetPage(paragraph.PageID); 752 <li>Page: <span class="fw-bold">@(page.GetDisplayName())</span>@($"( ID: {page.ID}) - Paragraph: ")<span class="fw-bold">@paragraph.Header</span>@($" (ID: {usage})")</li> 753 } 754 </ul> 755 </div> 756 </div> 757 </div> 758 } 759 </div> 760 </div> 761 </div> 762 </div> 763 </div> 764 } 765 </div> 766 } 767 } 768 </div> 769 </div> 770 } 771 <div class="g-col-12"> 772 <hr /> 773 </div> 774
Error executing template "Designs/Swift/Paragraph/Swift_Theme.cshtml" System.Data.SqlClient.SqlException (0x80131904): STRING_AGG aggregation result exceeded the limit of 8000 bytes. Use LOB types to avoid result truncation. at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction) at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose) at System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady) at System.Data.SqlClient.SqlDataReader.TryConsumeMetaData() at System.Data.SqlClient.SqlDataReader.get_MetaData() at System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString, Boolean isInternal, Boolean forDescribeParameterEncryption, Boolean shouldCacheForAlwaysEncrypted) at System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async, Int32 timeout, Task& task, Boolean asyncWrite, Boolean inRetry, SqlDataReader ds, Boolean describeParameterEncryptionRequest) at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, TaskCompletionSource`1 completion, Int32 timeout, Task& task, Boolean& usedCache, Boolean asyncWrite, Boolean inRetry) at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method) at System.Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior behavior, String method) at Dynamicweb.Data.Database.CreateDataReader(IDbCommand command, CommandBehavior behavior) at Dynamicweb.Data.Database.CreateDataReader(String sql, IDbConnection connection, IDbTransaction transaction, CommandBehavior behavior, Int32 commandTimeout, Dictionary`2 sqlParams) at Dynamicweb.Data.Database.CreateDataReader(String sql, IDbConnection connection, IDbTransaction transaction, Int32 commandTimeout, Dictionary`2 sqlParams) at Dynamicweb.Data.Database.CreateDataReader(String sql) at CompiledRazorTemplates.Dynamic.RazorEngine_8e3f1b11eb0041ceb2ca487c2be837e6.UpdateThemeUsages(String sqlQuery, List`1 themeUsages) in E:\Dynamicweb.net\Solutions\Dynamicweb\dw2022.cloud.dynamicweb-cms.com\Files\Templates\Designs\Swift\Paragraph\Swift_Theme.cshtml:line 202 at CompiledRazorTemplates.Dynamic.RazorEngine_8e3f1b11eb0041ceb2ca487c2be837e6.GetAllThemeUsages() in E:\Dynamicweb.net\Solutions\Dynamicweb\dw2022.cloud.dynamicweb-cms.com\Files\Templates\Designs\Swift\Paragraph\Swift_Theme.cshtml:line 184 at CompiledRazorTemplates.Dynamic.RazorEngine_8e3f1b11eb0041ceb2ca487c2be837e6.GetThemeUsageById(String themeId) in E:\Dynamicweb.net\Solutions\Dynamicweb\dw2022.cloud.dynamicweb-cms.com\Files\Templates\Designs\Swift\Paragraph\Swift_Theme.cshtml:line 238 at CompiledRazorTemplates.Dynamic.RazorEngine_8e3f1b11eb0041ceb2ca487c2be837e6.Execute() in E:\Dynamicweb.net\Solutions\Dynamicweb\dw2022.cloud.dynamicweb-cms.com\Files\Templates\Designs\Swift\Paragraph\Swift_Theme.cshtml:line 617 at RazorEngine.Templating.TemplateBase.RazorEngine.Templating.ITemplate.Run(ExecuteContext context, TextWriter reader) at RazorEngine.Templating.RazorEngineService.RunCompile(ITemplateKey key, TextWriter writer, Type modelType, Object model, DynamicViewBag viewBag) at RazorEngine.Templating.RazorEngineServiceExtensions.<>c__DisplayClass16_0.<RunCompile>b__0(TextWriter writer) at RazorEngine.Templating.RazorEngineServiceExtensions.WithWriter(Action`1 withWriter) at Dynamicweb.Rendering.RazorTemplateRenderingProvider.Render(Template template) at Dynamicweb.Rendering.TemplateRenderingService.Render(Template template) at Dynamicweb.Rendering.Template.RenderRazorTemplate() ClientConnectionId:b42d1cec-597c-4eed-bdc2-e0762a41101a Error Number:9829,State:1,Class:16
1 @inherits Dynamicweb.Rendering.ViewModelTemplate<Dynamicweb.Frontend.ParagraphViewModel> 2 @using System.Globalization 3 @using System.Drawing 4 @using Dynamicweb.Core 5 6 @functions{ 7 // Get Hex Color from color picker and translate to RGB color 8 public static string HexToRGB(string hexString) 9 { 10 if (hexString.Equals("none") || string.IsNullOrEmpty(hexString)) 11 return hexString; 12 13 //replace # occurences 14 if (hexString.IndexOf('#') != -1) 15 hexString = hexString.Replace("#", ""); 16 try 17 { 18 int r, g, b = 0; 19 r = int.Parse(hexString.Substring(0, 2), NumberStyles.AllowHexSpecifier); 20 g = int.Parse(hexString.Substring(2, 2), NumberStyles.AllowHexSpecifier); 21 b = int.Parse(hexString.Substring(4, 2), NumberStyles.AllowHexSpecifier); 22 23 string rgb = r + "," + g + "," + b; 24 return rgb; 25 } 26 catch (System.Exception) 27 { 28 return hexString; 29 } 30 } 31 32 public static string GetColorSquare(string hex) 33 { 34 return $"<div class=\"swift-checkered d-inline-block me-1\" style=\"height:1.25rem;width:1.25rem;\"><div style=\"background-color: {hex};border:.0625rem solid grey\" class=\"w-100 h-100\"></div></div>"; 35 } 36 37 public class HSL 38 { 39 public double h { get; set; } 40 public double s { get; set; } 41 public double l { get; set; } 42 } 43 44 //Convert HEX to HSL 45 public static HSL HexToHsl(string hexString) 46 { 47 System.Drawing.Color color = System.Drawing.ColorTranslator.FromHtml(hexString); 48 49 float _R = (color.R / 255f); 50 float _G = (color.G / 255f); 51 float _B = (color.B / 255f); 52 53 float _Min = Math.Min(Math.Min(_R, _G), _B); 54 float _Max = Math.Max(Math.Max(_R, _G), _B); 55 float _Delta = _Max - _Min; 56 57 float S = 0; 58 float L = (float)((_Max + _Min) / 2.0f); 59 60 if (_Delta != 0) 61 { 62 if (L < 0.5f) 63 { 64 S = (float)(_Delta / (_Max + _Min)); 65 } 66 else 67 { 68 S = (float)(_Delta / (2.0f - _Max - _Min)); 69 } 70 } 71 72 HSL hsl = new HSL(); 73 hsl.h = Math.Round(color.GetHue(), 2); 74 hsl.s = Math.Round(S, 2) * 100; 75 hsl.l = Math.Round(L, 2) * 100; 76 77 return hsl; 78 } 79 80 //Find contrast color (white, black) 81 public static Color GetContrastColor(string hexString) 82 { 83 System.Drawing.Color bg = System.Drawing.ColorTranslator.FromHtml(hexString); 84 85 int nThreshold = 105; 86 int bgDelta = Convert.ToInt32((bg.R * 0.299) + (bg.G * 0.587) + 87 (bg.B * 0.114)); 88 89 Color foreColor = (255 - bgDelta < nThreshold) ? Color.Black : Color.White; 90 return foreColor; 91 } 92 93 public string GetColorVariation(string hexString) 94 { 95 var contrast = GetContrastColor(hexString); 96 HSL currentHslColor = HexToHsl(hexString); 97 HSL variantHslColor = currentHslColor; 98 99 if (contrast == Color.Black) 100 { 101 variantHslColor.l = 85; //The background is dark - Color should be light 102 } 103 else 104 { 105 variantHslColor.l = 40; //The background is light - Color should be less light 106 } 107 108 //Color is very light 109 if (currentHslColor.l > 85) 110 { 111 variantHslColor.l = 95; 112 } 113 114 string colorString = variantHslColor.h + ", " + variantHslColor.s + "%, " + variantHslColor.l + "%"; 115 return colorString; 116 } 117 118 private class ThemeDatabaseUsage 119 { 120 public string TableName { get; set; } 121 public string ColumnName { get; set; } 122 } 123 124 private class ThemeUsage 125 { 126 public string Id { get; set; } 127 public List<int> WebsiteUsages { get; set; } = new List<int>(); 128 public List<int> PageUsages { get; set; } = new List<int>(); 129 public List<int> PagePropertyUsages { get; set; } = new List<int>(); 130 public List<int> GridRowUsages { get; set; } = new List<int>(); 131 public List<int> ParagraphUsages { get; set; } = new List<int>(); 132 public int AllUsages { get; set; } = 0; 133 } 134 135 private List<ThemeDatabaseUsage> GetThemeColumnsFromSchema() 136 { 137 string cacheKey = "ThemesFromDatabase"; 138 if (Dynamicweb.Context.Current.Items.Contains(cacheKey)) 139 { 140 return (List<ThemeDatabaseUsage>)Dynamicweb.Context.Current.Items[cacheKey]; 141 } 142 var schema = Dynamicweb.Data.Database.CreateDataReader("SELECT table_name, column_name FROM information_schema.columns WHERE column_name LIKE '%Theme%'"); 143 144 var rawData = new List<ThemeDatabaseUsage>(); 145 while (schema.Read()) { 146 rawData.Add(new ThemeDatabaseUsage {TableName = schema["table_name"].ToString(), ColumnName = schema["column_name"].ToString() }); 147 } 148 Dynamicweb.Context.Current.Items[cacheKey] = rawData; 149 return rawData; 150 } 151 152 private List<ThemeUsage> GetAllThemeUsages() 153 { 154 string cacheKey = "ThemeUsages"; 155 if (Dynamicweb.Context.Current.Items.Contains(cacheKey)) 156 { 157 return (List<ThemeUsage>)Dynamicweb.Context.Current.Items[cacheKey]; 158 } 159 160 var rawData = GetThemeColumnsFromSchema(); 161 var themeUsages = new List<ThemeUsage>(); 162 163 var sqlQuery = ""; 164 foreach (var row in rawData) 165 { 166 if (!string.IsNullOrEmpty(sqlQuery)) { sqlQuery += " UNION ALL "; } 167 sqlQuery += $"SELECT '{row.TableName}' AS TableName, '{row.ColumnName}' AS ColumnName, {row.ColumnName} AS ColumnValue, Id, AreaId, Page.PageId, PageProperties.PageId as 'PagePropertiesId', GridRowId, ParagraphId" + 168 $" FROM [{row.TableName}]" + 169 $" LEFT JOIN Area ON AreaItemType = '{row.TableName.Replace("ItemType_","")}' AND AreaItemId = Id" + 170 $" LEFT JOIN Page ON PageItemType = '{row.TableName.Replace("ItemType_","")}' AND PageItemId = Id" + 171 $" LEFT JOIN Page as PageProperties ON AreaItemTypePageProperty = '{row.TableName.Replace("ItemType_","")}' AND PageProperties.PagePropertyItemId = Id" + 172 $" LEFT JOIN GridRow ON GridRowItemType = '{row.TableName.Replace("ItemType_","")}' AND GridRowItemId = Id" + 173 $" LEFT JOIN Paragraph ON ParagraphItemType = '{row.TableName.Replace("ItemType_","")}' AND ParagraphItemId = Id" + 174 $" WHERE {row.ColumnName} != '' AND {row.ColumnName} IS NOT NULL" + 175 $" AND (AreaId IS NULL OR AreaId = {Pageview.AreaID})" + 176 $" AND (Page.PageId IS NULL OR Page.PageAreaId = {Pageview.AreaID})" + 177 $" AND (PageProperties.PageId IS NULL OR PageProperties.PageAreaId = {Pageview.AreaID})" + 178 $" AND (GridRowId IS NULL OR GridRowPageId IN (SELECT value From string_split(@pageIds, ',')))" + 179 $" AND (ParagraphId IS NULL OR ParagraphPageId IN (SELECT value From string_split(@pageIds, ',')))"; 180 181 var maxMsSqlServerCharLimit = 60000; 182 if (sqlQuery.Length > maxMsSqlServerCharLimit) 183 { 184 UpdateThemeUsages(sqlQuery, themeUsages); 185 sqlQuery = ""; 186 } 187 } 188 189 if (!string.IsNullOrEmpty(sqlQuery)) 190 { 191 UpdateThemeUsages(sqlQuery, themeUsages); 192 } 193 UpdateAllUsages(themeUsages); 194 195 Dynamicweb.Context.Current.Items[cacheKey] = themeUsages; 196 return themeUsages; 197 } 198 199 private void UpdateThemeUsages(string sqlQuery, List<ThemeUsage> themeUsages) 200 { 201 sqlQuery = $"DECLARE @pageIds NVARCHAR(max) = (SELECT STRING_AGG(PageId,',') FROM Page WHERE PageAreaId = {Pageview.AreaID}) " + sqlQuery; 202 var rawData = Dynamicweb.Data.Database.CreateDataReader(sqlQuery); 203 while (rawData.Read()) 204 { 205 var themeId = rawData["ColumnValue"].ToString(); 206 var themeUsageExists = themeUsages.FirstOrDefault(t => t.Id == themeId) != null; 207 if (!themeUsageExists) 208 { 209 themeUsages.Add(new ThemeUsage { Id = themeId }); 210 } 211 212 var themeUsage = themeUsages.FirstOrDefault(t => t.Id == themeId); 213 if (themeUsage == null) continue; 214 215 if (Converter.ToInt32(rawData["AreaId"].ToString()) > 0) { themeUsage.WebsiteUsages.Add(Converter.ToInt32(rawData["AreaId"].ToString())); } 216 if (Converter.ToInt32(rawData["PageId"].ToString()) > 0) { themeUsage.PageUsages.Add(Converter.ToInt32(rawData["PageId"].ToString())); } 217 if (Converter.ToInt32(rawData["PagePropertiesId"].ToString()) > 0) { themeUsage.PagePropertyUsages.Add(Converter.ToInt32(rawData["PagePropertiesId"].ToString())); } 218 if (Converter.ToInt32(rawData["GridRowId"].ToString()) > 0) { themeUsage.GridRowUsages.Add(Converter.ToInt32(rawData["GridRowId"].ToString())); } 219 if (Converter.ToInt32(rawData["ParagraphId"].ToString()) > 0) { themeUsage.ParagraphUsages.Add(Converter.ToInt32(rawData["ParagraphId"].ToString())); } 220 } 221 } 222 223 private void UpdateAllUsages(List<ThemeUsage> themeUsages) 224 { 225 foreach (var themeUsage in themeUsages) 226 { 227 int websiteUsages = themeUsage?.WebsiteUsages.Count ?? 0; 228 int pageUsages = themeUsage?.PageUsages.Count ?? 0; 229 int pagePropertyUsages = themeUsage?.PagePropertyUsages.Count ?? 0; 230 int gridRowUsages = themeUsage?.GridRowUsages.Count ?? 0; 231 int paragraphUsages = themeUsage?.ParagraphUsages.Count ?? 0; 232 themeUsage.AllUsages = websiteUsages + pageUsages + pagePropertyUsages + gridRowUsages + paragraphUsages; 233 } 234 } 235 236 private ThemeUsage GetThemeUsageById(string themeId) 237 { 238 var themeUsages = GetAllThemeUsages(); 239 return themeUsages.FirstOrDefault(t => t.Id == themeId); 240 } 241 242 } 243 244 @{ 245 string themeName = !string.IsNullOrWhiteSpace(Model.Item.GetString("Name")) ? Model.Item.GetString("Name") : "Default"; 246 string themeClassName = !string.IsNullOrWhiteSpace(Model.Item.GetString("CSSClassName")) ? Model.Item.GetString("CSSClassName").Replace(" ", "").Trim().ToLower() : ""; 247 248 //Theme colors 249 string foregroundColor = Model.Item.GetString("ForegroundColor", "currentColor"); 250 string backgroundColor = Model.Item.GetString("BackgroundColor", "transparent"); 251 string accentColor = Model.Item.GetString("accentColor", "currentColor"); 252 string borderColor = Model.Item.GetString("BorderColor", "transparent"); 253 254 //Primary button 255 string buttonPrimaryForegroundColor = Model.Item.GetString("ButtonPrimaryForegroundColor", "currentColor"); 256 string buttonPrimaryBackgroundColor = Model.Item.GetString("ButtonPrimaryBackgroundColor", "transparent"); 257 string buttonPrimaryBorderColor = Model.Item.GetString("ButtonPrimaryBorderColor", "transparent"); 258 259 string buttonPrimaryHoverBackgroundColorAuto = "transparent"; 260 if (buttonPrimaryBackgroundColor != "transparent") 261 { 262 buttonPrimaryHoverBackgroundColorAuto = "hsl(" + GetColorVariation(buttonPrimaryBackgroundColor) + ")"; 263 } 264 string buttonPrimaryHoverForegroundColor = Model.Item.GetString("ButtonPrimaryHoverForegroundColor", buttonPrimaryForegroundColor); 265 string buttonPrimaryHoverBackgroundColor = Model.Item.GetString("ButtonPrimaryHoverBackgroundColor", buttonPrimaryHoverBackgroundColorAuto); 266 string buttonPrimaryHoverBorderColor = Model.Item.GetString("ButtonPrimaryHoverBorderColor", buttonPrimaryBorderColor); 267 268 //Secondary buton 269 string buttonSecondaryForegroundColor = Model.Item.GetString("ButtonSecondaryForegroundColor", "currentColor"); 270 string buttonSecondaryBackgroundColor = Model.Item.GetString("ButtonSecondaryBackgroundColor", "transparent"); 271 string buttonSecondaryBorderColor = Model.Item.GetString("ButtonSecondaryBorderColor", "transparent"); 272 273 string buttonSecondaryHoverBackgroundColorAuto = "transparent"; 274 if (buttonSecondaryBackgroundColor != "transparent") 275 { 276 buttonSecondaryHoverBackgroundColorAuto = "hsl(" + GetColorVariation(buttonSecondaryBackgroundColor) + ")"; 277 } 278 string buttonSecondaryHoverForegroundColor = Model.Item.GetString("ButtonSecondaryHoverForegroundColor", buttonSecondaryForegroundColor); 279 string buttonSecondaryHoverBackgroundColor = Model.Item.GetString("ButtonSecondaryHoverBackgroundColor", buttonSecondaryHoverBackgroundColorAuto); 280 string buttonSecondaryHoverBorderColor = Model.Item.GetString("ButtonSecondaryHoverBorderColor", buttonSecondaryBorderColor); 281 282 //Link buton 283 string buttonLinkColor = Model.Item.GetString("ButtonLinkColor", "currentColor"); 284 string buttonLinkHoverColorAuto = "currentColor"; 285 if (buttonLinkColor != "currentColor") 286 { 287 buttonLinkHoverColorAuto = "hsl(" + GetColorVariation(buttonLinkColor) + ")"; 288 } 289 string buttonLinkHoverColor = Model.Item.GetString("ButtonLinkHoverColor", buttonLinkHoverColorAuto); 290 291 string accessibilityOutlineColor = Model.Item.GetString("OutlineColor") != null ? Model.Item.GetString("OutlineColor") : ""; 292 293 if (!string.IsNullOrEmpty(themeClassName)) 294 { 295 var sb = new System.Text.StringBuilder(); 296 297 sb.AppendLine("." + themeClassName + "{"); 298 if (!string.IsNullOrEmpty(foregroundColor)) 299 { 300 sb.AppendLine($"--swift-foreground-color: {foregroundColor};"); 301 sb.AppendLine($"--swift-foreground-color-rgb: {HexToRGB(foregroundColor)};"); 302 } 303 if (!string.IsNullOrEmpty(backgroundColor)) 304 { 305 sb.AppendLine($"--swift-background-color: {backgroundColor};"); 306 sb.AppendLine($"--swift-background-color-rgb: {HexToRGB(backgroundColor)};"); 307 } 308 if (!string.IsNullOrEmpty(accentColor)) 309 { 310 sb.AppendLine($"--swift-accent-color: {accentColor};"); 311 sb.AppendLine($"--swift-accent-color-rgb: {HexToRGB(accentColor)};"); 312 } 313 if (!string.IsNullOrEmpty(borderColor)) 314 { 315 sb.AppendLine($"--swift-border-color: {borderColor};"); 316 sb.AppendLine($"--swift-border-color-rgb: {HexToRGB(borderColor)};"); 317 } 318 319 if (!string.IsNullOrEmpty(buttonPrimaryBackgroundColor)) 320 { 321 sb.AppendLine($"--swift-button-primary-background-color: {buttonPrimaryBackgroundColor};"); 322 sb.AppendLine($"--swift-button-primary-background-color-rgb: {HexToRGB(buttonPrimaryBackgroundColor)};"); 323 } 324 if (!string.IsNullOrEmpty(buttonPrimaryForegroundColor)) 325 { 326 sb.AppendLine($"--swift-button-primary-foreground-color: {buttonPrimaryForegroundColor};"); 327 sb.AppendLine($"--swift-button-primary-foreground-color-rgb: {HexToRGB(buttonPrimaryForegroundColor)};"); 328 } 329 if (!string.IsNullOrEmpty(buttonPrimaryBorderColor)) 330 { 331 sb.AppendLine($"--swift-button-primary-border-color: {buttonPrimaryBorderColor};"); 332 sb.AppendLine($"--swift-button-primary-border-color-rgb: {HexToRGB(buttonPrimaryBorderColor)};"); 333 } 334 335 if (!string.IsNullOrEmpty(buttonPrimaryHoverBackgroundColor)) 336 { 337 sb.AppendLine($"--swift-button-primary-hover-background-color: {buttonPrimaryHoverBackgroundColor};"); 338 sb.AppendLine($"--swift-button-primary-hover-background-color-rgb: {HexToRGB(buttonPrimaryHoverBackgroundColor)};"); 339 } 340 if (!string.IsNullOrEmpty(buttonPrimaryHoverForegroundColor)) 341 { 342 sb.AppendLine($"--swift-button-primary-hover-foreground-color: {buttonPrimaryHoverForegroundColor};"); 343 sb.AppendLine($"--swift-button-primary-hover-foreground-color-rgb: {HexToRGB(buttonPrimaryHoverForegroundColor)};"); 344 } 345 if (!string.IsNullOrEmpty(buttonPrimaryHoverBorderColor)) 346 { 347 sb.AppendLine($"--swift-button-primary-hover-border-color: {buttonPrimaryHoverBorderColor};"); 348 sb.AppendLine($"--swift-button-primary-hover-border-color-rgb: {HexToRGB(buttonPrimaryHoverBorderColor)};"); 349 } 350 351 if (!string.IsNullOrEmpty(buttonSecondaryBackgroundColor)) 352 { 353 sb.AppendLine($"--swift-button-secondary-background-color: {buttonSecondaryBackgroundColor};"); 354 sb.AppendLine($"--swift-button-secondary-background-color-rgb: {HexToRGB(buttonSecondaryBackgroundColor)};"); 355 } 356 if (!string.IsNullOrEmpty(buttonSecondaryForegroundColor)) 357 { 358 sb.AppendLine($"--swift-button-secondary-foreground-color: {buttonSecondaryForegroundColor};"); 359 sb.AppendLine($"--swift-button-secondary-foreground-color-rgb: {HexToRGB(buttonSecondaryForegroundColor)};"); 360 } 361 if (!string.IsNullOrEmpty(buttonSecondaryBorderColor)) 362 { 363 sb.AppendLine($"--swift-button-secondary-border-color: {buttonSecondaryBorderColor};"); 364 sb.AppendLine($"--swift-button-secondary-border-color-rgb: {HexToRGB(buttonSecondaryBorderColor)};"); 365 } 366 if (!string.IsNullOrEmpty(buttonSecondaryHoverBackgroundColor)) 367 { 368 sb.AppendLine($"--swift-button-secondary-hover-background-color: {buttonSecondaryHoverBackgroundColor};"); 369 sb.AppendLine($"--swift-button-secondary-hover-background-color-rgb: {HexToRGB(buttonSecondaryHoverBackgroundColor)};"); 370 } 371 if (!string.IsNullOrEmpty(buttonSecondaryHoverForegroundColor)) 372 { 373 sb.AppendLine($"--swift-button-secondary-hover-foreground-color: {buttonSecondaryHoverForegroundColor};"); 374 sb.AppendLine($"--swift-button-secondary-hover-foreground-color-rgb: {HexToRGB(buttonSecondaryHoverForegroundColor)};"); 375 } 376 if (!string.IsNullOrEmpty(buttonSecondaryHoverBorderColor)) 377 { 378 sb.AppendLine($"--swift-button-secondary-hover-border-color: {buttonSecondaryHoverBorderColor};"); 379 sb.AppendLine($"--swift-button-secondary-hover-border-color-rgb: {HexToRGB(buttonSecondaryHoverBorderColor)};"); 380 } 381 if (!string.IsNullOrEmpty(buttonLinkColor)) 382 { 383 sb.AppendLine($"--swift-button-link-color: {buttonLinkColor};"); 384 sb.AppendLine($"--swift-button-link-color-rgb: {HexToRGB(buttonLinkColor)};"); 385 } 386 if (!string.IsNullOrEmpty(buttonLinkHoverColor)) 387 { 388 sb.AppendLine($"--swift-button-link-hover-color: {buttonLinkHoverColor};"); 389 sb.AppendLine($"--swift-button-link-hover-color-rgb: {HexToRGB(buttonLinkHoverColor)};"); 390 } 391 if (!string.IsNullOrEmpty(accessibilityOutlineColor)) 392 { 393 sb.AppendLine($"--swift-a11y-outline-color: {accessibilityOutlineColor};"); 394 sb.AppendLine($"--swift-a11y-outline-color-rgb: {HexToRGB(accessibilityOutlineColor)};"); 395 } 396 sb.AppendLine("}"); 397 398 Dynamicweb.Core.Helpers.TextFileHelper.WriteTextFile(sb.ToString() + Environment.NewLine, Dynamicweb.Context.Current.Server.MapPath($"/Files/Templates/Designs/Swift/_parsed/Swift_css/Swift_theme_styles_{Dynamicweb.Content.Services.Pages.GetPage(Model.PageID).AreaId}.tmp"), true); 399 } 400 } 401 402 @if (themeClassName != "") 403 { 404 string iconPath = "/Files/Templates/Designs/Swift/Assets/icons/"; 405 406 <div class="g-col-12 g-col-lg-4"> 407 <div class="swift-checkered p-3"> 408 <div class="theme-option theme @themeClassName p-lg-3"> 409 <div class="mb-2 pb-1 border-bottom d-flex align-items-center"> 410 <span class="icon-3 me-2"> 411 @ReadFile(iconPath + "sun.svg") 412 </span> 413 <h4 class="m-0 p-0">@themeName</h4> 414 </div> 415 <div class="d-flex flex-column gap-1 mb-2"> 416 <p class="mb-0">This is the body text of the theme.</p> 417 <p class="mb-0" style="color: var(--swift-accent-color)">This is the accent color of the theme.</p> 418 </div> 419 <div> 420 <button class="btn btn-primary me-1">Primary</button> 421 <button class="btn btn-secondary">Secondary</button> 422 <button class="btn btn-link">Link</button> 423 </div> 424 </div> 425 </div> 426 </div> 427 <div class="g-col-12 g-col-lg-8 mb-4 mb-lg-0"> 428 <div class="grid fs-7"> 429 <div class="g-col-12 g-col-lg-3"> 430 <table class="table table-borderless table-sm w-100"> 431 <thead> 432 <tr> 433 <th colspan="2" class="fw-bold">@Translate("Base")</th> 434 </tr> 435 </thead> 436 <tr> 437 <td>@Translate("Foreground")</td> 438 <td>@GetColorSquare(foregroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@foregroundColor');">@foregroundColor</a></td> 439 </tr> 440 <tr> 441 <td>@Translate("Background")</td> 442 <td>@GetColorSquare(backgroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@backgroundColor');">@backgroundColor</a></td> 443 </tr> 444 <tr> 445 <td>@Translate("Accent")</td> 446 <td>@GetColorSquare(accentColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@accentColor');">@accentColor</a></td> 447 </tr> 448 <tr> 449 <td>@Translate("Border")</td> 450 <td>@GetColorSquare(borderColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@borderColor');">@borderColor</a></td> 451 </tr> 452 </table> 453 </div> 454 <div class="g-col-12 g-col-lg-3"> 455 <table class="table table-borderless table-sm w-100"> 456 <thead> 457 <tr> 458 <th colspan="2" class="fw-bold">@Translate("Primary button")</th> 459 </tr> 460 </thead> 461 <tr> 462 <td>@Translate("Foreground")</td> 463 <td>@GetColorSquare(buttonPrimaryForegroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonPrimaryForegroundColor');">@buttonPrimaryForegroundColor</a></td> 464 </tr> 465 <tr> 466 <td>@Translate("Background")</td> 467 <td>@GetColorSquare(buttonPrimaryBackgroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonPrimaryBackgroundColor');">@buttonPrimaryBackgroundColor</a></td> 468 </tr> 469 @if (!string.IsNullOrEmpty(buttonPrimaryBorderColor)) 470 { 471 <tr> 472 <td>@Translate("Border")</td> 473 <td>@GetColorSquare(buttonPrimaryBorderColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonPrimaryBorderColor');">@buttonPrimaryBorderColor</a></td> 474 </tr> 475 } 476 <thead> 477 <tr> 478 <th colspan="2" class="fw-bold">@Translate("Primary button hover")</th> 479 </tr> 480 </thead> 481 @if (!string.IsNullOrEmpty(buttonPrimaryHoverForegroundColor)) 482 { 483 <tr> 484 <td>@Translate("Foreground")</td> 485 <td>@GetColorSquare(buttonPrimaryHoverForegroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonPrimaryHoverForegroundColor');">@buttonPrimaryHoverForegroundColor</a></td> 486 </tr> 487 } 488 @if (!string.IsNullOrEmpty(buttonPrimaryHoverBackgroundColor)) 489 { 490 <tr> 491 <td>@Translate("Background")</td> 492 <td>@GetColorSquare(buttonPrimaryHoverBackgroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonPrimaryHoverBackgroundColor');">@buttonPrimaryHoverBackgroundColor</a></td> 493 </tr> 494 } 495 @if (!string.IsNullOrEmpty(buttonPrimaryHoverBorderColor)) 496 { 497 <tr> 498 <td>@Translate("Border")</td> 499 <td>@GetColorSquare(buttonPrimaryHoverBorderColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonPrimaryHoverBorderColor');">@buttonPrimaryHoverBorderColor</a></td> 500 </tr> 501 } 502 </table> 503 </div> 504 <div class="g-col-12 g-col-lg-3"> 505 <table class="table table-borderless table-sm w-100"> 506 <thead> 507 <tr> 508 <th colspan="2" class="fw-bold">@Translate("Secondary button")</th> 509 </tr> 510 </thead> 511 <tr> 512 <td>@Translate("Foreground")</td> 513 <td>@GetColorSquare(buttonSecondaryForegroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonSecondaryForegroundColor');">@buttonSecondaryForegroundColor</a></td> 514 </tr> 515 <tr> 516 <td>@Translate("Background")</td> 517 <td>@GetColorSquare(buttonSecondaryBackgroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonSecondaryBackgroundColor');">@buttonSecondaryBackgroundColor</a></td> 518 </tr> 519 @if (!string.IsNullOrEmpty(buttonSecondaryBorderColor)) 520 { 521 <tr> 522 <td>@Translate("Border")</td> 523 <td>@GetColorSquare(buttonSecondaryBorderColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonSecondaryBorderColor');">@buttonSecondaryBorderColor</a></td> 524 </tr> 525 } 526 <thead> 527 <tr> 528 <th colspan="2" class="fw-bold">@Translate("Secondary button hover")</th> 529 </tr> 530 </thead> 531 @if (!string.IsNullOrEmpty(buttonSecondaryHoverForegroundColor)) 532 { 533 <tr> 534 <td>@Translate("Foreground")</td> 535 <td>@GetColorSquare(buttonSecondaryHoverForegroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonSecondaryHoverForegroundColor');">@buttonSecondaryHoverForegroundColor</a></td> 536 </tr> 537 } 538 @if (!string.IsNullOrEmpty(buttonSecondaryHoverBackgroundColor)) 539 { 540 <tr> 541 <td>@Translate("Background")</td> 542 <td>@GetColorSquare(buttonSecondaryHoverBackgroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonSecondaryHoverBackgroundColor');">@buttonSecondaryHoverBackgroundColor</a></td> 543 </tr> 544 } 545 @if (!string.IsNullOrEmpty(buttonSecondaryHoverBorderColor)) 546 { 547 <tr> 548 <td>@Translate("Border")</td> 549 <td>@GetColorSquare(buttonSecondaryHoverBorderColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonSecondaryHoverBorderColor');">@buttonSecondaryHoverBorderColor</a></td> 550 </tr> 551 } 552 @if (!string.IsNullOrEmpty(accessibilityOutlineColor)) 553 { 554 <tr> 555 <td>@Translate("Focus outline")</td> 556 <td>@GetColorSquare(accessibilityOutlineColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@accessibilityOutlineColor');">@accessibilityOutlineColor</a></td> 557 </tr> 558 } 559 </table> 560 </div> 561 <div class="g-col-12 g-col-lg-3"> 562 <table class="table table-borderless table-sm w-100"> 563 <thead> 564 <tr> 565 <th colspan="2" class="fw-bold">@Translate("Link button")</th> 566 </tr> 567 </thead> 568 <tr> 569 <td>@Translate("Link color")</td> 570 <td>@GetColorSquare(buttonLinkColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonLinkColor');">@buttonLinkColor</a></td> 571 </tr> 572 <thead> 573 <tr> 574 <th colspan="2" class="fw-bold">@Translate("Link button hover")</th> 575 </tr> 576 </thead> 577 @if (!string.IsNullOrEmpty(buttonLinkHoverColor)) 578 { 579 <tr> 580 <td>@Translate("Link hover color")</td> 581 <td>@GetColorSquare(buttonLinkHoverColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonLinkHoverColor');">@buttonLinkHoverColor</a></td> 582 </tr> 583 } 584 585 @if (!string.IsNullOrEmpty(accessibilityOutlineColor)) 586 { 587 <tr> 588 <td>@Translate("Focus outline")</td> 589 <td>@GetColorSquare(accessibilityOutlineColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@accessibilityOutlineColor');">@accessibilityOutlineColor</a></td> 590 </tr> 591 } 592 </table> 593 </div> 594 <div class="g-col-12 g-col-lg-3"> 595 <table class="table table-borderless table-sm w-100"> 596 <tr> 597 <td class="fw-bold">@Translate("Implementation")</td> 598 </tr> 599 <tr> 600 <td> 601 @{ 602 string implementation = $"<div class=\"theme {themeClassName}\"></div>"; 603 } 604 <div class="text-muted"> 605 <code class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@themeClassName');"> 606 @Dynamicweb.Core.Encoders.HtmlEncoder.HtmlEncode(implementation) 607 </code> 608 </div> 609 </td> 610 </tr> 611 </table> 612 </div> 613 @{ 614 bool hasUsageData = Converter.ToBoolean(Dynamicweb.Context.Current.Request["auditUsages"]); 615 if (hasUsageData) 616 { 617 var themeUsage = GetThemeUsageById(themeClassName); 618 int allUsages = themeUsage?.AllUsages ?? 0; 619 string buttonAttributes = allUsages > 0 ? $"data-bs-toggle=\"modal\" data-bs-target=\"#themeUsage_{Model.ID}\"" : string.Empty; 620 string badgeStyle = allUsages > 0 ? "bg-success" : "bg-danger"; 621 622 <div class="g-col-12 g-col-lg-9 position-relative"> 623 <button type="button" class="btn btn-primary btn-sm position-absolute end-0" @buttonAttributes> 624 Usages 625 <span class="position-absolute top-0 start-100 translate-middle badge rounded-pill text-white @badgeStyle">@allUsages</span> 626 </button> 627 628 @if (allUsages > 0) 629 { 630 int websiteUsages = themeUsage?.WebsiteUsages.Count ?? 0; 631 int pageUsages = themeUsage?.PageUsages.Count ?? 0; 632 int pagePropertyUsages = themeUsage?.PagePropertyUsages.Count ?? 0; 633 int gridRowUsages = themeUsage?.GridRowUsages.Count ?? 0; 634 int paragraphUsages = themeUsage?.ParagraphUsages.Count ?? 0; 635 636 <!-- Modal --> 637 <div class="modal fade" id="themeUsage_@(Model.ID)" tabindex="-1" aria-labelledby="usagesModelLabel" aria-hidden="true"> 638 <div class="modal-dialog modal-xl modal-dialog-centered modal-dialog-scrollable"> 639 <div class="modal-content"> 640 <div class="modal-header"> 641 <h5 class="modal-title" id="usagesModelLabel">@allUsages Usages of '@(themeName)' (@(themeClassName))</h5> 642 <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> 643 </div> 644 <div class="modal-body"> 645 <div class="accordion" id="accordionWrapper"> 646 @if(websiteUsages > 0) 647 { 648 <div class="accordion-item"> 649 <h2 class="accordion-header" id="headingWebsites"> 650 <button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#collapseWebsites" aria-expanded="true" aria-controls="collapseWebsites"> 651 <span class="pe-2">Websites</span><span class="badge rounded-pill bg-secondary text-light">@websiteUsages</span> 652 </button> 653 </h2> 654 <div id="collapseWebsites" class="accordion-collapse collapse show" aria-labelledby="headingWebsites" data-bs-parent="#accordionWrapper"> 655 <div class="accordion-body"> 656 <ul> 657 @foreach (var usage in themeUsage.WebsiteUsages) 658 { 659 var website = Dynamicweb.Content.Services.Areas.GetArea(usage); 660 <li><span class="fw-bold">@website.Name</span>@($" (ID: {usage})")</li> 661 } 662 </ul> 663 </div> 664 </div> 665 </div> 666 } 667 @if (pageUsages > 0) 668 { 669 var pages = Dynamicweb.Content.Services.Pages.GetPages(themeUsage.PageUsages.ToArray()); 670 671 <div class="accordion-item"> 672 <h2 class="accordion-header" id="headingPages"> 673 <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapsePages" aria-expanded="false" aria-controls="collapsePages"> 674 <span class="pe-2">Pages</span><span class="badge rounded-pill bg-secondary text-light">@pageUsages</span> 675 </button> 676 </h2> 677 <div id="collapsePages" class="accordion-collapse collapse" aria-labelledby="headingPages" data-bs-parent="#accordionWrapper"> 678 <div class="accordion-body"> 679 <ul> 680 @foreach (var usage in themeUsage.PageUsages) 681 { 682 <li><span class="fw-bold">@pages.FirstOrDefault(p => p.ID == usage).GetDisplayName()</span>@($" (ID: {usage})")</li> 683 } 684 </ul> 685 </div> 686 </div> 687 </div> 688 } 689 @if (pagePropertyUsages > 0) 690 { 691 var pages = Dynamicweb.Content.Services.Pages.GetPages(themeUsage.PageUsages.ToArray()); 692 693 <div class="accordion-item"> 694 <h2 class="accordion-header" id="headingPageProperties"> 695 <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapsePageProperties" aria-expanded="false" aria-controls="collapsePageProperties"> 696 <span class="pe-2">Page Properties</span><span class="badge rounded-pill bg-secondary text-light">@pagePropertyUsages</span> 697 </button> 698 </h2> 699 <div id="collapsePageProperties" class="accordion-collapse collapse" aria-labelledby="headingPageProperties" data-bs-parent="#accordionWrapper"> 700 <div class="accordion-body"> 701 <ul> 702 @foreach (var usage in themeUsage.PagePropertyUsages) 703 { 704 <li><span class="fw-bold">@pages.FirstOrDefault(p => p.ID == usage).GetDisplayName()</span>@($" (ID: {usage})")</li> 705 } 706 </ul> 707 </div> 708 </div> 709 </div> 710 } 711 @if (gridRowUsages > 0) 712 { 713 var rows = Dynamicweb.Content.Services.Grids.GetGridRows().Where(r => themeUsage.GridRowUsages.Contains(r.ID)).ToList(); 714 715 <div class="accordion-item"> 716 <h2 class="accordion-header" id="headingRows"> 717 <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseRows" aria-expanded="false" aria-controls="collapseRows"> 718 <span class="pe-2">Rows</span><span class="badge rounded-pill bg-secondary text-light">@gridRowUsages</span> 719 </button> 720 </h2> 721 <div id="collapseRows" class="accordion-collapse collapse" aria-labelledby="headingRows" data-bs-parent="#accordionWrapper"> 722 <div class="accordion-body"> 723 <ul> 724 @foreach (var usage in themeUsage.GridRowUsages) 725 { 726 var row = rows.FirstOrDefault(r => r.ID == usage); 727 var page = Dynamicweb.Content.Services.Pages.GetPage(row.PageId); 728 <li>Page: <span class="fw-bold">@(page.GetDisplayName())</span>@($"( ID: {page.ID}) - Row: ")<span class="fw-bold">@(row.DefinitionId)</span>@($" (ID: {usage})")</li> 729 } 730 </ul> 731 </div> 732 </div> 733 </div> 734 } 735 @if (paragraphUsages > 0) 736 { 737 var paragraphs = Dynamicweb.Content.Services.Paragraphs.GetParagraphs().Where(p => themeUsage.ParagraphUsages.Contains(p.ID)).ToList(); 738 739 <div class="accordion-item"> 740 <h2 class="accordion-header" id="headingParagraphs"> 741 <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseParagraphs" aria-expanded="false" aria-controls="collapseParagraphs"> 742 <span class="pe-2">Paragraphs</span><span class="badge rounded-pill bg-secondary text-light">@paragraphUsages</span> 743 </button> 744 </h2> 745 <div id="collapseParagraphs" class="accordion-collapse collapse" aria-labelledby="headingParagraphs" data-bs-parent="#accordionWrapper"> 746 <div class="accordion-body"> 747 <ul> 748 @foreach (var usage in themeUsage.ParagraphUsages) 749 { 750 var paragraph = paragraphs.FirstOrDefault(p => p.ID == usage); 751 var page = Dynamicweb.Content.Services.Pages.GetPage(paragraph.PageID); 752 <li>Page: <span class="fw-bold">@(page.GetDisplayName())</span>@($"( ID: {page.ID}) - Paragraph: ")<span class="fw-bold">@paragraph.Header</span>@($" (ID: {usage})")</li> 753 } 754 </ul> 755 </div> 756 </div> 757 </div> 758 } 759 </div> 760 </div> 761 </div> 762 </div> 763 </div> 764 } 765 </div> 766 } 767 } 768 </div> 769 </div> 770 } 771 <div class="g-col-12"> 772 <hr /> 773 </div> 774
Error executing template "Designs/Swift/Paragraph/Swift_Theme.cshtml" System.Data.SqlClient.SqlException (0x80131904): STRING_AGG aggregation result exceeded the limit of 8000 bytes. Use LOB types to avoid result truncation. at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction) at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose) at System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady) at System.Data.SqlClient.SqlDataReader.TryConsumeMetaData() at System.Data.SqlClient.SqlDataReader.get_MetaData() at System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString, Boolean isInternal, Boolean forDescribeParameterEncryption, Boolean shouldCacheForAlwaysEncrypted) at System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async, Int32 timeout, Task& task, Boolean asyncWrite, Boolean inRetry, SqlDataReader ds, Boolean describeParameterEncryptionRequest) at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, TaskCompletionSource`1 completion, Int32 timeout, Task& task, Boolean& usedCache, Boolean asyncWrite, Boolean inRetry) at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method) at System.Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior behavior, String method) at Dynamicweb.Data.Database.CreateDataReader(IDbCommand command, CommandBehavior behavior) at Dynamicweb.Data.Database.CreateDataReader(String sql, IDbConnection connection, IDbTransaction transaction, CommandBehavior behavior, Int32 commandTimeout, Dictionary`2 sqlParams) at Dynamicweb.Data.Database.CreateDataReader(String sql, IDbConnection connection, IDbTransaction transaction, Int32 commandTimeout, Dictionary`2 sqlParams) at Dynamicweb.Data.Database.CreateDataReader(String sql) at CompiledRazorTemplates.Dynamic.RazorEngine_8e3f1b11eb0041ceb2ca487c2be837e6.UpdateThemeUsages(String sqlQuery, List`1 themeUsages) in E:\Dynamicweb.net\Solutions\Dynamicweb\dw2022.cloud.dynamicweb-cms.com\Files\Templates\Designs\Swift\Paragraph\Swift_Theme.cshtml:line 202 at CompiledRazorTemplates.Dynamic.RazorEngine_8e3f1b11eb0041ceb2ca487c2be837e6.GetAllThemeUsages() in E:\Dynamicweb.net\Solutions\Dynamicweb\dw2022.cloud.dynamicweb-cms.com\Files\Templates\Designs\Swift\Paragraph\Swift_Theme.cshtml:line 184 at CompiledRazorTemplates.Dynamic.RazorEngine_8e3f1b11eb0041ceb2ca487c2be837e6.GetThemeUsageById(String themeId) in E:\Dynamicweb.net\Solutions\Dynamicweb\dw2022.cloud.dynamicweb-cms.com\Files\Templates\Designs\Swift\Paragraph\Swift_Theme.cshtml:line 238 at CompiledRazorTemplates.Dynamic.RazorEngine_8e3f1b11eb0041ceb2ca487c2be837e6.Execute() in E:\Dynamicweb.net\Solutions\Dynamicweb\dw2022.cloud.dynamicweb-cms.com\Files\Templates\Designs\Swift\Paragraph\Swift_Theme.cshtml:line 617 at RazorEngine.Templating.TemplateBase.RazorEngine.Templating.ITemplate.Run(ExecuteContext context, TextWriter reader) at RazorEngine.Templating.RazorEngineService.RunCompile(ITemplateKey key, TextWriter writer, Type modelType, Object model, DynamicViewBag viewBag) at RazorEngine.Templating.RazorEngineServiceExtensions.<>c__DisplayClass16_0.<RunCompile>b__0(TextWriter writer) at RazorEngine.Templating.RazorEngineServiceExtensions.WithWriter(Action`1 withWriter) at Dynamicweb.Rendering.RazorTemplateRenderingProvider.Render(Template template) at Dynamicweb.Rendering.TemplateRenderingService.Render(Template template) at Dynamicweb.Rendering.Template.RenderRazorTemplate() ClientConnectionId:b42d1cec-597c-4eed-bdc2-e0762a41101a Error Number:9829,State:1,Class:16
1 @inherits Dynamicweb.Rendering.ViewModelTemplate<Dynamicweb.Frontend.ParagraphViewModel> 2 @using System.Globalization 3 @using System.Drawing 4 @using Dynamicweb.Core 5 6 @functions{ 7 // Get Hex Color from color picker and translate to RGB color 8 public static string HexToRGB(string hexString) 9 { 10 if (hexString.Equals("none") || string.IsNullOrEmpty(hexString)) 11 return hexString; 12 13 //replace # occurences 14 if (hexString.IndexOf('#') != -1) 15 hexString = hexString.Replace("#", ""); 16 try 17 { 18 int r, g, b = 0; 19 r = int.Parse(hexString.Substring(0, 2), NumberStyles.AllowHexSpecifier); 20 g = int.Parse(hexString.Substring(2, 2), NumberStyles.AllowHexSpecifier); 21 b = int.Parse(hexString.Substring(4, 2), NumberStyles.AllowHexSpecifier); 22 23 string rgb = r + "," + g + "," + b; 24 return rgb; 25 } 26 catch (System.Exception) 27 { 28 return hexString; 29 } 30 } 31 32 public static string GetColorSquare(string hex) 33 { 34 return $"<div class=\"swift-checkered d-inline-block me-1\" style=\"height:1.25rem;width:1.25rem;\"><div style=\"background-color: {hex};border:.0625rem solid grey\" class=\"w-100 h-100\"></div></div>"; 35 } 36 37 public class HSL 38 { 39 public double h { get; set; } 40 public double s { get; set; } 41 public double l { get; set; } 42 } 43 44 //Convert HEX to HSL 45 public static HSL HexToHsl(string hexString) 46 { 47 System.Drawing.Color color = System.Drawing.ColorTranslator.FromHtml(hexString); 48 49 float _R = (color.R / 255f); 50 float _G = (color.G / 255f); 51 float _B = (color.B / 255f); 52 53 float _Min = Math.Min(Math.Min(_R, _G), _B); 54 float _Max = Math.Max(Math.Max(_R, _G), _B); 55 float _Delta = _Max - _Min; 56 57 float S = 0; 58 float L = (float)((_Max + _Min) / 2.0f); 59 60 if (_Delta != 0) 61 { 62 if (L < 0.5f) 63 { 64 S = (float)(_Delta / (_Max + _Min)); 65 } 66 else 67 { 68 S = (float)(_Delta / (2.0f - _Max - _Min)); 69 } 70 } 71 72 HSL hsl = new HSL(); 73 hsl.h = Math.Round(color.GetHue(), 2); 74 hsl.s = Math.Round(S, 2) * 100; 75 hsl.l = Math.Round(L, 2) * 100; 76 77 return hsl; 78 } 79 80 //Find contrast color (white, black) 81 public static Color GetContrastColor(string hexString) 82 { 83 System.Drawing.Color bg = System.Drawing.ColorTranslator.FromHtml(hexString); 84 85 int nThreshold = 105; 86 int bgDelta = Convert.ToInt32((bg.R * 0.299) + (bg.G * 0.587) + 87 (bg.B * 0.114)); 88 89 Color foreColor = (255 - bgDelta < nThreshold) ? Color.Black : Color.White; 90 return foreColor; 91 } 92 93 public string GetColorVariation(string hexString) 94 { 95 var contrast = GetContrastColor(hexString); 96 HSL currentHslColor = HexToHsl(hexString); 97 HSL variantHslColor = currentHslColor; 98 99 if (contrast == Color.Black) 100 { 101 variantHslColor.l = 85; //The background is dark - Color should be light 102 } 103 else 104 { 105 variantHslColor.l = 40; //The background is light - Color should be less light 106 } 107 108 //Color is very light 109 if (currentHslColor.l > 85) 110 { 111 variantHslColor.l = 95; 112 } 113 114 string colorString = variantHslColor.h + ", " + variantHslColor.s + "%, " + variantHslColor.l + "%"; 115 return colorString; 116 } 117 118 private class ThemeDatabaseUsage 119 { 120 public string TableName { get; set; } 121 public string ColumnName { get; set; } 122 } 123 124 private class ThemeUsage 125 { 126 public string Id { get; set; } 127 public List<int> WebsiteUsages { get; set; } = new List<int>(); 128 public List<int> PageUsages { get; set; } = new List<int>(); 129 public List<int> PagePropertyUsages { get; set; } = new List<int>(); 130 public List<int> GridRowUsages { get; set; } = new List<int>(); 131 public List<int> ParagraphUsages { get; set; } = new List<int>(); 132 public int AllUsages { get; set; } = 0; 133 } 134 135 private List<ThemeDatabaseUsage> GetThemeColumnsFromSchema() 136 { 137 string cacheKey = "ThemesFromDatabase"; 138 if (Dynamicweb.Context.Current.Items.Contains(cacheKey)) 139 { 140 return (List<ThemeDatabaseUsage>)Dynamicweb.Context.Current.Items[cacheKey]; 141 } 142 var schema = Dynamicweb.Data.Database.CreateDataReader("SELECT table_name, column_name FROM information_schema.columns WHERE column_name LIKE '%Theme%'"); 143 144 var rawData = new List<ThemeDatabaseUsage>(); 145 while (schema.Read()) { 146 rawData.Add(new ThemeDatabaseUsage {TableName = schema["table_name"].ToString(), ColumnName = schema["column_name"].ToString() }); 147 } 148 Dynamicweb.Context.Current.Items[cacheKey] = rawData; 149 return rawData; 150 } 151 152 private List<ThemeUsage> GetAllThemeUsages() 153 { 154 string cacheKey = "ThemeUsages"; 155 if (Dynamicweb.Context.Current.Items.Contains(cacheKey)) 156 { 157 return (List<ThemeUsage>)Dynamicweb.Context.Current.Items[cacheKey]; 158 } 159 160 var rawData = GetThemeColumnsFromSchema(); 161 var themeUsages = new List<ThemeUsage>(); 162 163 var sqlQuery = ""; 164 foreach (var row in rawData) 165 { 166 if (!string.IsNullOrEmpty(sqlQuery)) { sqlQuery += " UNION ALL "; } 167 sqlQuery += $"SELECT '{row.TableName}' AS TableName, '{row.ColumnName}' AS ColumnName, {row.ColumnName} AS ColumnValue, Id, AreaId, Page.PageId, PageProperties.PageId as 'PagePropertiesId', GridRowId, ParagraphId" + 168 $" FROM [{row.TableName}]" + 169 $" LEFT JOIN Area ON AreaItemType = '{row.TableName.Replace("ItemType_","")}' AND AreaItemId = Id" + 170 $" LEFT JOIN Page ON PageItemType = '{row.TableName.Replace("ItemType_","")}' AND PageItemId = Id" + 171 $" LEFT JOIN Page as PageProperties ON AreaItemTypePageProperty = '{row.TableName.Replace("ItemType_","")}' AND PageProperties.PagePropertyItemId = Id" + 172 $" LEFT JOIN GridRow ON GridRowItemType = '{row.TableName.Replace("ItemType_","")}' AND GridRowItemId = Id" + 173 $" LEFT JOIN Paragraph ON ParagraphItemType = '{row.TableName.Replace("ItemType_","")}' AND ParagraphItemId = Id" + 174 $" WHERE {row.ColumnName} != '' AND {row.ColumnName} IS NOT NULL" + 175 $" AND (AreaId IS NULL OR AreaId = {Pageview.AreaID})" + 176 $" AND (Page.PageId IS NULL OR Page.PageAreaId = {Pageview.AreaID})" + 177 $" AND (PageProperties.PageId IS NULL OR PageProperties.PageAreaId = {Pageview.AreaID})" + 178 $" AND (GridRowId IS NULL OR GridRowPageId IN (SELECT value From string_split(@pageIds, ',')))" + 179 $" AND (ParagraphId IS NULL OR ParagraphPageId IN (SELECT value From string_split(@pageIds, ',')))"; 180 181 var maxMsSqlServerCharLimit = 60000; 182 if (sqlQuery.Length > maxMsSqlServerCharLimit) 183 { 184 UpdateThemeUsages(sqlQuery, themeUsages); 185 sqlQuery = ""; 186 } 187 } 188 189 if (!string.IsNullOrEmpty(sqlQuery)) 190 { 191 UpdateThemeUsages(sqlQuery, themeUsages); 192 } 193 UpdateAllUsages(themeUsages); 194 195 Dynamicweb.Context.Current.Items[cacheKey] = themeUsages; 196 return themeUsages; 197 } 198 199 private void UpdateThemeUsages(string sqlQuery, List<ThemeUsage> themeUsages) 200 { 201 sqlQuery = $"DECLARE @pageIds NVARCHAR(max) = (SELECT STRING_AGG(PageId,',') FROM Page WHERE PageAreaId = {Pageview.AreaID}) " + sqlQuery; 202 var rawData = Dynamicweb.Data.Database.CreateDataReader(sqlQuery); 203 while (rawData.Read()) 204 { 205 var themeId = rawData["ColumnValue"].ToString(); 206 var themeUsageExists = themeUsages.FirstOrDefault(t => t.Id == themeId) != null; 207 if (!themeUsageExists) 208 { 209 themeUsages.Add(new ThemeUsage { Id = themeId }); 210 } 211 212 var themeUsage = themeUsages.FirstOrDefault(t => t.Id == themeId); 213 if (themeUsage == null) continue; 214 215 if (Converter.ToInt32(rawData["AreaId"].ToString()) > 0) { themeUsage.WebsiteUsages.Add(Converter.ToInt32(rawData["AreaId"].ToString())); } 216 if (Converter.ToInt32(rawData["PageId"].ToString()) > 0) { themeUsage.PageUsages.Add(Converter.ToInt32(rawData["PageId"].ToString())); } 217 if (Converter.ToInt32(rawData["PagePropertiesId"].ToString()) > 0) { themeUsage.PagePropertyUsages.Add(Converter.ToInt32(rawData["PagePropertiesId"].ToString())); } 218 if (Converter.ToInt32(rawData["GridRowId"].ToString()) > 0) { themeUsage.GridRowUsages.Add(Converter.ToInt32(rawData["GridRowId"].ToString())); } 219 if (Converter.ToInt32(rawData["ParagraphId"].ToString()) > 0) { themeUsage.ParagraphUsages.Add(Converter.ToInt32(rawData["ParagraphId"].ToString())); } 220 } 221 } 222 223 private void UpdateAllUsages(List<ThemeUsage> themeUsages) 224 { 225 foreach (var themeUsage in themeUsages) 226 { 227 int websiteUsages = themeUsage?.WebsiteUsages.Count ?? 0; 228 int pageUsages = themeUsage?.PageUsages.Count ?? 0; 229 int pagePropertyUsages = themeUsage?.PagePropertyUsages.Count ?? 0; 230 int gridRowUsages = themeUsage?.GridRowUsages.Count ?? 0; 231 int paragraphUsages = themeUsage?.ParagraphUsages.Count ?? 0; 232 themeUsage.AllUsages = websiteUsages + pageUsages + pagePropertyUsages + gridRowUsages + paragraphUsages; 233 } 234 } 235 236 private ThemeUsage GetThemeUsageById(string themeId) 237 { 238 var themeUsages = GetAllThemeUsages(); 239 return themeUsages.FirstOrDefault(t => t.Id == themeId); 240 } 241 242 } 243 244 @{ 245 string themeName = !string.IsNullOrWhiteSpace(Model.Item.GetString("Name")) ? Model.Item.GetString("Name") : "Default"; 246 string themeClassName = !string.IsNullOrWhiteSpace(Model.Item.GetString("CSSClassName")) ? Model.Item.GetString("CSSClassName").Replace(" ", "").Trim().ToLower() : ""; 247 248 //Theme colors 249 string foregroundColor = Model.Item.GetString("ForegroundColor", "currentColor"); 250 string backgroundColor = Model.Item.GetString("BackgroundColor", "transparent"); 251 string accentColor = Model.Item.GetString("accentColor", "currentColor"); 252 string borderColor = Model.Item.GetString("BorderColor", "transparent"); 253 254 //Primary button 255 string buttonPrimaryForegroundColor = Model.Item.GetString("ButtonPrimaryForegroundColor", "currentColor"); 256 string buttonPrimaryBackgroundColor = Model.Item.GetString("ButtonPrimaryBackgroundColor", "transparent"); 257 string buttonPrimaryBorderColor = Model.Item.GetString("ButtonPrimaryBorderColor", "transparent"); 258 259 string buttonPrimaryHoverBackgroundColorAuto = "transparent"; 260 if (buttonPrimaryBackgroundColor != "transparent") 261 { 262 buttonPrimaryHoverBackgroundColorAuto = "hsl(" + GetColorVariation(buttonPrimaryBackgroundColor) + ")"; 263 } 264 string buttonPrimaryHoverForegroundColor = Model.Item.GetString("ButtonPrimaryHoverForegroundColor", buttonPrimaryForegroundColor); 265 string buttonPrimaryHoverBackgroundColor = Model.Item.GetString("ButtonPrimaryHoverBackgroundColor", buttonPrimaryHoverBackgroundColorAuto); 266 string buttonPrimaryHoverBorderColor = Model.Item.GetString("ButtonPrimaryHoverBorderColor", buttonPrimaryBorderColor); 267 268 //Secondary buton 269 string buttonSecondaryForegroundColor = Model.Item.GetString("ButtonSecondaryForegroundColor", "currentColor"); 270 string buttonSecondaryBackgroundColor = Model.Item.GetString("ButtonSecondaryBackgroundColor", "transparent"); 271 string buttonSecondaryBorderColor = Model.Item.GetString("ButtonSecondaryBorderColor", "transparent"); 272 273 string buttonSecondaryHoverBackgroundColorAuto = "transparent"; 274 if (buttonSecondaryBackgroundColor != "transparent") 275 { 276 buttonSecondaryHoverBackgroundColorAuto = "hsl(" + GetColorVariation(buttonSecondaryBackgroundColor) + ")"; 277 } 278 string buttonSecondaryHoverForegroundColor = Model.Item.GetString("ButtonSecondaryHoverForegroundColor", buttonSecondaryForegroundColor); 279 string buttonSecondaryHoverBackgroundColor = Model.Item.GetString("ButtonSecondaryHoverBackgroundColor", buttonSecondaryHoverBackgroundColorAuto); 280 string buttonSecondaryHoverBorderColor = Model.Item.GetString("ButtonSecondaryHoverBorderColor", buttonSecondaryBorderColor); 281 282 //Link buton 283 string buttonLinkColor = Model.Item.GetString("ButtonLinkColor", "currentColor"); 284 string buttonLinkHoverColorAuto = "currentColor"; 285 if (buttonLinkColor != "currentColor") 286 { 287 buttonLinkHoverColorAuto = "hsl(" + GetColorVariation(buttonLinkColor) + ")"; 288 } 289 string buttonLinkHoverColor = Model.Item.GetString("ButtonLinkHoverColor", buttonLinkHoverColorAuto); 290 291 string accessibilityOutlineColor = Model.Item.GetString("OutlineColor") != null ? Model.Item.GetString("OutlineColor") : ""; 292 293 if (!string.IsNullOrEmpty(themeClassName)) 294 { 295 var sb = new System.Text.StringBuilder(); 296 297 sb.AppendLine("." + themeClassName + "{"); 298 if (!string.IsNullOrEmpty(foregroundColor)) 299 { 300 sb.AppendLine($"--swift-foreground-color: {foregroundColor};"); 301 sb.AppendLine($"--swift-foreground-color-rgb: {HexToRGB(foregroundColor)};"); 302 } 303 if (!string.IsNullOrEmpty(backgroundColor)) 304 { 305 sb.AppendLine($"--swift-background-color: {backgroundColor};"); 306 sb.AppendLine($"--swift-background-color-rgb: {HexToRGB(backgroundColor)};"); 307 } 308 if (!string.IsNullOrEmpty(accentColor)) 309 { 310 sb.AppendLine($"--swift-accent-color: {accentColor};"); 311 sb.AppendLine($"--swift-accent-color-rgb: {HexToRGB(accentColor)};"); 312 } 313 if (!string.IsNullOrEmpty(borderColor)) 314 { 315 sb.AppendLine($"--swift-border-color: {borderColor};"); 316 sb.AppendLine($"--swift-border-color-rgb: {HexToRGB(borderColor)};"); 317 } 318 319 if (!string.IsNullOrEmpty(buttonPrimaryBackgroundColor)) 320 { 321 sb.AppendLine($"--swift-button-primary-background-color: {buttonPrimaryBackgroundColor};"); 322 sb.AppendLine($"--swift-button-primary-background-color-rgb: {HexToRGB(buttonPrimaryBackgroundColor)};"); 323 } 324 if (!string.IsNullOrEmpty(buttonPrimaryForegroundColor)) 325 { 326 sb.AppendLine($"--swift-button-primary-foreground-color: {buttonPrimaryForegroundColor};"); 327 sb.AppendLine($"--swift-button-primary-foreground-color-rgb: {HexToRGB(buttonPrimaryForegroundColor)};"); 328 } 329 if (!string.IsNullOrEmpty(buttonPrimaryBorderColor)) 330 { 331 sb.AppendLine($"--swift-button-primary-border-color: {buttonPrimaryBorderColor};"); 332 sb.AppendLine($"--swift-button-primary-border-color-rgb: {HexToRGB(buttonPrimaryBorderColor)};"); 333 } 334 335 if (!string.IsNullOrEmpty(buttonPrimaryHoverBackgroundColor)) 336 { 337 sb.AppendLine($"--swift-button-primary-hover-background-color: {buttonPrimaryHoverBackgroundColor};"); 338 sb.AppendLine($"--swift-button-primary-hover-background-color-rgb: {HexToRGB(buttonPrimaryHoverBackgroundColor)};"); 339 } 340 if (!string.IsNullOrEmpty(buttonPrimaryHoverForegroundColor)) 341 { 342 sb.AppendLine($"--swift-button-primary-hover-foreground-color: {buttonPrimaryHoverForegroundColor};"); 343 sb.AppendLine($"--swift-button-primary-hover-foreground-color-rgb: {HexToRGB(buttonPrimaryHoverForegroundColor)};"); 344 } 345 if (!string.IsNullOrEmpty(buttonPrimaryHoverBorderColor)) 346 { 347 sb.AppendLine($"--swift-button-primary-hover-border-color: {buttonPrimaryHoverBorderColor};"); 348 sb.AppendLine($"--swift-button-primary-hover-border-color-rgb: {HexToRGB(buttonPrimaryHoverBorderColor)};"); 349 } 350 351 if (!string.IsNullOrEmpty(buttonSecondaryBackgroundColor)) 352 { 353 sb.AppendLine($"--swift-button-secondary-background-color: {buttonSecondaryBackgroundColor};"); 354 sb.AppendLine($"--swift-button-secondary-background-color-rgb: {HexToRGB(buttonSecondaryBackgroundColor)};"); 355 } 356 if (!string.IsNullOrEmpty(buttonSecondaryForegroundColor)) 357 { 358 sb.AppendLine($"--swift-button-secondary-foreground-color: {buttonSecondaryForegroundColor};"); 359 sb.AppendLine($"--swift-button-secondary-foreground-color-rgb: {HexToRGB(buttonSecondaryForegroundColor)};"); 360 } 361 if (!string.IsNullOrEmpty(buttonSecondaryBorderColor)) 362 { 363 sb.AppendLine($"--swift-button-secondary-border-color: {buttonSecondaryBorderColor};"); 364 sb.AppendLine($"--swift-button-secondary-border-color-rgb: {HexToRGB(buttonSecondaryBorderColor)};"); 365 } 366 if (!string.IsNullOrEmpty(buttonSecondaryHoverBackgroundColor)) 367 { 368 sb.AppendLine($"--swift-button-secondary-hover-background-color: {buttonSecondaryHoverBackgroundColor};"); 369 sb.AppendLine($"--swift-button-secondary-hover-background-color-rgb: {HexToRGB(buttonSecondaryHoverBackgroundColor)};"); 370 } 371 if (!string.IsNullOrEmpty(buttonSecondaryHoverForegroundColor)) 372 { 373 sb.AppendLine($"--swift-button-secondary-hover-foreground-color: {buttonSecondaryHoverForegroundColor};"); 374 sb.AppendLine($"--swift-button-secondary-hover-foreground-color-rgb: {HexToRGB(buttonSecondaryHoverForegroundColor)};"); 375 } 376 if (!string.IsNullOrEmpty(buttonSecondaryHoverBorderColor)) 377 { 378 sb.AppendLine($"--swift-button-secondary-hover-border-color: {buttonSecondaryHoverBorderColor};"); 379 sb.AppendLine($"--swift-button-secondary-hover-border-color-rgb: {HexToRGB(buttonSecondaryHoverBorderColor)};"); 380 } 381 if (!string.IsNullOrEmpty(buttonLinkColor)) 382 { 383 sb.AppendLine($"--swift-button-link-color: {buttonLinkColor};"); 384 sb.AppendLine($"--swift-button-link-color-rgb: {HexToRGB(buttonLinkColor)};"); 385 } 386 if (!string.IsNullOrEmpty(buttonLinkHoverColor)) 387 { 388 sb.AppendLine($"--swift-button-link-hover-color: {buttonLinkHoverColor};"); 389 sb.AppendLine($"--swift-button-link-hover-color-rgb: {HexToRGB(buttonLinkHoverColor)};"); 390 } 391 if (!string.IsNullOrEmpty(accessibilityOutlineColor)) 392 { 393 sb.AppendLine($"--swift-a11y-outline-color: {accessibilityOutlineColor};"); 394 sb.AppendLine($"--swift-a11y-outline-color-rgb: {HexToRGB(accessibilityOutlineColor)};"); 395 } 396 sb.AppendLine("}"); 397 398 Dynamicweb.Core.Helpers.TextFileHelper.WriteTextFile(sb.ToString() + Environment.NewLine, Dynamicweb.Context.Current.Server.MapPath($"/Files/Templates/Designs/Swift/_parsed/Swift_css/Swift_theme_styles_{Dynamicweb.Content.Services.Pages.GetPage(Model.PageID).AreaId}.tmp"), true); 399 } 400 } 401 402 @if (themeClassName != "") 403 { 404 string iconPath = "/Files/Templates/Designs/Swift/Assets/icons/"; 405 406 <div class="g-col-12 g-col-lg-4"> 407 <div class="swift-checkered p-3"> 408 <div class="theme-option theme @themeClassName p-lg-3"> 409 <div class="mb-2 pb-1 border-bottom d-flex align-items-center"> 410 <span class="icon-3 me-2"> 411 @ReadFile(iconPath + "sun.svg") 412 </span> 413 <h4 class="m-0 p-0">@themeName</h4> 414 </div> 415 <div class="d-flex flex-column gap-1 mb-2"> 416 <p class="mb-0">This is the body text of the theme.</p> 417 <p class="mb-0" style="color: var(--swift-accent-color)">This is the accent color of the theme.</p> 418 </div> 419 <div> 420 <button class="btn btn-primary me-1">Primary</button> 421 <button class="btn btn-secondary">Secondary</button> 422 <button class="btn btn-link">Link</button> 423 </div> 424 </div> 425 </div> 426 </div> 427 <div class="g-col-12 g-col-lg-8 mb-4 mb-lg-0"> 428 <div class="grid fs-7"> 429 <div class="g-col-12 g-col-lg-3"> 430 <table class="table table-borderless table-sm w-100"> 431 <thead> 432 <tr> 433 <th colspan="2" class="fw-bold">@Translate("Base")</th> 434 </tr> 435 </thead> 436 <tr> 437 <td>@Translate("Foreground")</td> 438 <td>@GetColorSquare(foregroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@foregroundColor');">@foregroundColor</a></td> 439 </tr> 440 <tr> 441 <td>@Translate("Background")</td> 442 <td>@GetColorSquare(backgroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@backgroundColor');">@backgroundColor</a></td> 443 </tr> 444 <tr> 445 <td>@Translate("Accent")</td> 446 <td>@GetColorSquare(accentColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@accentColor');">@accentColor</a></td> 447 </tr> 448 <tr> 449 <td>@Translate("Border")</td> 450 <td>@GetColorSquare(borderColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@borderColor');">@borderColor</a></td> 451 </tr> 452 </table> 453 </div> 454 <div class="g-col-12 g-col-lg-3"> 455 <table class="table table-borderless table-sm w-100"> 456 <thead> 457 <tr> 458 <th colspan="2" class="fw-bold">@Translate("Primary button")</th> 459 </tr> 460 </thead> 461 <tr> 462 <td>@Translate("Foreground")</td> 463 <td>@GetColorSquare(buttonPrimaryForegroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonPrimaryForegroundColor');">@buttonPrimaryForegroundColor</a></td> 464 </tr> 465 <tr> 466 <td>@Translate("Background")</td> 467 <td>@GetColorSquare(buttonPrimaryBackgroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonPrimaryBackgroundColor');">@buttonPrimaryBackgroundColor</a></td> 468 </tr> 469 @if (!string.IsNullOrEmpty(buttonPrimaryBorderColor)) 470 { 471 <tr> 472 <td>@Translate("Border")</td> 473 <td>@GetColorSquare(buttonPrimaryBorderColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonPrimaryBorderColor');">@buttonPrimaryBorderColor</a></td> 474 </tr> 475 } 476 <thead> 477 <tr> 478 <th colspan="2" class="fw-bold">@Translate("Primary button hover")</th> 479 </tr> 480 </thead> 481 @if (!string.IsNullOrEmpty(buttonPrimaryHoverForegroundColor)) 482 { 483 <tr> 484 <td>@Translate("Foreground")</td> 485 <td>@GetColorSquare(buttonPrimaryHoverForegroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonPrimaryHoverForegroundColor');">@buttonPrimaryHoverForegroundColor</a></td> 486 </tr> 487 } 488 @if (!string.IsNullOrEmpty(buttonPrimaryHoverBackgroundColor)) 489 { 490 <tr> 491 <td>@Translate("Background")</td> 492 <td>@GetColorSquare(buttonPrimaryHoverBackgroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonPrimaryHoverBackgroundColor');">@buttonPrimaryHoverBackgroundColor</a></td> 493 </tr> 494 } 495 @if (!string.IsNullOrEmpty(buttonPrimaryHoverBorderColor)) 496 { 497 <tr> 498 <td>@Translate("Border")</td> 499 <td>@GetColorSquare(buttonPrimaryHoverBorderColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonPrimaryHoverBorderColor');">@buttonPrimaryHoverBorderColor</a></td> 500 </tr> 501 } 502 </table> 503 </div> 504 <div class="g-col-12 g-col-lg-3"> 505 <table class="table table-borderless table-sm w-100"> 506 <thead> 507 <tr> 508 <th colspan="2" class="fw-bold">@Translate("Secondary button")</th> 509 </tr> 510 </thead> 511 <tr> 512 <td>@Translate("Foreground")</td> 513 <td>@GetColorSquare(buttonSecondaryForegroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonSecondaryForegroundColor');">@buttonSecondaryForegroundColor</a></td> 514 </tr> 515 <tr> 516 <td>@Translate("Background")</td> 517 <td>@GetColorSquare(buttonSecondaryBackgroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonSecondaryBackgroundColor');">@buttonSecondaryBackgroundColor</a></td> 518 </tr> 519 @if (!string.IsNullOrEmpty(buttonSecondaryBorderColor)) 520 { 521 <tr> 522 <td>@Translate("Border")</td> 523 <td>@GetColorSquare(buttonSecondaryBorderColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonSecondaryBorderColor');">@buttonSecondaryBorderColor</a></td> 524 </tr> 525 } 526 <thead> 527 <tr> 528 <th colspan="2" class="fw-bold">@Translate("Secondary button hover")</th> 529 </tr> 530 </thead> 531 @if (!string.IsNullOrEmpty(buttonSecondaryHoverForegroundColor)) 532 { 533 <tr> 534 <td>@Translate("Foreground")</td> 535 <td>@GetColorSquare(buttonSecondaryHoverForegroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonSecondaryHoverForegroundColor');">@buttonSecondaryHoverForegroundColor</a></td> 536 </tr> 537 } 538 @if (!string.IsNullOrEmpty(buttonSecondaryHoverBackgroundColor)) 539 { 540 <tr> 541 <td>@Translate("Background")</td> 542 <td>@GetColorSquare(buttonSecondaryHoverBackgroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonSecondaryHoverBackgroundColor');">@buttonSecondaryHoverBackgroundColor</a></td> 543 </tr> 544 } 545 @if (!string.IsNullOrEmpty(buttonSecondaryHoverBorderColor)) 546 { 547 <tr> 548 <td>@Translate("Border")</td> 549 <td>@GetColorSquare(buttonSecondaryHoverBorderColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonSecondaryHoverBorderColor');">@buttonSecondaryHoverBorderColor</a></td> 550 </tr> 551 } 552 @if (!string.IsNullOrEmpty(accessibilityOutlineColor)) 553 { 554 <tr> 555 <td>@Translate("Focus outline")</td> 556 <td>@GetColorSquare(accessibilityOutlineColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@accessibilityOutlineColor');">@accessibilityOutlineColor</a></td> 557 </tr> 558 } 559 </table> 560 </div> 561 <div class="g-col-12 g-col-lg-3"> 562 <table class="table table-borderless table-sm w-100"> 563 <thead> 564 <tr> 565 <th colspan="2" class="fw-bold">@Translate("Link button")</th> 566 </tr> 567 </thead> 568 <tr> 569 <td>@Translate("Link color")</td> 570 <td>@GetColorSquare(buttonLinkColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonLinkColor');">@buttonLinkColor</a></td> 571 </tr> 572 <thead> 573 <tr> 574 <th colspan="2" class="fw-bold">@Translate("Link button hover")</th> 575 </tr> 576 </thead> 577 @if (!string.IsNullOrEmpty(buttonLinkHoverColor)) 578 { 579 <tr> 580 <td>@Translate("Link hover color")</td> 581 <td>@GetColorSquare(buttonLinkHoverColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonLinkHoverColor');">@buttonLinkHoverColor</a></td> 582 </tr> 583 } 584 585 @if (!string.IsNullOrEmpty(accessibilityOutlineColor)) 586 { 587 <tr> 588 <td>@Translate("Focus outline")</td> 589 <td>@GetColorSquare(accessibilityOutlineColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@accessibilityOutlineColor');">@accessibilityOutlineColor</a></td> 590 </tr> 591 } 592 </table> 593 </div> 594 <div class="g-col-12 g-col-lg-3"> 595 <table class="table table-borderless table-sm w-100"> 596 <tr> 597 <td class="fw-bold">@Translate("Implementation")</td> 598 </tr> 599 <tr> 600 <td> 601 @{ 602 string implementation = $"<div class=\"theme {themeClassName}\"></div>"; 603 } 604 <div class="text-muted"> 605 <code class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@themeClassName');"> 606 @Dynamicweb.Core.Encoders.HtmlEncoder.HtmlEncode(implementation) 607 </code> 608 </div> 609 </td> 610 </tr> 611 </table> 612 </div> 613 @{ 614 bool hasUsageData = Converter.ToBoolean(Dynamicweb.Context.Current.Request["auditUsages"]); 615 if (hasUsageData) 616 { 617 var themeUsage = GetThemeUsageById(themeClassName); 618 int allUsages = themeUsage?.AllUsages ?? 0; 619 string buttonAttributes = allUsages > 0 ? $"data-bs-toggle=\"modal\" data-bs-target=\"#themeUsage_{Model.ID}\"" : string.Empty; 620 string badgeStyle = allUsages > 0 ? "bg-success" : "bg-danger"; 621 622 <div class="g-col-12 g-col-lg-9 position-relative"> 623 <button type="button" class="btn btn-primary btn-sm position-absolute end-0" @buttonAttributes> 624 Usages 625 <span class="position-absolute top-0 start-100 translate-middle badge rounded-pill text-white @badgeStyle">@allUsages</span> 626 </button> 627 628 @if (allUsages > 0) 629 { 630 int websiteUsages = themeUsage?.WebsiteUsages.Count ?? 0; 631 int pageUsages = themeUsage?.PageUsages.Count ?? 0; 632 int pagePropertyUsages = themeUsage?.PagePropertyUsages.Count ?? 0; 633 int gridRowUsages = themeUsage?.GridRowUsages.Count ?? 0; 634 int paragraphUsages = themeUsage?.ParagraphUsages.Count ?? 0; 635 636 <!-- Modal --> 637 <div class="modal fade" id="themeUsage_@(Model.ID)" tabindex="-1" aria-labelledby="usagesModelLabel" aria-hidden="true"> 638 <div class="modal-dialog modal-xl modal-dialog-centered modal-dialog-scrollable"> 639 <div class="modal-content"> 640 <div class="modal-header"> 641 <h5 class="modal-title" id="usagesModelLabel">@allUsages Usages of '@(themeName)' (@(themeClassName))</h5> 642 <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> 643 </div> 644 <div class="modal-body"> 645 <div class="accordion" id="accordionWrapper"> 646 @if(websiteUsages > 0) 647 { 648 <div class="accordion-item"> 649 <h2 class="accordion-header" id="headingWebsites"> 650 <button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#collapseWebsites" aria-expanded="true" aria-controls="collapseWebsites"> 651 <span class="pe-2">Websites</span><span class="badge rounded-pill bg-secondary text-light">@websiteUsages</span> 652 </button> 653 </h2> 654 <div id="collapseWebsites" class="accordion-collapse collapse show" aria-labelledby="headingWebsites" data-bs-parent="#accordionWrapper"> 655 <div class="accordion-body"> 656 <ul> 657 @foreach (var usage in themeUsage.WebsiteUsages) 658 { 659 var website = Dynamicweb.Content.Services.Areas.GetArea(usage); 660 <li><span class="fw-bold">@website.Name</span>@($" (ID: {usage})")</li> 661 } 662 </ul> 663 </div> 664 </div> 665 </div> 666 } 667 @if (pageUsages > 0) 668 { 669 var pages = Dynamicweb.Content.Services.Pages.GetPages(themeUsage.PageUsages.ToArray()); 670 671 <div class="accordion-item"> 672 <h2 class="accordion-header" id="headingPages"> 673 <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapsePages" aria-expanded="false" aria-controls="collapsePages"> 674 <span class="pe-2">Pages</span><span class="badge rounded-pill bg-secondary text-light">@pageUsages</span> 675 </button> 676 </h2> 677 <div id="collapsePages" class="accordion-collapse collapse" aria-labelledby="headingPages" data-bs-parent="#accordionWrapper"> 678 <div class="accordion-body"> 679 <ul> 680 @foreach (var usage in themeUsage.PageUsages) 681 { 682 <li><span class="fw-bold">@pages.FirstOrDefault(p => p.ID == usage).GetDisplayName()</span>@($" (ID: {usage})")</li> 683 } 684 </ul> 685 </div> 686 </div> 687 </div> 688 } 689 @if (pagePropertyUsages > 0) 690 { 691 var pages = Dynamicweb.Content.Services.Pages.GetPages(themeUsage.PageUsages.ToArray()); 692 693 <div class="accordion-item"> 694 <h2 class="accordion-header" id="headingPageProperties"> 695 <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapsePageProperties" aria-expanded="false" aria-controls="collapsePageProperties"> 696 <span class="pe-2">Page Properties</span><span class="badge rounded-pill bg-secondary text-light">@pagePropertyUsages</span> 697 </button> 698 </h2> 699 <div id="collapsePageProperties" class="accordion-collapse collapse" aria-labelledby="headingPageProperties" data-bs-parent="#accordionWrapper"> 700 <div class="accordion-body"> 701 <ul> 702 @foreach (var usage in themeUsage.PagePropertyUsages) 703 { 704 <li><span class="fw-bold">@pages.FirstOrDefault(p => p.ID == usage).GetDisplayName()</span>@($" (ID: {usage})")</li> 705 } 706 </ul> 707 </div> 708 </div> 709 </div> 710 } 711 @if (gridRowUsages > 0) 712 { 713 var rows = Dynamicweb.Content.Services.Grids.GetGridRows().Where(r => themeUsage.GridRowUsages.Contains(r.ID)).ToList(); 714 715 <div class="accordion-item"> 716 <h2 class="accordion-header" id="headingRows"> 717 <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseRows" aria-expanded="false" aria-controls="collapseRows"> 718 <span class="pe-2">Rows</span><span class="badge rounded-pill bg-secondary text-light">@gridRowUsages</span> 719 </button> 720 </h2> 721 <div id="collapseRows" class="accordion-collapse collapse" aria-labelledby="headingRows" data-bs-parent="#accordionWrapper"> 722 <div class="accordion-body"> 723 <ul> 724 @foreach (var usage in themeUsage.GridRowUsages) 725 { 726 var row = rows.FirstOrDefault(r => r.ID == usage); 727 var page = Dynamicweb.Content.Services.Pages.GetPage(row.PageId); 728 <li>Page: <span class="fw-bold">@(page.GetDisplayName())</span>@($"( ID: {page.ID}) - Row: ")<span class="fw-bold">@(row.DefinitionId)</span>@($" (ID: {usage})")</li> 729 } 730 </ul> 731 </div> 732 </div> 733 </div> 734 } 735 @if (paragraphUsages > 0) 736 { 737 var paragraphs = Dynamicweb.Content.Services.Paragraphs.GetParagraphs().Where(p => themeUsage.ParagraphUsages.Contains(p.ID)).ToList(); 738 739 <div class="accordion-item"> 740 <h2 class="accordion-header" id="headingParagraphs"> 741 <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseParagraphs" aria-expanded="false" aria-controls="collapseParagraphs"> 742 <span class="pe-2">Paragraphs</span><span class="badge rounded-pill bg-secondary text-light">@paragraphUsages</span> 743 </button> 744 </h2> 745 <div id="collapseParagraphs" class="accordion-collapse collapse" aria-labelledby="headingParagraphs" data-bs-parent="#accordionWrapper"> 746 <div class="accordion-body"> 747 <ul> 748 @foreach (var usage in themeUsage.ParagraphUsages) 749 { 750 var paragraph = paragraphs.FirstOrDefault(p => p.ID == usage); 751 var page = Dynamicweb.Content.Services.Pages.GetPage(paragraph.PageID); 752 <li>Page: <span class="fw-bold">@(page.GetDisplayName())</span>@($"( ID: {page.ID}) - Paragraph: ")<span class="fw-bold">@paragraph.Header</span>@($" (ID: {usage})")</li> 753 } 754 </ul> 755 </div> 756 </div> 757 </div> 758 } 759 </div> 760 </div> 761 </div> 762 </div> 763 </div> 764 } 765 </div> 766 } 767 } 768 </div> 769 </div> 770 } 771 <div class="g-col-12"> 772 <hr /> 773 </div> 774
Error executing template "Designs/Swift/Paragraph/Swift_Theme.cshtml" System.Data.SqlClient.SqlException (0x80131904): STRING_AGG aggregation result exceeded the limit of 8000 bytes. Use LOB types to avoid result truncation. at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction) at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose) at System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady) at System.Data.SqlClient.SqlDataReader.TryConsumeMetaData() at System.Data.SqlClient.SqlDataReader.get_MetaData() at System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString, Boolean isInternal, Boolean forDescribeParameterEncryption, Boolean shouldCacheForAlwaysEncrypted) at System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async, Int32 timeout, Task& task, Boolean asyncWrite, Boolean inRetry, SqlDataReader ds, Boolean describeParameterEncryptionRequest) at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, TaskCompletionSource`1 completion, Int32 timeout, Task& task, Boolean& usedCache, Boolean asyncWrite, Boolean inRetry) at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method) at System.Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior behavior, String method) at Dynamicweb.Data.Database.CreateDataReader(IDbCommand command, CommandBehavior behavior) at Dynamicweb.Data.Database.CreateDataReader(String sql, IDbConnection connection, IDbTransaction transaction, CommandBehavior behavior, Int32 commandTimeout, Dictionary`2 sqlParams) at Dynamicweb.Data.Database.CreateDataReader(String sql, IDbConnection connection, IDbTransaction transaction, Int32 commandTimeout, Dictionary`2 sqlParams) at Dynamicweb.Data.Database.CreateDataReader(String sql) at CompiledRazorTemplates.Dynamic.RazorEngine_8e3f1b11eb0041ceb2ca487c2be837e6.UpdateThemeUsages(String sqlQuery, List`1 themeUsages) in E:\Dynamicweb.net\Solutions\Dynamicweb\dw2022.cloud.dynamicweb-cms.com\Files\Templates\Designs\Swift\Paragraph\Swift_Theme.cshtml:line 202 at CompiledRazorTemplates.Dynamic.RazorEngine_8e3f1b11eb0041ceb2ca487c2be837e6.GetAllThemeUsages() in E:\Dynamicweb.net\Solutions\Dynamicweb\dw2022.cloud.dynamicweb-cms.com\Files\Templates\Designs\Swift\Paragraph\Swift_Theme.cshtml:line 184 at CompiledRazorTemplates.Dynamic.RazorEngine_8e3f1b11eb0041ceb2ca487c2be837e6.GetThemeUsageById(String themeId) in E:\Dynamicweb.net\Solutions\Dynamicweb\dw2022.cloud.dynamicweb-cms.com\Files\Templates\Designs\Swift\Paragraph\Swift_Theme.cshtml:line 238 at CompiledRazorTemplates.Dynamic.RazorEngine_8e3f1b11eb0041ceb2ca487c2be837e6.Execute() in E:\Dynamicweb.net\Solutions\Dynamicweb\dw2022.cloud.dynamicweb-cms.com\Files\Templates\Designs\Swift\Paragraph\Swift_Theme.cshtml:line 617 at RazorEngine.Templating.TemplateBase.RazorEngine.Templating.ITemplate.Run(ExecuteContext context, TextWriter reader) at RazorEngine.Templating.RazorEngineService.RunCompile(ITemplateKey key, TextWriter writer, Type modelType, Object model, DynamicViewBag viewBag) at RazorEngine.Templating.RazorEngineServiceExtensions.<>c__DisplayClass16_0.<RunCompile>b__0(TextWriter writer) at RazorEngine.Templating.RazorEngineServiceExtensions.WithWriter(Action`1 withWriter) at Dynamicweb.Rendering.RazorTemplateRenderingProvider.Render(Template template) at Dynamicweb.Rendering.TemplateRenderingService.Render(Template template) at Dynamicweb.Rendering.Template.RenderRazorTemplate() ClientConnectionId:b42d1cec-597c-4eed-bdc2-e0762a41101a Error Number:9829,State:1,Class:16
1 @inherits Dynamicweb.Rendering.ViewModelTemplate<Dynamicweb.Frontend.ParagraphViewModel> 2 @using System.Globalization 3 @using System.Drawing 4 @using Dynamicweb.Core 5 6 @functions{ 7 // Get Hex Color from color picker and translate to RGB color 8 public static string HexToRGB(string hexString) 9 { 10 if (hexString.Equals("none") || string.IsNullOrEmpty(hexString)) 11 return hexString; 12 13 //replace # occurences 14 if (hexString.IndexOf('#') != -1) 15 hexString = hexString.Replace("#", ""); 16 try 17 { 18 int r, g, b = 0; 19 r = int.Parse(hexString.Substring(0, 2), NumberStyles.AllowHexSpecifier); 20 g = int.Parse(hexString.Substring(2, 2), NumberStyles.AllowHexSpecifier); 21 b = int.Parse(hexString.Substring(4, 2), NumberStyles.AllowHexSpecifier); 22 23 string rgb = r + "," + g + "," + b; 24 return rgb; 25 } 26 catch (System.Exception) 27 { 28 return hexString; 29 } 30 } 31 32 public static string GetColorSquare(string hex) 33 { 34 return $"<div class=\"swift-checkered d-inline-block me-1\" style=\"height:1.25rem;width:1.25rem;\"><div style=\"background-color: {hex};border:.0625rem solid grey\" class=\"w-100 h-100\"></div></div>"; 35 } 36 37 public class HSL 38 { 39 public double h { get; set; } 40 public double s { get; set; } 41 public double l { get; set; } 42 } 43 44 //Convert HEX to HSL 45 public static HSL HexToHsl(string hexString) 46 { 47 System.Drawing.Color color = System.Drawing.ColorTranslator.FromHtml(hexString); 48 49 float _R = (color.R / 255f); 50 float _G = (color.G / 255f); 51 float _B = (color.B / 255f); 52 53 float _Min = Math.Min(Math.Min(_R, _G), _B); 54 float _Max = Math.Max(Math.Max(_R, _G), _B); 55 float _Delta = _Max - _Min; 56 57 float S = 0; 58 float L = (float)((_Max + _Min) / 2.0f); 59 60 if (_Delta != 0) 61 { 62 if (L < 0.5f) 63 { 64 S = (float)(_Delta / (_Max + _Min)); 65 } 66 else 67 { 68 S = (float)(_Delta / (2.0f - _Max - _Min)); 69 } 70 } 71 72 HSL hsl = new HSL(); 73 hsl.h = Math.Round(color.GetHue(), 2); 74 hsl.s = Math.Round(S, 2) * 100; 75 hsl.l = Math.Round(L, 2) * 100; 76 77 return hsl; 78 } 79 80 //Find contrast color (white, black) 81 public static Color GetContrastColor(string hexString) 82 { 83 System.Drawing.Color bg = System.Drawing.ColorTranslator.FromHtml(hexString); 84 85 int nThreshold = 105; 86 int bgDelta = Convert.ToInt32((bg.R * 0.299) + (bg.G * 0.587) + 87 (bg.B * 0.114)); 88 89 Color foreColor = (255 - bgDelta < nThreshold) ? Color.Black : Color.White; 90 return foreColor; 91 } 92 93 public string GetColorVariation(string hexString) 94 { 95 var contrast = GetContrastColor(hexString); 96 HSL currentHslColor = HexToHsl(hexString); 97 HSL variantHslColor = currentHslColor; 98 99 if (contrast == Color.Black) 100 { 101 variantHslColor.l = 85; //The background is dark - Color should be light 102 } 103 else 104 { 105 variantHslColor.l = 40; //The background is light - Color should be less light 106 } 107 108 //Color is very light 109 if (currentHslColor.l > 85) 110 { 111 variantHslColor.l = 95; 112 } 113 114 string colorString = variantHslColor.h + ", " + variantHslColor.s + "%, " + variantHslColor.l + "%"; 115 return colorString; 116 } 117 118 private class ThemeDatabaseUsage 119 { 120 public string TableName { get; set; } 121 public string ColumnName { get; set; } 122 } 123 124 private class ThemeUsage 125 { 126 public string Id { get; set; } 127 public List<int> WebsiteUsages { get; set; } = new List<int>(); 128 public List<int> PageUsages { get; set; } = new List<int>(); 129 public List<int> PagePropertyUsages { get; set; } = new List<int>(); 130 public List<int> GridRowUsages { get; set; } = new List<int>(); 131 public List<int> ParagraphUsages { get; set; } = new List<int>(); 132 public int AllUsages { get; set; } = 0; 133 } 134 135 private List<ThemeDatabaseUsage> GetThemeColumnsFromSchema() 136 { 137 string cacheKey = "ThemesFromDatabase"; 138 if (Dynamicweb.Context.Current.Items.Contains(cacheKey)) 139 { 140 return (List<ThemeDatabaseUsage>)Dynamicweb.Context.Current.Items[cacheKey]; 141 } 142 var schema = Dynamicweb.Data.Database.CreateDataReader("SELECT table_name, column_name FROM information_schema.columns WHERE column_name LIKE '%Theme%'"); 143 144 var rawData = new List<ThemeDatabaseUsage>(); 145 while (schema.Read()) { 146 rawData.Add(new ThemeDatabaseUsage {TableName = schema["table_name"].ToString(), ColumnName = schema["column_name"].ToString() }); 147 } 148 Dynamicweb.Context.Current.Items[cacheKey] = rawData; 149 return rawData; 150 } 151 152 private List<ThemeUsage> GetAllThemeUsages() 153 { 154 string cacheKey = "ThemeUsages"; 155 if (Dynamicweb.Context.Current.Items.Contains(cacheKey)) 156 { 157 return (List<ThemeUsage>)Dynamicweb.Context.Current.Items[cacheKey]; 158 } 159 160 var rawData = GetThemeColumnsFromSchema(); 161 var themeUsages = new List<ThemeUsage>(); 162 163 var sqlQuery = ""; 164 foreach (var row in rawData) 165 { 166 if (!string.IsNullOrEmpty(sqlQuery)) { sqlQuery += " UNION ALL "; } 167 sqlQuery += $"SELECT '{row.TableName}' AS TableName, '{row.ColumnName}' AS ColumnName, {row.ColumnName} AS ColumnValue, Id, AreaId, Page.PageId, PageProperties.PageId as 'PagePropertiesId', GridRowId, ParagraphId" + 168 $" FROM [{row.TableName}]" + 169 $" LEFT JOIN Area ON AreaItemType = '{row.TableName.Replace("ItemType_","")}' AND AreaItemId = Id" + 170 $" LEFT JOIN Page ON PageItemType = '{row.TableName.Replace("ItemType_","")}' AND PageItemId = Id" + 171 $" LEFT JOIN Page as PageProperties ON AreaItemTypePageProperty = '{row.TableName.Replace("ItemType_","")}' AND PageProperties.PagePropertyItemId = Id" + 172 $" LEFT JOIN GridRow ON GridRowItemType = '{row.TableName.Replace("ItemType_","")}' AND GridRowItemId = Id" + 173 $" LEFT JOIN Paragraph ON ParagraphItemType = '{row.TableName.Replace("ItemType_","")}' AND ParagraphItemId = Id" + 174 $" WHERE {row.ColumnName} != '' AND {row.ColumnName} IS NOT NULL" + 175 $" AND (AreaId IS NULL OR AreaId = {Pageview.AreaID})" + 176 $" AND (Page.PageId IS NULL OR Page.PageAreaId = {Pageview.AreaID})" + 177 $" AND (PageProperties.PageId IS NULL OR PageProperties.PageAreaId = {Pageview.AreaID})" + 178 $" AND (GridRowId IS NULL OR GridRowPageId IN (SELECT value From string_split(@pageIds, ',')))" + 179 $" AND (ParagraphId IS NULL OR ParagraphPageId IN (SELECT value From string_split(@pageIds, ',')))"; 180 181 var maxMsSqlServerCharLimit = 60000; 182 if (sqlQuery.Length > maxMsSqlServerCharLimit) 183 { 184 UpdateThemeUsages(sqlQuery, themeUsages); 185 sqlQuery = ""; 186 } 187 } 188 189 if (!string.IsNullOrEmpty(sqlQuery)) 190 { 191 UpdateThemeUsages(sqlQuery, themeUsages); 192 } 193 UpdateAllUsages(themeUsages); 194 195 Dynamicweb.Context.Current.Items[cacheKey] = themeUsages; 196 return themeUsages; 197 } 198 199 private void UpdateThemeUsages(string sqlQuery, List<ThemeUsage> themeUsages) 200 { 201 sqlQuery = $"DECLARE @pageIds NVARCHAR(max) = (SELECT STRING_AGG(PageId,',') FROM Page WHERE PageAreaId = {Pageview.AreaID}) " + sqlQuery; 202 var rawData = Dynamicweb.Data.Database.CreateDataReader(sqlQuery); 203 while (rawData.Read()) 204 { 205 var themeId = rawData["ColumnValue"].ToString(); 206 var themeUsageExists = themeUsages.FirstOrDefault(t => t.Id == themeId) != null; 207 if (!themeUsageExists) 208 { 209 themeUsages.Add(new ThemeUsage { Id = themeId }); 210 } 211 212 var themeUsage = themeUsages.FirstOrDefault(t => t.Id == themeId); 213 if (themeUsage == null) continue; 214 215 if (Converter.ToInt32(rawData["AreaId"].ToString()) > 0) { themeUsage.WebsiteUsages.Add(Converter.ToInt32(rawData["AreaId"].ToString())); } 216 if (Converter.ToInt32(rawData["PageId"].ToString()) > 0) { themeUsage.PageUsages.Add(Converter.ToInt32(rawData["PageId"].ToString())); } 217 if (Converter.ToInt32(rawData["PagePropertiesId"].ToString()) > 0) { themeUsage.PagePropertyUsages.Add(Converter.ToInt32(rawData["PagePropertiesId"].ToString())); } 218 if (Converter.ToInt32(rawData["GridRowId"].ToString()) > 0) { themeUsage.GridRowUsages.Add(Converter.ToInt32(rawData["GridRowId"].ToString())); } 219 if (Converter.ToInt32(rawData["ParagraphId"].ToString()) > 0) { themeUsage.ParagraphUsages.Add(Converter.ToInt32(rawData["ParagraphId"].ToString())); } 220 } 221 } 222 223 private void UpdateAllUsages(List<ThemeUsage> themeUsages) 224 { 225 foreach (var themeUsage in themeUsages) 226 { 227 int websiteUsages = themeUsage?.WebsiteUsages.Count ?? 0; 228 int pageUsages = themeUsage?.PageUsages.Count ?? 0; 229 int pagePropertyUsages = themeUsage?.PagePropertyUsages.Count ?? 0; 230 int gridRowUsages = themeUsage?.GridRowUsages.Count ?? 0; 231 int paragraphUsages = themeUsage?.ParagraphUsages.Count ?? 0; 232 themeUsage.AllUsages = websiteUsages + pageUsages + pagePropertyUsages + gridRowUsages + paragraphUsages; 233 } 234 } 235 236 private ThemeUsage GetThemeUsageById(string themeId) 237 { 238 var themeUsages = GetAllThemeUsages(); 239 return themeUsages.FirstOrDefault(t => t.Id == themeId); 240 } 241 242 } 243 244 @{ 245 string themeName = !string.IsNullOrWhiteSpace(Model.Item.GetString("Name")) ? Model.Item.GetString("Name") : "Default"; 246 string themeClassName = !string.IsNullOrWhiteSpace(Model.Item.GetString("CSSClassName")) ? Model.Item.GetString("CSSClassName").Replace(" ", "").Trim().ToLower() : ""; 247 248 //Theme colors 249 string foregroundColor = Model.Item.GetString("ForegroundColor", "currentColor"); 250 string backgroundColor = Model.Item.GetString("BackgroundColor", "transparent"); 251 string accentColor = Model.Item.GetString("accentColor", "currentColor"); 252 string borderColor = Model.Item.GetString("BorderColor", "transparent"); 253 254 //Primary button 255 string buttonPrimaryForegroundColor = Model.Item.GetString("ButtonPrimaryForegroundColor", "currentColor"); 256 string buttonPrimaryBackgroundColor = Model.Item.GetString("ButtonPrimaryBackgroundColor", "transparent"); 257 string buttonPrimaryBorderColor = Model.Item.GetString("ButtonPrimaryBorderColor", "transparent"); 258 259 string buttonPrimaryHoverBackgroundColorAuto = "transparent"; 260 if (buttonPrimaryBackgroundColor != "transparent") 261 { 262 buttonPrimaryHoverBackgroundColorAuto = "hsl(" + GetColorVariation(buttonPrimaryBackgroundColor) + ")"; 263 } 264 string buttonPrimaryHoverForegroundColor = Model.Item.GetString("ButtonPrimaryHoverForegroundColor", buttonPrimaryForegroundColor); 265 string buttonPrimaryHoverBackgroundColor = Model.Item.GetString("ButtonPrimaryHoverBackgroundColor", buttonPrimaryHoverBackgroundColorAuto); 266 string buttonPrimaryHoverBorderColor = Model.Item.GetString("ButtonPrimaryHoverBorderColor", buttonPrimaryBorderColor); 267 268 //Secondary buton 269 string buttonSecondaryForegroundColor = Model.Item.GetString("ButtonSecondaryForegroundColor", "currentColor"); 270 string buttonSecondaryBackgroundColor = Model.Item.GetString("ButtonSecondaryBackgroundColor", "transparent"); 271 string buttonSecondaryBorderColor = Model.Item.GetString("ButtonSecondaryBorderColor", "transparent"); 272 273 string buttonSecondaryHoverBackgroundColorAuto = "transparent"; 274 if (buttonSecondaryBackgroundColor != "transparent") 275 { 276 buttonSecondaryHoverBackgroundColorAuto = "hsl(" + GetColorVariation(buttonSecondaryBackgroundColor) + ")"; 277 } 278 string buttonSecondaryHoverForegroundColor = Model.Item.GetString("ButtonSecondaryHoverForegroundColor", buttonSecondaryForegroundColor); 279 string buttonSecondaryHoverBackgroundColor = Model.Item.GetString("ButtonSecondaryHoverBackgroundColor", buttonSecondaryHoverBackgroundColorAuto); 280 string buttonSecondaryHoverBorderColor = Model.Item.GetString("ButtonSecondaryHoverBorderColor", buttonSecondaryBorderColor); 281 282 //Link buton 283 string buttonLinkColor = Model.Item.GetString("ButtonLinkColor", "currentColor"); 284 string buttonLinkHoverColorAuto = "currentColor"; 285 if (buttonLinkColor != "currentColor") 286 { 287 buttonLinkHoverColorAuto = "hsl(" + GetColorVariation(buttonLinkColor) + ")"; 288 } 289 string buttonLinkHoverColor = Model.Item.GetString("ButtonLinkHoverColor", buttonLinkHoverColorAuto); 290 291 string accessibilityOutlineColor = Model.Item.GetString("OutlineColor") != null ? Model.Item.GetString("OutlineColor") : ""; 292 293 if (!string.IsNullOrEmpty(themeClassName)) 294 { 295 var sb = new System.Text.StringBuilder(); 296 297 sb.AppendLine("." + themeClassName + "{"); 298 if (!string.IsNullOrEmpty(foregroundColor)) 299 { 300 sb.AppendLine($"--swift-foreground-color: {foregroundColor};"); 301 sb.AppendLine($"--swift-foreground-color-rgb: {HexToRGB(foregroundColor)};"); 302 } 303 if (!string.IsNullOrEmpty(backgroundColor)) 304 { 305 sb.AppendLine($"--swift-background-color: {backgroundColor};"); 306 sb.AppendLine($"--swift-background-color-rgb: {HexToRGB(backgroundColor)};"); 307 } 308 if (!string.IsNullOrEmpty(accentColor)) 309 { 310 sb.AppendLine($"--swift-accent-color: {accentColor};"); 311 sb.AppendLine($"--swift-accent-color-rgb: {HexToRGB(accentColor)};"); 312 } 313 if (!string.IsNullOrEmpty(borderColor)) 314 { 315 sb.AppendLine($"--swift-border-color: {borderColor};"); 316 sb.AppendLine($"--swift-border-color-rgb: {HexToRGB(borderColor)};"); 317 } 318 319 if (!string.IsNullOrEmpty(buttonPrimaryBackgroundColor)) 320 { 321 sb.AppendLine($"--swift-button-primary-background-color: {buttonPrimaryBackgroundColor};"); 322 sb.AppendLine($"--swift-button-primary-background-color-rgb: {HexToRGB(buttonPrimaryBackgroundColor)};"); 323 } 324 if (!string.IsNullOrEmpty(buttonPrimaryForegroundColor)) 325 { 326 sb.AppendLine($"--swift-button-primary-foreground-color: {buttonPrimaryForegroundColor};"); 327 sb.AppendLine($"--swift-button-primary-foreground-color-rgb: {HexToRGB(buttonPrimaryForegroundColor)};"); 328 } 329 if (!string.IsNullOrEmpty(buttonPrimaryBorderColor)) 330 { 331 sb.AppendLine($"--swift-button-primary-border-color: {buttonPrimaryBorderColor};"); 332 sb.AppendLine($"--swift-button-primary-border-color-rgb: {HexToRGB(buttonPrimaryBorderColor)};"); 333 } 334 335 if (!string.IsNullOrEmpty(buttonPrimaryHoverBackgroundColor)) 336 { 337 sb.AppendLine($"--swift-button-primary-hover-background-color: {buttonPrimaryHoverBackgroundColor};"); 338 sb.AppendLine($"--swift-button-primary-hover-background-color-rgb: {HexToRGB(buttonPrimaryHoverBackgroundColor)};"); 339 } 340 if (!string.IsNullOrEmpty(buttonPrimaryHoverForegroundColor)) 341 { 342 sb.AppendLine($"--swift-button-primary-hover-foreground-color: {buttonPrimaryHoverForegroundColor};"); 343 sb.AppendLine($"--swift-button-primary-hover-foreground-color-rgb: {HexToRGB(buttonPrimaryHoverForegroundColor)};"); 344 } 345 if (!string.IsNullOrEmpty(buttonPrimaryHoverBorderColor)) 346 { 347 sb.AppendLine($"--swift-button-primary-hover-border-color: {buttonPrimaryHoverBorderColor};"); 348 sb.AppendLine($"--swift-button-primary-hover-border-color-rgb: {HexToRGB(buttonPrimaryHoverBorderColor)};"); 349 } 350 351 if (!string.IsNullOrEmpty(buttonSecondaryBackgroundColor)) 352 { 353 sb.AppendLine($"--swift-button-secondary-background-color: {buttonSecondaryBackgroundColor};"); 354 sb.AppendLine($"--swift-button-secondary-background-color-rgb: {HexToRGB(buttonSecondaryBackgroundColor)};"); 355 } 356 if (!string.IsNullOrEmpty(buttonSecondaryForegroundColor)) 357 { 358 sb.AppendLine($"--swift-button-secondary-foreground-color: {buttonSecondaryForegroundColor};"); 359 sb.AppendLine($"--swift-button-secondary-foreground-color-rgb: {HexToRGB(buttonSecondaryForegroundColor)};"); 360 } 361 if (!string.IsNullOrEmpty(buttonSecondaryBorderColor)) 362 { 363 sb.AppendLine($"--swift-button-secondary-border-color: {buttonSecondaryBorderColor};"); 364 sb.AppendLine($"--swift-button-secondary-border-color-rgb: {HexToRGB(buttonSecondaryBorderColor)};"); 365 } 366 if (!string.IsNullOrEmpty(buttonSecondaryHoverBackgroundColor)) 367 { 368 sb.AppendLine($"--swift-button-secondary-hover-background-color: {buttonSecondaryHoverBackgroundColor};"); 369 sb.AppendLine($"--swift-button-secondary-hover-background-color-rgb: {HexToRGB(buttonSecondaryHoverBackgroundColor)};"); 370 } 371 if (!string.IsNullOrEmpty(buttonSecondaryHoverForegroundColor)) 372 { 373 sb.AppendLine($"--swift-button-secondary-hover-foreground-color: {buttonSecondaryHoverForegroundColor};"); 374 sb.AppendLine($"--swift-button-secondary-hover-foreground-color-rgb: {HexToRGB(buttonSecondaryHoverForegroundColor)};"); 375 } 376 if (!string.IsNullOrEmpty(buttonSecondaryHoverBorderColor)) 377 { 378 sb.AppendLine($"--swift-button-secondary-hover-border-color: {buttonSecondaryHoverBorderColor};"); 379 sb.AppendLine($"--swift-button-secondary-hover-border-color-rgb: {HexToRGB(buttonSecondaryHoverBorderColor)};"); 380 } 381 if (!string.IsNullOrEmpty(buttonLinkColor)) 382 { 383 sb.AppendLine($"--swift-button-link-color: {buttonLinkColor};"); 384 sb.AppendLine($"--swift-button-link-color-rgb: {HexToRGB(buttonLinkColor)};"); 385 } 386 if (!string.IsNullOrEmpty(buttonLinkHoverColor)) 387 { 388 sb.AppendLine($"--swift-button-link-hover-color: {buttonLinkHoverColor};"); 389 sb.AppendLine($"--swift-button-link-hover-color-rgb: {HexToRGB(buttonLinkHoverColor)};"); 390 } 391 if (!string.IsNullOrEmpty(accessibilityOutlineColor)) 392 { 393 sb.AppendLine($"--swift-a11y-outline-color: {accessibilityOutlineColor};"); 394 sb.AppendLine($"--swift-a11y-outline-color-rgb: {HexToRGB(accessibilityOutlineColor)};"); 395 } 396 sb.AppendLine("}"); 397 398 Dynamicweb.Core.Helpers.TextFileHelper.WriteTextFile(sb.ToString() + Environment.NewLine, Dynamicweb.Context.Current.Server.MapPath($"/Files/Templates/Designs/Swift/_parsed/Swift_css/Swift_theme_styles_{Dynamicweb.Content.Services.Pages.GetPage(Model.PageID).AreaId}.tmp"), true); 399 } 400 } 401 402 @if (themeClassName != "") 403 { 404 string iconPath = "/Files/Templates/Designs/Swift/Assets/icons/"; 405 406 <div class="g-col-12 g-col-lg-4"> 407 <div class="swift-checkered p-3"> 408 <div class="theme-option theme @themeClassName p-lg-3"> 409 <div class="mb-2 pb-1 border-bottom d-flex align-items-center"> 410 <span class="icon-3 me-2"> 411 @ReadFile(iconPath + "sun.svg") 412 </span> 413 <h4 class="m-0 p-0">@themeName</h4> 414 </div> 415 <div class="d-flex flex-column gap-1 mb-2"> 416 <p class="mb-0">This is the body text of the theme.</p> 417 <p class="mb-0" style="color: var(--swift-accent-color)">This is the accent color of the theme.</p> 418 </div> 419 <div> 420 <button class="btn btn-primary me-1">Primary</button> 421 <button class="btn btn-secondary">Secondary</button> 422 <button class="btn btn-link">Link</button> 423 </div> 424 </div> 425 </div> 426 </div> 427 <div class="g-col-12 g-col-lg-8 mb-4 mb-lg-0"> 428 <div class="grid fs-7"> 429 <div class="g-col-12 g-col-lg-3"> 430 <table class="table table-borderless table-sm w-100"> 431 <thead> 432 <tr> 433 <th colspan="2" class="fw-bold">@Translate("Base")</th> 434 </tr> 435 </thead> 436 <tr> 437 <td>@Translate("Foreground")</td> 438 <td>@GetColorSquare(foregroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@foregroundColor');">@foregroundColor</a></td> 439 </tr> 440 <tr> 441 <td>@Translate("Background")</td> 442 <td>@GetColorSquare(backgroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@backgroundColor');">@backgroundColor</a></td> 443 </tr> 444 <tr> 445 <td>@Translate("Accent")</td> 446 <td>@GetColorSquare(accentColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@accentColor');">@accentColor</a></td> 447 </tr> 448 <tr> 449 <td>@Translate("Border")</td> 450 <td>@GetColorSquare(borderColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@borderColor');">@borderColor</a></td> 451 </tr> 452 </table> 453 </div> 454 <div class="g-col-12 g-col-lg-3"> 455 <table class="table table-borderless table-sm w-100"> 456 <thead> 457 <tr> 458 <th colspan="2" class="fw-bold">@Translate("Primary button")</th> 459 </tr> 460 </thead> 461 <tr> 462 <td>@Translate("Foreground")</td> 463 <td>@GetColorSquare(buttonPrimaryForegroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonPrimaryForegroundColor');">@buttonPrimaryForegroundColor</a></td> 464 </tr> 465 <tr> 466 <td>@Translate("Background")</td> 467 <td>@GetColorSquare(buttonPrimaryBackgroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonPrimaryBackgroundColor');">@buttonPrimaryBackgroundColor</a></td> 468 </tr> 469 @if (!string.IsNullOrEmpty(buttonPrimaryBorderColor)) 470 { 471 <tr> 472 <td>@Translate("Border")</td> 473 <td>@GetColorSquare(buttonPrimaryBorderColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonPrimaryBorderColor');">@buttonPrimaryBorderColor</a></td> 474 </tr> 475 } 476 <thead> 477 <tr> 478 <th colspan="2" class="fw-bold">@Translate("Primary button hover")</th> 479 </tr> 480 </thead> 481 @if (!string.IsNullOrEmpty(buttonPrimaryHoverForegroundColor)) 482 { 483 <tr> 484 <td>@Translate("Foreground")</td> 485 <td>@GetColorSquare(buttonPrimaryHoverForegroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonPrimaryHoverForegroundColor');">@buttonPrimaryHoverForegroundColor</a></td> 486 </tr> 487 } 488 @if (!string.IsNullOrEmpty(buttonPrimaryHoverBackgroundColor)) 489 { 490 <tr> 491 <td>@Translate("Background")</td> 492 <td>@GetColorSquare(buttonPrimaryHoverBackgroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonPrimaryHoverBackgroundColor');">@buttonPrimaryHoverBackgroundColor</a></td> 493 </tr> 494 } 495 @if (!string.IsNullOrEmpty(buttonPrimaryHoverBorderColor)) 496 { 497 <tr> 498 <td>@Translate("Border")</td> 499 <td>@GetColorSquare(buttonPrimaryHoverBorderColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonPrimaryHoverBorderColor');">@buttonPrimaryHoverBorderColor</a></td> 500 </tr> 501 } 502 </table> 503 </div> 504 <div class="g-col-12 g-col-lg-3"> 505 <table class="table table-borderless table-sm w-100"> 506 <thead> 507 <tr> 508 <th colspan="2" class="fw-bold">@Translate("Secondary button")</th> 509 </tr> 510 </thead> 511 <tr> 512 <td>@Translate("Foreground")</td> 513 <td>@GetColorSquare(buttonSecondaryForegroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonSecondaryForegroundColor');">@buttonSecondaryForegroundColor</a></td> 514 </tr> 515 <tr> 516 <td>@Translate("Background")</td> 517 <td>@GetColorSquare(buttonSecondaryBackgroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonSecondaryBackgroundColor');">@buttonSecondaryBackgroundColor</a></td> 518 </tr> 519 @if (!string.IsNullOrEmpty(buttonSecondaryBorderColor)) 520 { 521 <tr> 522 <td>@Translate("Border")</td> 523 <td>@GetColorSquare(buttonSecondaryBorderColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonSecondaryBorderColor');">@buttonSecondaryBorderColor</a></td> 524 </tr> 525 } 526 <thead> 527 <tr> 528 <th colspan="2" class="fw-bold">@Translate("Secondary button hover")</th> 529 </tr> 530 </thead> 531 @if (!string.IsNullOrEmpty(buttonSecondaryHoverForegroundColor)) 532 { 533 <tr> 534 <td>@Translate("Foreground")</td> 535 <td>@GetColorSquare(buttonSecondaryHoverForegroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonSecondaryHoverForegroundColor');">@buttonSecondaryHoverForegroundColor</a></td> 536 </tr> 537 } 538 @if (!string.IsNullOrEmpty(buttonSecondaryHoverBackgroundColor)) 539 { 540 <tr> 541 <td>@Translate("Background")</td> 542 <td>@GetColorSquare(buttonSecondaryHoverBackgroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonSecondaryHoverBackgroundColor');">@buttonSecondaryHoverBackgroundColor</a></td> 543 </tr> 544 } 545 @if (!string.IsNullOrEmpty(buttonSecondaryHoverBorderColor)) 546 { 547 <tr> 548 <td>@Translate("Border")</td> 549 <td>@GetColorSquare(buttonSecondaryHoverBorderColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonSecondaryHoverBorderColor');">@buttonSecondaryHoverBorderColor</a></td> 550 </tr> 551 } 552 @if (!string.IsNullOrEmpty(accessibilityOutlineColor)) 553 { 554 <tr> 555 <td>@Translate("Focus outline")</td> 556 <td>@GetColorSquare(accessibilityOutlineColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@accessibilityOutlineColor');">@accessibilityOutlineColor</a></td> 557 </tr> 558 } 559 </table> 560 </div> 561 <div class="g-col-12 g-col-lg-3"> 562 <table class="table table-borderless table-sm w-100"> 563 <thead> 564 <tr> 565 <th colspan="2" class="fw-bold">@Translate("Link button")</th> 566 </tr> 567 </thead> 568 <tr> 569 <td>@Translate("Link color")</td> 570 <td>@GetColorSquare(buttonLinkColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonLinkColor');">@buttonLinkColor</a></td> 571 </tr> 572 <thead> 573 <tr> 574 <th colspan="2" class="fw-bold">@Translate("Link button hover")</th> 575 </tr> 576 </thead> 577 @if (!string.IsNullOrEmpty(buttonLinkHoverColor)) 578 { 579 <tr> 580 <td>@Translate("Link hover color")</td> 581 <td>@GetColorSquare(buttonLinkHoverColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonLinkHoverColor');">@buttonLinkHoverColor</a></td> 582 </tr> 583 } 584 585 @if (!string.IsNullOrEmpty(accessibilityOutlineColor)) 586 { 587 <tr> 588 <td>@Translate("Focus outline")</td> 589 <td>@GetColorSquare(accessibilityOutlineColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@accessibilityOutlineColor');">@accessibilityOutlineColor</a></td> 590 </tr> 591 } 592 </table> 593 </div> 594 <div class="g-col-12 g-col-lg-3"> 595 <table class="table table-borderless table-sm w-100"> 596 <tr> 597 <td class="fw-bold">@Translate("Implementation")</td> 598 </tr> 599 <tr> 600 <td> 601 @{ 602 string implementation = $"<div class=\"theme {themeClassName}\"></div>"; 603 } 604 <div class="text-muted"> 605 <code class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@themeClassName');"> 606 @Dynamicweb.Core.Encoders.HtmlEncoder.HtmlEncode(implementation) 607 </code> 608 </div> 609 </td> 610 </tr> 611 </table> 612 </div> 613 @{ 614 bool hasUsageData = Converter.ToBoolean(Dynamicweb.Context.Current.Request["auditUsages"]); 615 if (hasUsageData) 616 { 617 var themeUsage = GetThemeUsageById(themeClassName); 618 int allUsages = themeUsage?.AllUsages ?? 0; 619 string buttonAttributes = allUsages > 0 ? $"data-bs-toggle=\"modal\" data-bs-target=\"#themeUsage_{Model.ID}\"" : string.Empty; 620 string badgeStyle = allUsages > 0 ? "bg-success" : "bg-danger"; 621 622 <div class="g-col-12 g-col-lg-9 position-relative"> 623 <button type="button" class="btn btn-primary btn-sm position-absolute end-0" @buttonAttributes> 624 Usages 625 <span class="position-absolute top-0 start-100 translate-middle badge rounded-pill text-white @badgeStyle">@allUsages</span> 626 </button> 627 628 @if (allUsages > 0) 629 { 630 int websiteUsages = themeUsage?.WebsiteUsages.Count ?? 0; 631 int pageUsages = themeUsage?.PageUsages.Count ?? 0; 632 int pagePropertyUsages = themeUsage?.PagePropertyUsages.Count ?? 0; 633 int gridRowUsages = themeUsage?.GridRowUsages.Count ?? 0; 634 int paragraphUsages = themeUsage?.ParagraphUsages.Count ?? 0; 635 636 <!-- Modal --> 637 <div class="modal fade" id="themeUsage_@(Model.ID)" tabindex="-1" aria-labelledby="usagesModelLabel" aria-hidden="true"> 638 <div class="modal-dialog modal-xl modal-dialog-centered modal-dialog-scrollable"> 639 <div class="modal-content"> 640 <div class="modal-header"> 641 <h5 class="modal-title" id="usagesModelLabel">@allUsages Usages of '@(themeName)' (@(themeClassName))</h5> 642 <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> 643 </div> 644 <div class="modal-body"> 645 <div class="accordion" id="accordionWrapper"> 646 @if(websiteUsages > 0) 647 { 648 <div class="accordion-item"> 649 <h2 class="accordion-header" id="headingWebsites"> 650 <button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#collapseWebsites" aria-expanded="true" aria-controls="collapseWebsites"> 651 <span class="pe-2">Websites</span><span class="badge rounded-pill bg-secondary text-light">@websiteUsages</span> 652 </button> 653 </h2> 654 <div id="collapseWebsites" class="accordion-collapse collapse show" aria-labelledby="headingWebsites" data-bs-parent="#accordionWrapper"> 655 <div class="accordion-body"> 656 <ul> 657 @foreach (var usage in themeUsage.WebsiteUsages) 658 { 659 var website = Dynamicweb.Content.Services.Areas.GetArea(usage); 660 <li><span class="fw-bold">@website.Name</span>@($" (ID: {usage})")</li> 661 } 662 </ul> 663 </div> 664 </div> 665 </div> 666 } 667 @if (pageUsages > 0) 668 { 669 var pages = Dynamicweb.Content.Services.Pages.GetPages(themeUsage.PageUsages.ToArray()); 670 671 <div class="accordion-item"> 672 <h2 class="accordion-header" id="headingPages"> 673 <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapsePages" aria-expanded="false" aria-controls="collapsePages"> 674 <span class="pe-2">Pages</span><span class="badge rounded-pill bg-secondary text-light">@pageUsages</span> 675 </button> 676 </h2> 677 <div id="collapsePages" class="accordion-collapse collapse" aria-labelledby="headingPages" data-bs-parent="#accordionWrapper"> 678 <div class="accordion-body"> 679 <ul> 680 @foreach (var usage in themeUsage.PageUsages) 681 { 682 <li><span class="fw-bold">@pages.FirstOrDefault(p => p.ID == usage).GetDisplayName()</span>@($" (ID: {usage})")</li> 683 } 684 </ul> 685 </div> 686 </div> 687 </div> 688 } 689 @if (pagePropertyUsages > 0) 690 { 691 var pages = Dynamicweb.Content.Services.Pages.GetPages(themeUsage.PageUsages.ToArray()); 692 693 <div class="accordion-item"> 694 <h2 class="accordion-header" id="headingPageProperties"> 695 <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapsePageProperties" aria-expanded="false" aria-controls="collapsePageProperties"> 696 <span class="pe-2">Page Properties</span><span class="badge rounded-pill bg-secondary text-light">@pagePropertyUsages</span> 697 </button> 698 </h2> 699 <div id="collapsePageProperties" class="accordion-collapse collapse" aria-labelledby="headingPageProperties" data-bs-parent="#accordionWrapper"> 700 <div class="accordion-body"> 701 <ul> 702 @foreach (var usage in themeUsage.PagePropertyUsages) 703 { 704 <li><span class="fw-bold">@pages.FirstOrDefault(p => p.ID == usage).GetDisplayName()</span>@($" (ID: {usage})")</li> 705 } 706 </ul> 707 </div> 708 </div> 709 </div> 710 } 711 @if (gridRowUsages > 0) 712 { 713 var rows = Dynamicweb.Content.Services.Grids.GetGridRows().Where(r => themeUsage.GridRowUsages.Contains(r.ID)).ToList(); 714 715 <div class="accordion-item"> 716 <h2 class="accordion-header" id="headingRows"> 717 <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseRows" aria-expanded="false" aria-controls="collapseRows"> 718 <span class="pe-2">Rows</span><span class="badge rounded-pill bg-secondary text-light">@gridRowUsages</span> 719 </button> 720 </h2> 721 <div id="collapseRows" class="accordion-collapse collapse" aria-labelledby="headingRows" data-bs-parent="#accordionWrapper"> 722 <div class="accordion-body"> 723 <ul> 724 @foreach (var usage in themeUsage.GridRowUsages) 725 { 726 var row = rows.FirstOrDefault(r => r.ID == usage); 727 var page = Dynamicweb.Content.Services.Pages.GetPage(row.PageId); 728 <li>Page: <span class="fw-bold">@(page.GetDisplayName())</span>@($"( ID: {page.ID}) - Row: ")<span class="fw-bold">@(row.DefinitionId)</span>@($" (ID: {usage})")</li> 729 } 730 </ul> 731 </div> 732 </div> 733 </div> 734 } 735 @if (paragraphUsages > 0) 736 { 737 var paragraphs = Dynamicweb.Content.Services.Paragraphs.GetParagraphs().Where(p => themeUsage.ParagraphUsages.Contains(p.ID)).ToList(); 738 739 <div class="accordion-item"> 740 <h2 class="accordion-header" id="headingParagraphs"> 741 <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseParagraphs" aria-expanded="false" aria-controls="collapseParagraphs"> 742 <span class="pe-2">Paragraphs</span><span class="badge rounded-pill bg-secondary text-light">@paragraphUsages</span> 743 </button> 744 </h2> 745 <div id="collapseParagraphs" class="accordion-collapse collapse" aria-labelledby="headingParagraphs" data-bs-parent="#accordionWrapper"> 746 <div class="accordion-body"> 747 <ul> 748 @foreach (var usage in themeUsage.ParagraphUsages) 749 { 750 var paragraph = paragraphs.FirstOrDefault(p => p.ID == usage); 751 var page = Dynamicweb.Content.Services.Pages.GetPage(paragraph.PageID); 752 <li>Page: <span class="fw-bold">@(page.GetDisplayName())</span>@($"( ID: {page.ID}) - Paragraph: ")<span class="fw-bold">@paragraph.Header</span>@($" (ID: {usage})")</li> 753 } 754 </ul> 755 </div> 756 </div> 757 </div> 758 } 759 </div> 760 </div> 761 </div> 762 </div> 763 </div> 764 } 765 </div> 766 } 767 } 768 </div> 769 </div> 770 } 771 <div class="g-col-12"> 772 <hr /> 773 </div> 774
Error executing template "Designs/Swift/Paragraph/Swift_Theme.cshtml" System.Data.SqlClient.SqlException (0x80131904): STRING_AGG aggregation result exceeded the limit of 8000 bytes. Use LOB types to avoid result truncation. at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction) at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose) at System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady) at System.Data.SqlClient.SqlDataReader.TryConsumeMetaData() at System.Data.SqlClient.SqlDataReader.get_MetaData() at System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString, Boolean isInternal, Boolean forDescribeParameterEncryption, Boolean shouldCacheForAlwaysEncrypted) at System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async, Int32 timeout, Task& task, Boolean asyncWrite, Boolean inRetry, SqlDataReader ds, Boolean describeParameterEncryptionRequest) at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, TaskCompletionSource`1 completion, Int32 timeout, Task& task, Boolean& usedCache, Boolean asyncWrite, Boolean inRetry) at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method) at System.Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior behavior, String method) at Dynamicweb.Data.Database.CreateDataReader(IDbCommand command, CommandBehavior behavior) at Dynamicweb.Data.Database.CreateDataReader(String sql, IDbConnection connection, IDbTransaction transaction, CommandBehavior behavior, Int32 commandTimeout, Dictionary`2 sqlParams) at Dynamicweb.Data.Database.CreateDataReader(String sql, IDbConnection connection, IDbTransaction transaction, Int32 commandTimeout, Dictionary`2 sqlParams) at Dynamicweb.Data.Database.CreateDataReader(String sql) at CompiledRazorTemplates.Dynamic.RazorEngine_8e3f1b11eb0041ceb2ca487c2be837e6.UpdateThemeUsages(String sqlQuery, List`1 themeUsages) in E:\Dynamicweb.net\Solutions\Dynamicweb\dw2022.cloud.dynamicweb-cms.com\Files\Templates\Designs\Swift\Paragraph\Swift_Theme.cshtml:line 202 at CompiledRazorTemplates.Dynamic.RazorEngine_8e3f1b11eb0041ceb2ca487c2be837e6.GetAllThemeUsages() in E:\Dynamicweb.net\Solutions\Dynamicweb\dw2022.cloud.dynamicweb-cms.com\Files\Templates\Designs\Swift\Paragraph\Swift_Theme.cshtml:line 184 at CompiledRazorTemplates.Dynamic.RazorEngine_8e3f1b11eb0041ceb2ca487c2be837e6.GetThemeUsageById(String themeId) in E:\Dynamicweb.net\Solutions\Dynamicweb\dw2022.cloud.dynamicweb-cms.com\Files\Templates\Designs\Swift\Paragraph\Swift_Theme.cshtml:line 238 at CompiledRazorTemplates.Dynamic.RazorEngine_8e3f1b11eb0041ceb2ca487c2be837e6.Execute() in E:\Dynamicweb.net\Solutions\Dynamicweb\dw2022.cloud.dynamicweb-cms.com\Files\Templates\Designs\Swift\Paragraph\Swift_Theme.cshtml:line 617 at RazorEngine.Templating.TemplateBase.RazorEngine.Templating.ITemplate.Run(ExecuteContext context, TextWriter reader) at RazorEngine.Templating.RazorEngineService.RunCompile(ITemplateKey key, TextWriter writer, Type modelType, Object model, DynamicViewBag viewBag) at RazorEngine.Templating.RazorEngineServiceExtensions.<>c__DisplayClass16_0.<RunCompile>b__0(TextWriter writer) at RazorEngine.Templating.RazorEngineServiceExtensions.WithWriter(Action`1 withWriter) at Dynamicweb.Rendering.RazorTemplateRenderingProvider.Render(Template template) at Dynamicweb.Rendering.TemplateRenderingService.Render(Template template) at Dynamicweb.Rendering.Template.RenderRazorTemplate() ClientConnectionId:b42d1cec-597c-4eed-bdc2-e0762a41101a Error Number:9829,State:1,Class:16
1 @inherits Dynamicweb.Rendering.ViewModelTemplate<Dynamicweb.Frontend.ParagraphViewModel> 2 @using System.Globalization 3 @using System.Drawing 4 @using Dynamicweb.Core 5 6 @functions{ 7 // Get Hex Color from color picker and translate to RGB color 8 public static string HexToRGB(string hexString) 9 { 10 if (hexString.Equals("none") || string.IsNullOrEmpty(hexString)) 11 return hexString; 12 13 //replace # occurences 14 if (hexString.IndexOf('#') != -1) 15 hexString = hexString.Replace("#", ""); 16 try 17 { 18 int r, g, b = 0; 19 r = int.Parse(hexString.Substring(0, 2), NumberStyles.AllowHexSpecifier); 20 g = int.Parse(hexString.Substring(2, 2), NumberStyles.AllowHexSpecifier); 21 b = int.Parse(hexString.Substring(4, 2), NumberStyles.AllowHexSpecifier); 22 23 string rgb = r + "," + g + "," + b; 24 return rgb; 25 } 26 catch (System.Exception) 27 { 28 return hexString; 29 } 30 } 31 32 public static string GetColorSquare(string hex) 33 { 34 return $"<div class=\"swift-checkered d-inline-block me-1\" style=\"height:1.25rem;width:1.25rem;\"><div style=\"background-color: {hex};border:.0625rem solid grey\" class=\"w-100 h-100\"></div></div>"; 35 } 36 37 public class HSL 38 { 39 public double h { get; set; } 40 public double s { get; set; } 41 public double l { get; set; } 42 } 43 44 //Convert HEX to HSL 45 public static HSL HexToHsl(string hexString) 46 { 47 System.Drawing.Color color = System.Drawing.ColorTranslator.FromHtml(hexString); 48 49 float _R = (color.R / 255f); 50 float _G = (color.G / 255f); 51 float _B = (color.B / 255f); 52 53 float _Min = Math.Min(Math.Min(_R, _G), _B); 54 float _Max = Math.Max(Math.Max(_R, _G), _B); 55 float _Delta = _Max - _Min; 56 57 float S = 0; 58 float L = (float)((_Max + _Min) / 2.0f); 59 60 if (_Delta != 0) 61 { 62 if (L < 0.5f) 63 { 64 S = (float)(_Delta / (_Max + _Min)); 65 } 66 else 67 { 68 S = (float)(_Delta / (2.0f - _Max - _Min)); 69 } 70 } 71 72 HSL hsl = new HSL(); 73 hsl.h = Math.Round(color.GetHue(), 2); 74 hsl.s = Math.Round(S, 2) * 100; 75 hsl.l = Math.Round(L, 2) * 100; 76 77 return hsl; 78 } 79 80 //Find contrast color (white, black) 81 public static Color GetContrastColor(string hexString) 82 { 83 System.Drawing.Color bg = System.Drawing.ColorTranslator.FromHtml(hexString); 84 85 int nThreshold = 105; 86 int bgDelta = Convert.ToInt32((bg.R * 0.299) + (bg.G * 0.587) + 87 (bg.B * 0.114)); 88 89 Color foreColor = (255 - bgDelta < nThreshold) ? Color.Black : Color.White; 90 return foreColor; 91 } 92 93 public string GetColorVariation(string hexString) 94 { 95 var contrast = GetContrastColor(hexString); 96 HSL currentHslColor = HexToHsl(hexString); 97 HSL variantHslColor = currentHslColor; 98 99 if (contrast == Color.Black) 100 { 101 variantHslColor.l = 85; //The background is dark - Color should be light 102 } 103 else 104 { 105 variantHslColor.l = 40; //The background is light - Color should be less light 106 } 107 108 //Color is very light 109 if (currentHslColor.l > 85) 110 { 111 variantHslColor.l = 95; 112 } 113 114 string colorString = variantHslColor.h + ", " + variantHslColor.s + "%, " + variantHslColor.l + "%"; 115 return colorString; 116 } 117 118 private class ThemeDatabaseUsage 119 { 120 public string TableName { get; set; } 121 public string ColumnName { get; set; } 122 } 123 124 private class ThemeUsage 125 { 126 public string Id { get; set; } 127 public List<int> WebsiteUsages { get; set; } = new List<int>(); 128 public List<int> PageUsages { get; set; } = new List<int>(); 129 public List<int> PagePropertyUsages { get; set; } = new List<int>(); 130 public List<int> GridRowUsages { get; set; } = new List<int>(); 131 public List<int> ParagraphUsages { get; set; } = new List<int>(); 132 public int AllUsages { get; set; } = 0; 133 } 134 135 private List<ThemeDatabaseUsage> GetThemeColumnsFromSchema() 136 { 137 string cacheKey = "ThemesFromDatabase"; 138 if (Dynamicweb.Context.Current.Items.Contains(cacheKey)) 139 { 140 return (List<ThemeDatabaseUsage>)Dynamicweb.Context.Current.Items[cacheKey]; 141 } 142 var schema = Dynamicweb.Data.Database.CreateDataReader("SELECT table_name, column_name FROM information_schema.columns WHERE column_name LIKE '%Theme%'"); 143 144 var rawData = new List<ThemeDatabaseUsage>(); 145 while (schema.Read()) { 146 rawData.Add(new ThemeDatabaseUsage {TableName = schema["table_name"].ToString(), ColumnName = schema["column_name"].ToString() }); 147 } 148 Dynamicweb.Context.Current.Items[cacheKey] = rawData; 149 return rawData; 150 } 151 152 private List<ThemeUsage> GetAllThemeUsages() 153 { 154 string cacheKey = "ThemeUsages"; 155 if (Dynamicweb.Context.Current.Items.Contains(cacheKey)) 156 { 157 return (List<ThemeUsage>)Dynamicweb.Context.Current.Items[cacheKey]; 158 } 159 160 var rawData = GetThemeColumnsFromSchema(); 161 var themeUsages = new List<ThemeUsage>(); 162 163 var sqlQuery = ""; 164 foreach (var row in rawData) 165 { 166 if (!string.IsNullOrEmpty(sqlQuery)) { sqlQuery += " UNION ALL "; } 167 sqlQuery += $"SELECT '{row.TableName}' AS TableName, '{row.ColumnName}' AS ColumnName, {row.ColumnName} AS ColumnValue, Id, AreaId, Page.PageId, PageProperties.PageId as 'PagePropertiesId', GridRowId, ParagraphId" + 168 $" FROM [{row.TableName}]" + 169 $" LEFT JOIN Area ON AreaItemType = '{row.TableName.Replace("ItemType_","")}' AND AreaItemId = Id" + 170 $" LEFT JOIN Page ON PageItemType = '{row.TableName.Replace("ItemType_","")}' AND PageItemId = Id" + 171 $" LEFT JOIN Page as PageProperties ON AreaItemTypePageProperty = '{row.TableName.Replace("ItemType_","")}' AND PageProperties.PagePropertyItemId = Id" + 172 $" LEFT JOIN GridRow ON GridRowItemType = '{row.TableName.Replace("ItemType_","")}' AND GridRowItemId = Id" + 173 $" LEFT JOIN Paragraph ON ParagraphItemType = '{row.TableName.Replace("ItemType_","")}' AND ParagraphItemId = Id" + 174 $" WHERE {row.ColumnName} != '' AND {row.ColumnName} IS NOT NULL" + 175 $" AND (AreaId IS NULL OR AreaId = {Pageview.AreaID})" + 176 $" AND (Page.PageId IS NULL OR Page.PageAreaId = {Pageview.AreaID})" + 177 $" AND (PageProperties.PageId IS NULL OR PageProperties.PageAreaId = {Pageview.AreaID})" + 178 $" AND (GridRowId IS NULL OR GridRowPageId IN (SELECT value From string_split(@pageIds, ',')))" + 179 $" AND (ParagraphId IS NULL OR ParagraphPageId IN (SELECT value From string_split(@pageIds, ',')))"; 180 181 var maxMsSqlServerCharLimit = 60000; 182 if (sqlQuery.Length > maxMsSqlServerCharLimit) 183 { 184 UpdateThemeUsages(sqlQuery, themeUsages); 185 sqlQuery = ""; 186 } 187 } 188 189 if (!string.IsNullOrEmpty(sqlQuery)) 190 { 191 UpdateThemeUsages(sqlQuery, themeUsages); 192 } 193 UpdateAllUsages(themeUsages); 194 195 Dynamicweb.Context.Current.Items[cacheKey] = themeUsages; 196 return themeUsages; 197 } 198 199 private void UpdateThemeUsages(string sqlQuery, List<ThemeUsage> themeUsages) 200 { 201 sqlQuery = $"DECLARE @pageIds NVARCHAR(max) = (SELECT STRING_AGG(PageId,',') FROM Page WHERE PageAreaId = {Pageview.AreaID}) " + sqlQuery; 202 var rawData = Dynamicweb.Data.Database.CreateDataReader(sqlQuery); 203 while (rawData.Read()) 204 { 205 var themeId = rawData["ColumnValue"].ToString(); 206 var themeUsageExists = themeUsages.FirstOrDefault(t => t.Id == themeId) != null; 207 if (!themeUsageExists) 208 { 209 themeUsages.Add(new ThemeUsage { Id = themeId }); 210 } 211 212 var themeUsage = themeUsages.FirstOrDefault(t => t.Id == themeId); 213 if (themeUsage == null) continue; 214 215 if (Converter.ToInt32(rawData["AreaId"].ToString()) > 0) { themeUsage.WebsiteUsages.Add(Converter.ToInt32(rawData["AreaId"].ToString())); } 216 if (Converter.ToInt32(rawData["PageId"].ToString()) > 0) { themeUsage.PageUsages.Add(Converter.ToInt32(rawData["PageId"].ToString())); } 217 if (Converter.ToInt32(rawData["PagePropertiesId"].ToString()) > 0) { themeUsage.PagePropertyUsages.Add(Converter.ToInt32(rawData["PagePropertiesId"].ToString())); } 218 if (Converter.ToInt32(rawData["GridRowId"].ToString()) > 0) { themeUsage.GridRowUsages.Add(Converter.ToInt32(rawData["GridRowId"].ToString())); } 219 if (Converter.ToInt32(rawData["ParagraphId"].ToString()) > 0) { themeUsage.ParagraphUsages.Add(Converter.ToInt32(rawData["ParagraphId"].ToString())); } 220 } 221 } 222 223 private void UpdateAllUsages(List<ThemeUsage> themeUsages) 224 { 225 foreach (var themeUsage in themeUsages) 226 { 227 int websiteUsages = themeUsage?.WebsiteUsages.Count ?? 0; 228 int pageUsages = themeUsage?.PageUsages.Count ?? 0; 229 int pagePropertyUsages = themeUsage?.PagePropertyUsages.Count ?? 0; 230 int gridRowUsages = themeUsage?.GridRowUsages.Count ?? 0; 231 int paragraphUsages = themeUsage?.ParagraphUsages.Count ?? 0; 232 themeUsage.AllUsages = websiteUsages + pageUsages + pagePropertyUsages + gridRowUsages + paragraphUsages; 233 } 234 } 235 236 private ThemeUsage GetThemeUsageById(string themeId) 237 { 238 var themeUsages = GetAllThemeUsages(); 239 return themeUsages.FirstOrDefault(t => t.Id == themeId); 240 } 241 242 } 243 244 @{ 245 string themeName = !string.IsNullOrWhiteSpace(Model.Item.GetString("Name")) ? Model.Item.GetString("Name") : "Default"; 246 string themeClassName = !string.IsNullOrWhiteSpace(Model.Item.GetString("CSSClassName")) ? Model.Item.GetString("CSSClassName").Replace(" ", "").Trim().ToLower() : ""; 247 248 //Theme colors 249 string foregroundColor = Model.Item.GetString("ForegroundColor", "currentColor"); 250 string backgroundColor = Model.Item.GetString("BackgroundColor", "transparent"); 251 string accentColor = Model.Item.GetString("accentColor", "currentColor"); 252 string borderColor = Model.Item.GetString("BorderColor", "transparent"); 253 254 //Primary button 255 string buttonPrimaryForegroundColor = Model.Item.GetString("ButtonPrimaryForegroundColor", "currentColor"); 256 string buttonPrimaryBackgroundColor = Model.Item.GetString("ButtonPrimaryBackgroundColor", "transparent"); 257 string buttonPrimaryBorderColor = Model.Item.GetString("ButtonPrimaryBorderColor", "transparent"); 258 259 string buttonPrimaryHoverBackgroundColorAuto = "transparent"; 260 if (buttonPrimaryBackgroundColor != "transparent") 261 { 262 buttonPrimaryHoverBackgroundColorAuto = "hsl(" + GetColorVariation(buttonPrimaryBackgroundColor) + ")"; 263 } 264 string buttonPrimaryHoverForegroundColor = Model.Item.GetString("ButtonPrimaryHoverForegroundColor", buttonPrimaryForegroundColor); 265 string buttonPrimaryHoverBackgroundColor = Model.Item.GetString("ButtonPrimaryHoverBackgroundColor", buttonPrimaryHoverBackgroundColorAuto); 266 string buttonPrimaryHoverBorderColor = Model.Item.GetString("ButtonPrimaryHoverBorderColor", buttonPrimaryBorderColor); 267 268 //Secondary buton 269 string buttonSecondaryForegroundColor = Model.Item.GetString("ButtonSecondaryForegroundColor", "currentColor"); 270 string buttonSecondaryBackgroundColor = Model.Item.GetString("ButtonSecondaryBackgroundColor", "transparent"); 271 string buttonSecondaryBorderColor = Model.Item.GetString("ButtonSecondaryBorderColor", "transparent"); 272 273 string buttonSecondaryHoverBackgroundColorAuto = "transparent"; 274 if (buttonSecondaryBackgroundColor != "transparent") 275 { 276 buttonSecondaryHoverBackgroundColorAuto = "hsl(" + GetColorVariation(buttonSecondaryBackgroundColor) + ")"; 277 } 278 string buttonSecondaryHoverForegroundColor = Model.Item.GetString("ButtonSecondaryHoverForegroundColor", buttonSecondaryForegroundColor); 279 string buttonSecondaryHoverBackgroundColor = Model.Item.GetString("ButtonSecondaryHoverBackgroundColor", buttonSecondaryHoverBackgroundColorAuto); 280 string buttonSecondaryHoverBorderColor = Model.Item.GetString("ButtonSecondaryHoverBorderColor", buttonSecondaryBorderColor); 281 282 //Link buton 283 string buttonLinkColor = Model.Item.GetString("ButtonLinkColor", "currentColor"); 284 string buttonLinkHoverColorAuto = "currentColor"; 285 if (buttonLinkColor != "currentColor") 286 { 287 buttonLinkHoverColorAuto = "hsl(" + GetColorVariation(buttonLinkColor) + ")"; 288 } 289 string buttonLinkHoverColor = Model.Item.GetString("ButtonLinkHoverColor", buttonLinkHoverColorAuto); 290 291 string accessibilityOutlineColor = Model.Item.GetString("OutlineColor") != null ? Model.Item.GetString("OutlineColor") : ""; 292 293 if (!string.IsNullOrEmpty(themeClassName)) 294 { 295 var sb = new System.Text.StringBuilder(); 296 297 sb.AppendLine("." + themeClassName + "{"); 298 if (!string.IsNullOrEmpty(foregroundColor)) 299 { 300 sb.AppendLine($"--swift-foreground-color: {foregroundColor};"); 301 sb.AppendLine($"--swift-foreground-color-rgb: {HexToRGB(foregroundColor)};"); 302 } 303 if (!string.IsNullOrEmpty(backgroundColor)) 304 { 305 sb.AppendLine($"--swift-background-color: {backgroundColor};"); 306 sb.AppendLine($"--swift-background-color-rgb: {HexToRGB(backgroundColor)};"); 307 } 308 if (!string.IsNullOrEmpty(accentColor)) 309 { 310 sb.AppendLine($"--swift-accent-color: {accentColor};"); 311 sb.AppendLine($"--swift-accent-color-rgb: {HexToRGB(accentColor)};"); 312 } 313 if (!string.IsNullOrEmpty(borderColor)) 314 { 315 sb.AppendLine($"--swift-border-color: {borderColor};"); 316 sb.AppendLine($"--swift-border-color-rgb: {HexToRGB(borderColor)};"); 317 } 318 319 if (!string.IsNullOrEmpty(buttonPrimaryBackgroundColor)) 320 { 321 sb.AppendLine($"--swift-button-primary-background-color: {buttonPrimaryBackgroundColor};"); 322 sb.AppendLine($"--swift-button-primary-background-color-rgb: {HexToRGB(buttonPrimaryBackgroundColor)};"); 323 } 324 if (!string.IsNullOrEmpty(buttonPrimaryForegroundColor)) 325 { 326 sb.AppendLine($"--swift-button-primary-foreground-color: {buttonPrimaryForegroundColor};"); 327 sb.AppendLine($"--swift-button-primary-foreground-color-rgb: {HexToRGB(buttonPrimaryForegroundColor)};"); 328 } 329 if (!string.IsNullOrEmpty(buttonPrimaryBorderColor)) 330 { 331 sb.AppendLine($"--swift-button-primary-border-color: {buttonPrimaryBorderColor};"); 332 sb.AppendLine($"--swift-button-primary-border-color-rgb: {HexToRGB(buttonPrimaryBorderColor)};"); 333 } 334 335 if (!string.IsNullOrEmpty(buttonPrimaryHoverBackgroundColor)) 336 { 337 sb.AppendLine($"--swift-button-primary-hover-background-color: {buttonPrimaryHoverBackgroundColor};"); 338 sb.AppendLine($"--swift-button-primary-hover-background-color-rgb: {HexToRGB(buttonPrimaryHoverBackgroundColor)};"); 339 } 340 if (!string.IsNullOrEmpty(buttonPrimaryHoverForegroundColor)) 341 { 342 sb.AppendLine($"--swift-button-primary-hover-foreground-color: {buttonPrimaryHoverForegroundColor};"); 343 sb.AppendLine($"--swift-button-primary-hover-foreground-color-rgb: {HexToRGB(buttonPrimaryHoverForegroundColor)};"); 344 } 345 if (!string.IsNullOrEmpty(buttonPrimaryHoverBorderColor)) 346 { 347 sb.AppendLine($"--swift-button-primary-hover-border-color: {buttonPrimaryHoverBorderColor};"); 348 sb.AppendLine($"--swift-button-primary-hover-border-color-rgb: {HexToRGB(buttonPrimaryHoverBorderColor)};"); 349 } 350 351 if (!string.IsNullOrEmpty(buttonSecondaryBackgroundColor)) 352 { 353 sb.AppendLine($"--swift-button-secondary-background-color: {buttonSecondaryBackgroundColor};"); 354 sb.AppendLine($"--swift-button-secondary-background-color-rgb: {HexToRGB(buttonSecondaryBackgroundColor)};"); 355 } 356 if (!string.IsNullOrEmpty(buttonSecondaryForegroundColor)) 357 { 358 sb.AppendLine($"--swift-button-secondary-foreground-color: {buttonSecondaryForegroundColor};"); 359 sb.AppendLine($"--swift-button-secondary-foreground-color-rgb: {HexToRGB(buttonSecondaryForegroundColor)};"); 360 } 361 if (!string.IsNullOrEmpty(buttonSecondaryBorderColor)) 362 { 363 sb.AppendLine($"--swift-button-secondary-border-color: {buttonSecondaryBorderColor};"); 364 sb.AppendLine($"--swift-button-secondary-border-color-rgb: {HexToRGB(buttonSecondaryBorderColor)};"); 365 } 366 if (!string.IsNullOrEmpty(buttonSecondaryHoverBackgroundColor)) 367 { 368 sb.AppendLine($"--swift-button-secondary-hover-background-color: {buttonSecondaryHoverBackgroundColor};"); 369 sb.AppendLine($"--swift-button-secondary-hover-background-color-rgb: {HexToRGB(buttonSecondaryHoverBackgroundColor)};"); 370 } 371 if (!string.IsNullOrEmpty(buttonSecondaryHoverForegroundColor)) 372 { 373 sb.AppendLine($"--swift-button-secondary-hover-foreground-color: {buttonSecondaryHoverForegroundColor};"); 374 sb.AppendLine($"--swift-button-secondary-hover-foreground-color-rgb: {HexToRGB(buttonSecondaryHoverForegroundColor)};"); 375 } 376 if (!string.IsNullOrEmpty(buttonSecondaryHoverBorderColor)) 377 { 378 sb.AppendLine($"--swift-button-secondary-hover-border-color: {buttonSecondaryHoverBorderColor};"); 379 sb.AppendLine($"--swift-button-secondary-hover-border-color-rgb: {HexToRGB(buttonSecondaryHoverBorderColor)};"); 380 } 381 if (!string.IsNullOrEmpty(buttonLinkColor)) 382 { 383 sb.AppendLine($"--swift-button-link-color: {buttonLinkColor};"); 384 sb.AppendLine($"--swift-button-link-color-rgb: {HexToRGB(buttonLinkColor)};"); 385 } 386 if (!string.IsNullOrEmpty(buttonLinkHoverColor)) 387 { 388 sb.AppendLine($"--swift-button-link-hover-color: {buttonLinkHoverColor};"); 389 sb.AppendLine($"--swift-button-link-hover-color-rgb: {HexToRGB(buttonLinkHoverColor)};"); 390 } 391 if (!string.IsNullOrEmpty(accessibilityOutlineColor)) 392 { 393 sb.AppendLine($"--swift-a11y-outline-color: {accessibilityOutlineColor};"); 394 sb.AppendLine($"--swift-a11y-outline-color-rgb: {HexToRGB(accessibilityOutlineColor)};"); 395 } 396 sb.AppendLine("}"); 397 398 Dynamicweb.Core.Helpers.TextFileHelper.WriteTextFile(sb.ToString() + Environment.NewLine, Dynamicweb.Context.Current.Server.MapPath($"/Files/Templates/Designs/Swift/_parsed/Swift_css/Swift_theme_styles_{Dynamicweb.Content.Services.Pages.GetPage(Model.PageID).AreaId}.tmp"), true); 399 } 400 } 401 402 @if (themeClassName != "") 403 { 404 string iconPath = "/Files/Templates/Designs/Swift/Assets/icons/"; 405 406 <div class="g-col-12 g-col-lg-4"> 407 <div class="swift-checkered p-3"> 408 <div class="theme-option theme @themeClassName p-lg-3"> 409 <div class="mb-2 pb-1 border-bottom d-flex align-items-center"> 410 <span class="icon-3 me-2"> 411 @ReadFile(iconPath + "sun.svg") 412 </span> 413 <h4 class="m-0 p-0">@themeName</h4> 414 </div> 415 <div class="d-flex flex-column gap-1 mb-2"> 416 <p class="mb-0">This is the body text of the theme.</p> 417 <p class="mb-0" style="color: var(--swift-accent-color)">This is the accent color of the theme.</p> 418 </div> 419 <div> 420 <button class="btn btn-primary me-1">Primary</button> 421 <button class="btn btn-secondary">Secondary</button> 422 <button class="btn btn-link">Link</button> 423 </div> 424 </div> 425 </div> 426 </div> 427 <div class="g-col-12 g-col-lg-8 mb-4 mb-lg-0"> 428 <div class="grid fs-7"> 429 <div class="g-col-12 g-col-lg-3"> 430 <table class="table table-borderless table-sm w-100"> 431 <thead> 432 <tr> 433 <th colspan="2" class="fw-bold">@Translate("Base")</th> 434 </tr> 435 </thead> 436 <tr> 437 <td>@Translate("Foreground")</td> 438 <td>@GetColorSquare(foregroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@foregroundColor');">@foregroundColor</a></td> 439 </tr> 440 <tr> 441 <td>@Translate("Background")</td> 442 <td>@GetColorSquare(backgroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@backgroundColor');">@backgroundColor</a></td> 443 </tr> 444 <tr> 445 <td>@Translate("Accent")</td> 446 <td>@GetColorSquare(accentColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@accentColor');">@accentColor</a></td> 447 </tr> 448 <tr> 449 <td>@Translate("Border")</td> 450 <td>@GetColorSquare(borderColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@borderColor');">@borderColor</a></td> 451 </tr> 452 </table> 453 </div> 454 <div class="g-col-12 g-col-lg-3"> 455 <table class="table table-borderless table-sm w-100"> 456 <thead> 457 <tr> 458 <th colspan="2" class="fw-bold">@Translate("Primary button")</th> 459 </tr> 460 </thead> 461 <tr> 462 <td>@Translate("Foreground")</td> 463 <td>@GetColorSquare(buttonPrimaryForegroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonPrimaryForegroundColor');">@buttonPrimaryForegroundColor</a></td> 464 </tr> 465 <tr> 466 <td>@Translate("Background")</td> 467 <td>@GetColorSquare(buttonPrimaryBackgroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonPrimaryBackgroundColor');">@buttonPrimaryBackgroundColor</a></td> 468 </tr> 469 @if (!string.IsNullOrEmpty(buttonPrimaryBorderColor)) 470 { 471 <tr> 472 <td>@Translate("Border")</td> 473 <td>@GetColorSquare(buttonPrimaryBorderColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonPrimaryBorderColor');">@buttonPrimaryBorderColor</a></td> 474 </tr> 475 } 476 <thead> 477 <tr> 478 <th colspan="2" class="fw-bold">@Translate("Primary button hover")</th> 479 </tr> 480 </thead> 481 @if (!string.IsNullOrEmpty(buttonPrimaryHoverForegroundColor)) 482 { 483 <tr> 484 <td>@Translate("Foreground")</td> 485 <td>@GetColorSquare(buttonPrimaryHoverForegroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonPrimaryHoverForegroundColor');">@buttonPrimaryHoverForegroundColor</a></td> 486 </tr> 487 } 488 @if (!string.IsNullOrEmpty(buttonPrimaryHoverBackgroundColor)) 489 { 490 <tr> 491 <td>@Translate("Background")</td> 492 <td>@GetColorSquare(buttonPrimaryHoverBackgroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonPrimaryHoverBackgroundColor');">@buttonPrimaryHoverBackgroundColor</a></td> 493 </tr> 494 } 495 @if (!string.IsNullOrEmpty(buttonPrimaryHoverBorderColor)) 496 { 497 <tr> 498 <td>@Translate("Border")</td> 499 <td>@GetColorSquare(buttonPrimaryHoverBorderColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonPrimaryHoverBorderColor');">@buttonPrimaryHoverBorderColor</a></td> 500 </tr> 501 } 502 </table> 503 </div> 504 <div class="g-col-12 g-col-lg-3"> 505 <table class="table table-borderless table-sm w-100"> 506 <thead> 507 <tr> 508 <th colspan="2" class="fw-bold">@Translate("Secondary button")</th> 509 </tr> 510 </thead> 511 <tr> 512 <td>@Translate("Foreground")</td> 513 <td>@GetColorSquare(buttonSecondaryForegroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonSecondaryForegroundColor');">@buttonSecondaryForegroundColor</a></td> 514 </tr> 515 <tr> 516 <td>@Translate("Background")</td> 517 <td>@GetColorSquare(buttonSecondaryBackgroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonSecondaryBackgroundColor');">@buttonSecondaryBackgroundColor</a></td> 518 </tr> 519 @if (!string.IsNullOrEmpty(buttonSecondaryBorderColor)) 520 { 521 <tr> 522 <td>@Translate("Border")</td> 523 <td>@GetColorSquare(buttonSecondaryBorderColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonSecondaryBorderColor');">@buttonSecondaryBorderColor</a></td> 524 </tr> 525 } 526 <thead> 527 <tr> 528 <th colspan="2" class="fw-bold">@Translate("Secondary button hover")</th> 529 </tr> 530 </thead> 531 @if (!string.IsNullOrEmpty(buttonSecondaryHoverForegroundColor)) 532 { 533 <tr> 534 <td>@Translate("Foreground")</td> 535 <td>@GetColorSquare(buttonSecondaryHoverForegroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonSecondaryHoverForegroundColor');">@buttonSecondaryHoverForegroundColor</a></td> 536 </tr> 537 } 538 @if (!string.IsNullOrEmpty(buttonSecondaryHoverBackgroundColor)) 539 { 540 <tr> 541 <td>@Translate("Background")</td> 542 <td>@GetColorSquare(buttonSecondaryHoverBackgroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonSecondaryHoverBackgroundColor');">@buttonSecondaryHoverBackgroundColor</a></td> 543 </tr> 544 } 545 @if (!string.IsNullOrEmpty(buttonSecondaryHoverBorderColor)) 546 { 547 <tr> 548 <td>@Translate("Border")</td> 549 <td>@GetColorSquare(buttonSecondaryHoverBorderColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonSecondaryHoverBorderColor');">@buttonSecondaryHoverBorderColor</a></td> 550 </tr> 551 } 552 @if (!string.IsNullOrEmpty(accessibilityOutlineColor)) 553 { 554 <tr> 555 <td>@Translate("Focus outline")</td> 556 <td>@GetColorSquare(accessibilityOutlineColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@accessibilityOutlineColor');">@accessibilityOutlineColor</a></td> 557 </tr> 558 } 559 </table> 560 </div> 561 <div class="g-col-12 g-col-lg-3"> 562 <table class="table table-borderless table-sm w-100"> 563 <thead> 564 <tr> 565 <th colspan="2" class="fw-bold">@Translate("Link button")</th> 566 </tr> 567 </thead> 568 <tr> 569 <td>@Translate("Link color")</td> 570 <td>@GetColorSquare(buttonLinkColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonLinkColor');">@buttonLinkColor</a></td> 571 </tr> 572 <thead> 573 <tr> 574 <th colspan="2" class="fw-bold">@Translate("Link button hover")</th> 575 </tr> 576 </thead> 577 @if (!string.IsNullOrEmpty(buttonLinkHoverColor)) 578 { 579 <tr> 580 <td>@Translate("Link hover color")</td> 581 <td>@GetColorSquare(buttonLinkHoverColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonLinkHoverColor');">@buttonLinkHoverColor</a></td> 582 </tr> 583 } 584 585 @if (!string.IsNullOrEmpty(accessibilityOutlineColor)) 586 { 587 <tr> 588 <td>@Translate("Focus outline")</td> 589 <td>@GetColorSquare(accessibilityOutlineColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@accessibilityOutlineColor');">@accessibilityOutlineColor</a></td> 590 </tr> 591 } 592 </table> 593 </div> 594 <div class="g-col-12 g-col-lg-3"> 595 <table class="table table-borderless table-sm w-100"> 596 <tr> 597 <td class="fw-bold">@Translate("Implementation")</td> 598 </tr> 599 <tr> 600 <td> 601 @{ 602 string implementation = $"<div class=\"theme {themeClassName}\"></div>"; 603 } 604 <div class="text-muted"> 605 <code class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@themeClassName');"> 606 @Dynamicweb.Core.Encoders.HtmlEncoder.HtmlEncode(implementation) 607 </code> 608 </div> 609 </td> 610 </tr> 611 </table> 612 </div> 613 @{ 614 bool hasUsageData = Converter.ToBoolean(Dynamicweb.Context.Current.Request["auditUsages"]); 615 if (hasUsageData) 616 { 617 var themeUsage = GetThemeUsageById(themeClassName); 618 int allUsages = themeUsage?.AllUsages ?? 0; 619 string buttonAttributes = allUsages > 0 ? $"data-bs-toggle=\"modal\" data-bs-target=\"#themeUsage_{Model.ID}\"" : string.Empty; 620 string badgeStyle = allUsages > 0 ? "bg-success" : "bg-danger"; 621 622 <div class="g-col-12 g-col-lg-9 position-relative"> 623 <button type="button" class="btn btn-primary btn-sm position-absolute end-0" @buttonAttributes> 624 Usages 625 <span class="position-absolute top-0 start-100 translate-middle badge rounded-pill text-white @badgeStyle">@allUsages</span> 626 </button> 627 628 @if (allUsages > 0) 629 { 630 int websiteUsages = themeUsage?.WebsiteUsages.Count ?? 0; 631 int pageUsages = themeUsage?.PageUsages.Count ?? 0; 632 int pagePropertyUsages = themeUsage?.PagePropertyUsages.Count ?? 0; 633 int gridRowUsages = themeUsage?.GridRowUsages.Count ?? 0; 634 int paragraphUsages = themeUsage?.ParagraphUsages.Count ?? 0; 635 636 <!-- Modal --> 637 <div class="modal fade" id="themeUsage_@(Model.ID)" tabindex="-1" aria-labelledby="usagesModelLabel" aria-hidden="true"> 638 <div class="modal-dialog modal-xl modal-dialog-centered modal-dialog-scrollable"> 639 <div class="modal-content"> 640 <div class="modal-header"> 641 <h5 class="modal-title" id="usagesModelLabel">@allUsages Usages of '@(themeName)' (@(themeClassName))</h5> 642 <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> 643 </div> 644 <div class="modal-body"> 645 <div class="accordion" id="accordionWrapper"> 646 @if(websiteUsages > 0) 647 { 648 <div class="accordion-item"> 649 <h2 class="accordion-header" id="headingWebsites"> 650 <button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#collapseWebsites" aria-expanded="true" aria-controls="collapseWebsites"> 651 <span class="pe-2">Websites</span><span class="badge rounded-pill bg-secondary text-light">@websiteUsages</span> 652 </button> 653 </h2> 654 <div id="collapseWebsites" class="accordion-collapse collapse show" aria-labelledby="headingWebsites" data-bs-parent="#accordionWrapper"> 655 <div class="accordion-body"> 656 <ul> 657 @foreach (var usage in themeUsage.WebsiteUsages) 658 { 659 var website = Dynamicweb.Content.Services.Areas.GetArea(usage); 660 <li><span class="fw-bold">@website.Name</span>@($" (ID: {usage})")</li> 661 } 662 </ul> 663 </div> 664 </div> 665 </div> 666 } 667 @if (pageUsages > 0) 668 { 669 var pages = Dynamicweb.Content.Services.Pages.GetPages(themeUsage.PageUsages.ToArray()); 670 671 <div class="accordion-item"> 672 <h2 class="accordion-header" id="headingPages"> 673 <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapsePages" aria-expanded="false" aria-controls="collapsePages"> 674 <span class="pe-2">Pages</span><span class="badge rounded-pill bg-secondary text-light">@pageUsages</span> 675 </button> 676 </h2> 677 <div id="collapsePages" class="accordion-collapse collapse" aria-labelledby="headingPages" data-bs-parent="#accordionWrapper"> 678 <div class="accordion-body"> 679 <ul> 680 @foreach (var usage in themeUsage.PageUsages) 681 { 682 <li><span class="fw-bold">@pages.FirstOrDefault(p => p.ID == usage).GetDisplayName()</span>@($" (ID: {usage})")</li> 683 } 684 </ul> 685 </div> 686 </div> 687 </div> 688 } 689 @if (pagePropertyUsages > 0) 690 { 691 var pages = Dynamicweb.Content.Services.Pages.GetPages(themeUsage.PageUsages.ToArray()); 692 693 <div class="accordion-item"> 694 <h2 class="accordion-header" id="headingPageProperties"> 695 <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapsePageProperties" aria-expanded="false" aria-controls="collapsePageProperties"> 696 <span class="pe-2">Page Properties</span><span class="badge rounded-pill bg-secondary text-light">@pagePropertyUsages</span> 697 </button> 698 </h2> 699 <div id="collapsePageProperties" class="accordion-collapse collapse" aria-labelledby="headingPageProperties" data-bs-parent="#accordionWrapper"> 700 <div class="accordion-body"> 701 <ul> 702 @foreach (var usage in themeUsage.PagePropertyUsages) 703 { 704 <li><span class="fw-bold">@pages.FirstOrDefault(p => p.ID == usage).GetDisplayName()</span>@($" (ID: {usage})")</li> 705 } 706 </ul> 707 </div> 708 </div> 709 </div> 710 } 711 @if (gridRowUsages > 0) 712 { 713 var rows = Dynamicweb.Content.Services.Grids.GetGridRows().Where(r => themeUsage.GridRowUsages.Contains(r.ID)).ToList(); 714 715 <div class="accordion-item"> 716 <h2 class="accordion-header" id="headingRows"> 717 <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseRows" aria-expanded="false" aria-controls="collapseRows"> 718 <span class="pe-2">Rows</span><span class="badge rounded-pill bg-secondary text-light">@gridRowUsages</span> 719 </button> 720 </h2> 721 <div id="collapseRows" class="accordion-collapse collapse" aria-labelledby="headingRows" data-bs-parent="#accordionWrapper"> 722 <div class="accordion-body"> 723 <ul> 724 @foreach (var usage in themeUsage.GridRowUsages) 725 { 726 var row = rows.FirstOrDefault(r => r.ID == usage); 727 var page = Dynamicweb.Content.Services.Pages.GetPage(row.PageId); 728 <li>Page: <span class="fw-bold">@(page.GetDisplayName())</span>@($"( ID: {page.ID}) - Row: ")<span class="fw-bold">@(row.DefinitionId)</span>@($" (ID: {usage})")</li> 729 } 730 </ul> 731 </div> 732 </div> 733 </div> 734 } 735 @if (paragraphUsages > 0) 736 { 737 var paragraphs = Dynamicweb.Content.Services.Paragraphs.GetParagraphs().Where(p => themeUsage.ParagraphUsages.Contains(p.ID)).ToList(); 738 739 <div class="accordion-item"> 740 <h2 class="accordion-header" id="headingParagraphs"> 741 <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseParagraphs" aria-expanded="false" aria-controls="collapseParagraphs"> 742 <span class="pe-2">Paragraphs</span><span class="badge rounded-pill bg-secondary text-light">@paragraphUsages</span> 743 </button> 744 </h2> 745 <div id="collapseParagraphs" class="accordion-collapse collapse" aria-labelledby="headingParagraphs" data-bs-parent="#accordionWrapper"> 746 <div class="accordion-body"> 747 <ul> 748 @foreach (var usage in themeUsage.ParagraphUsages) 749 { 750 var paragraph = paragraphs.FirstOrDefault(p => p.ID == usage); 751 var page = Dynamicweb.Content.Services.Pages.GetPage(paragraph.PageID); 752 <li>Page: <span class="fw-bold">@(page.GetDisplayName())</span>@($"( ID: {page.ID}) - Paragraph: ")<span class="fw-bold">@paragraph.Header</span>@($" (ID: {usage})")</li> 753 } 754 </ul> 755 </div> 756 </div> 757 </div> 758 } 759 </div> 760 </div> 761 </div> 762 </div> 763 </div> 764 } 765 </div> 766 } 767 } 768 </div> 769 </div> 770 } 771 <div class="g-col-12"> 772 <hr /> 773 </div> 774
Error executing template "Designs/Swift/Paragraph/Swift_Theme.cshtml" System.Data.SqlClient.SqlException (0x80131904): STRING_AGG aggregation result exceeded the limit of 8000 bytes. Use LOB types to avoid result truncation. at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction) at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose) at System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady) at System.Data.SqlClient.SqlDataReader.TryConsumeMetaData() at System.Data.SqlClient.SqlDataReader.get_MetaData() at System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString, Boolean isInternal, Boolean forDescribeParameterEncryption, Boolean shouldCacheForAlwaysEncrypted) at System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async, Int32 timeout, Task& task, Boolean asyncWrite, Boolean inRetry, SqlDataReader ds, Boolean describeParameterEncryptionRequest) at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, TaskCompletionSource`1 completion, Int32 timeout, Task& task, Boolean& usedCache, Boolean asyncWrite, Boolean inRetry) at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method) at System.Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior behavior, String method) at Dynamicweb.Data.Database.CreateDataReader(IDbCommand command, CommandBehavior behavior) at Dynamicweb.Data.Database.CreateDataReader(String sql, IDbConnection connection, IDbTransaction transaction, CommandBehavior behavior, Int32 commandTimeout, Dictionary`2 sqlParams) at Dynamicweb.Data.Database.CreateDataReader(String sql, IDbConnection connection, IDbTransaction transaction, Int32 commandTimeout, Dictionary`2 sqlParams) at Dynamicweb.Data.Database.CreateDataReader(String sql) at CompiledRazorTemplates.Dynamic.RazorEngine_8e3f1b11eb0041ceb2ca487c2be837e6.UpdateThemeUsages(String sqlQuery, List`1 themeUsages) in E:\Dynamicweb.net\Solutions\Dynamicweb\dw2022.cloud.dynamicweb-cms.com\Files\Templates\Designs\Swift\Paragraph\Swift_Theme.cshtml:line 202 at CompiledRazorTemplates.Dynamic.RazorEngine_8e3f1b11eb0041ceb2ca487c2be837e6.GetAllThemeUsages() in E:\Dynamicweb.net\Solutions\Dynamicweb\dw2022.cloud.dynamicweb-cms.com\Files\Templates\Designs\Swift\Paragraph\Swift_Theme.cshtml:line 184 at CompiledRazorTemplates.Dynamic.RazorEngine_8e3f1b11eb0041ceb2ca487c2be837e6.GetThemeUsageById(String themeId) in E:\Dynamicweb.net\Solutions\Dynamicweb\dw2022.cloud.dynamicweb-cms.com\Files\Templates\Designs\Swift\Paragraph\Swift_Theme.cshtml:line 238 at CompiledRazorTemplates.Dynamic.RazorEngine_8e3f1b11eb0041ceb2ca487c2be837e6.Execute() in E:\Dynamicweb.net\Solutions\Dynamicweb\dw2022.cloud.dynamicweb-cms.com\Files\Templates\Designs\Swift\Paragraph\Swift_Theme.cshtml:line 617 at RazorEngine.Templating.TemplateBase.RazorEngine.Templating.ITemplate.Run(ExecuteContext context, TextWriter reader) at RazorEngine.Templating.RazorEngineService.RunCompile(ITemplateKey key, TextWriter writer, Type modelType, Object model, DynamicViewBag viewBag) at RazorEngine.Templating.RazorEngineServiceExtensions.<>c__DisplayClass16_0.<RunCompile>b__0(TextWriter writer) at RazorEngine.Templating.RazorEngineServiceExtensions.WithWriter(Action`1 withWriter) at Dynamicweb.Rendering.RazorTemplateRenderingProvider.Render(Template template) at Dynamicweb.Rendering.TemplateRenderingService.Render(Template template) at Dynamicweb.Rendering.Template.RenderRazorTemplate() ClientConnectionId:b42d1cec-597c-4eed-bdc2-e0762a41101a Error Number:9829,State:1,Class:16
1 @inherits Dynamicweb.Rendering.ViewModelTemplate<Dynamicweb.Frontend.ParagraphViewModel> 2 @using System.Globalization 3 @using System.Drawing 4 @using Dynamicweb.Core 5 6 @functions{ 7 // Get Hex Color from color picker and translate to RGB color 8 public static string HexToRGB(string hexString) 9 { 10 if (hexString.Equals("none") || string.IsNullOrEmpty(hexString)) 11 return hexString; 12 13 //replace # occurences 14 if (hexString.IndexOf('#') != -1) 15 hexString = hexString.Replace("#", ""); 16 try 17 { 18 int r, g, b = 0; 19 r = int.Parse(hexString.Substring(0, 2), NumberStyles.AllowHexSpecifier); 20 g = int.Parse(hexString.Substring(2, 2), NumberStyles.AllowHexSpecifier); 21 b = int.Parse(hexString.Substring(4, 2), NumberStyles.AllowHexSpecifier); 22 23 string rgb = r + "," + g + "," + b; 24 return rgb; 25 } 26 catch (System.Exception) 27 { 28 return hexString; 29 } 30 } 31 32 public static string GetColorSquare(string hex) 33 { 34 return $"<div class=\"swift-checkered d-inline-block me-1\" style=\"height:1.25rem;width:1.25rem;\"><div style=\"background-color: {hex};border:.0625rem solid grey\" class=\"w-100 h-100\"></div></div>"; 35 } 36 37 public class HSL 38 { 39 public double h { get; set; } 40 public double s { get; set; } 41 public double l { get; set; } 42 } 43 44 //Convert HEX to HSL 45 public static HSL HexToHsl(string hexString) 46 { 47 System.Drawing.Color color = System.Drawing.ColorTranslator.FromHtml(hexString); 48 49 float _R = (color.R / 255f); 50 float _G = (color.G / 255f); 51 float _B = (color.B / 255f); 52 53 float _Min = Math.Min(Math.Min(_R, _G), _B); 54 float _Max = Math.Max(Math.Max(_R, _G), _B); 55 float _Delta = _Max - _Min; 56 57 float S = 0; 58 float L = (float)((_Max + _Min) / 2.0f); 59 60 if (_Delta != 0) 61 { 62 if (L < 0.5f) 63 { 64 S = (float)(_Delta / (_Max + _Min)); 65 } 66 else 67 { 68 S = (float)(_Delta / (2.0f - _Max - _Min)); 69 } 70 } 71 72 HSL hsl = new HSL(); 73 hsl.h = Math.Round(color.GetHue(), 2); 74 hsl.s = Math.Round(S, 2) * 100; 75 hsl.l = Math.Round(L, 2) * 100; 76 77 return hsl; 78 } 79 80 //Find contrast color (white, black) 81 public static Color GetContrastColor(string hexString) 82 { 83 System.Drawing.Color bg = System.Drawing.ColorTranslator.FromHtml(hexString); 84 85 int nThreshold = 105; 86 int bgDelta = Convert.ToInt32((bg.R * 0.299) + (bg.G * 0.587) + 87 (bg.B * 0.114)); 88 89 Color foreColor = (255 - bgDelta < nThreshold) ? Color.Black : Color.White; 90 return foreColor; 91 } 92 93 public string GetColorVariation(string hexString) 94 { 95 var contrast = GetContrastColor(hexString); 96 HSL currentHslColor = HexToHsl(hexString); 97 HSL variantHslColor = currentHslColor; 98 99 if (contrast == Color.Black) 100 { 101 variantHslColor.l = 85; //The background is dark - Color should be light 102 } 103 else 104 { 105 variantHslColor.l = 40; //The background is light - Color should be less light 106 } 107 108 //Color is very light 109 if (currentHslColor.l > 85) 110 { 111 variantHslColor.l = 95; 112 } 113 114 string colorString = variantHslColor.h + ", " + variantHslColor.s + "%, " + variantHslColor.l + "%"; 115 return colorString; 116 } 117 118 private class ThemeDatabaseUsage 119 { 120 public string TableName { get; set; } 121 public string ColumnName { get; set; } 122 } 123 124 private class ThemeUsage 125 { 126 public string Id { get; set; } 127 public List<int> WebsiteUsages { get; set; } = new List<int>(); 128 public List<int> PageUsages { get; set; } = new List<int>(); 129 public List<int> PagePropertyUsages { get; set; } = new List<int>(); 130 public List<int> GridRowUsages { get; set; } = new List<int>(); 131 public List<int> ParagraphUsages { get; set; } = new List<int>(); 132 public int AllUsages { get; set; } = 0; 133 } 134 135 private List<ThemeDatabaseUsage> GetThemeColumnsFromSchema() 136 { 137 string cacheKey = "ThemesFromDatabase"; 138 if (Dynamicweb.Context.Current.Items.Contains(cacheKey)) 139 { 140 return (List<ThemeDatabaseUsage>)Dynamicweb.Context.Current.Items[cacheKey]; 141 } 142 var schema = Dynamicweb.Data.Database.CreateDataReader("SELECT table_name, column_name FROM information_schema.columns WHERE column_name LIKE '%Theme%'"); 143 144 var rawData = new List<ThemeDatabaseUsage>(); 145 while (schema.Read()) { 146 rawData.Add(new ThemeDatabaseUsage {TableName = schema["table_name"].ToString(), ColumnName = schema["column_name"].ToString() }); 147 } 148 Dynamicweb.Context.Current.Items[cacheKey] = rawData; 149 return rawData; 150 } 151 152 private List<ThemeUsage> GetAllThemeUsages() 153 { 154 string cacheKey = "ThemeUsages"; 155 if (Dynamicweb.Context.Current.Items.Contains(cacheKey)) 156 { 157 return (List<ThemeUsage>)Dynamicweb.Context.Current.Items[cacheKey]; 158 } 159 160 var rawData = GetThemeColumnsFromSchema(); 161 var themeUsages = new List<ThemeUsage>(); 162 163 var sqlQuery = ""; 164 foreach (var row in rawData) 165 { 166 if (!string.IsNullOrEmpty(sqlQuery)) { sqlQuery += " UNION ALL "; } 167 sqlQuery += $"SELECT '{row.TableName}' AS TableName, '{row.ColumnName}' AS ColumnName, {row.ColumnName} AS ColumnValue, Id, AreaId, Page.PageId, PageProperties.PageId as 'PagePropertiesId', GridRowId, ParagraphId" + 168 $" FROM [{row.TableName}]" + 169 $" LEFT JOIN Area ON AreaItemType = '{row.TableName.Replace("ItemType_","")}' AND AreaItemId = Id" + 170 $" LEFT JOIN Page ON PageItemType = '{row.TableName.Replace("ItemType_","")}' AND PageItemId = Id" + 171 $" LEFT JOIN Page as PageProperties ON AreaItemTypePageProperty = '{row.TableName.Replace("ItemType_","")}' AND PageProperties.PagePropertyItemId = Id" + 172 $" LEFT JOIN GridRow ON GridRowItemType = '{row.TableName.Replace("ItemType_","")}' AND GridRowItemId = Id" + 173 $" LEFT JOIN Paragraph ON ParagraphItemType = '{row.TableName.Replace("ItemType_","")}' AND ParagraphItemId = Id" + 174 $" WHERE {row.ColumnName} != '' AND {row.ColumnName} IS NOT NULL" + 175 $" AND (AreaId IS NULL OR AreaId = {Pageview.AreaID})" + 176 $" AND (Page.PageId IS NULL OR Page.PageAreaId = {Pageview.AreaID})" + 177 $" AND (PageProperties.PageId IS NULL OR PageProperties.PageAreaId = {Pageview.AreaID})" + 178 $" AND (GridRowId IS NULL OR GridRowPageId IN (SELECT value From string_split(@pageIds, ',')))" + 179 $" AND (ParagraphId IS NULL OR ParagraphPageId IN (SELECT value From string_split(@pageIds, ',')))"; 180 181 var maxMsSqlServerCharLimit = 60000; 182 if (sqlQuery.Length > maxMsSqlServerCharLimit) 183 { 184 UpdateThemeUsages(sqlQuery, themeUsages); 185 sqlQuery = ""; 186 } 187 } 188 189 if (!string.IsNullOrEmpty(sqlQuery)) 190 { 191 UpdateThemeUsages(sqlQuery, themeUsages); 192 } 193 UpdateAllUsages(themeUsages); 194 195 Dynamicweb.Context.Current.Items[cacheKey] = themeUsages; 196 return themeUsages; 197 } 198 199 private void UpdateThemeUsages(string sqlQuery, List<ThemeUsage> themeUsages) 200 { 201 sqlQuery = $"DECLARE @pageIds NVARCHAR(max) = (SELECT STRING_AGG(PageId,',') FROM Page WHERE PageAreaId = {Pageview.AreaID}) " + sqlQuery; 202 var rawData = Dynamicweb.Data.Database.CreateDataReader(sqlQuery); 203 while (rawData.Read()) 204 { 205 var themeId = rawData["ColumnValue"].ToString(); 206 var themeUsageExists = themeUsages.FirstOrDefault(t => t.Id == themeId) != null; 207 if (!themeUsageExists) 208 { 209 themeUsages.Add(new ThemeUsage { Id = themeId }); 210 } 211 212 var themeUsage = themeUsages.FirstOrDefault(t => t.Id == themeId); 213 if (themeUsage == null) continue; 214 215 if (Converter.ToInt32(rawData["AreaId"].ToString()) > 0) { themeUsage.WebsiteUsages.Add(Converter.ToInt32(rawData["AreaId"].ToString())); } 216 if (Converter.ToInt32(rawData["PageId"].ToString()) > 0) { themeUsage.PageUsages.Add(Converter.ToInt32(rawData["PageId"].ToString())); } 217 if (Converter.ToInt32(rawData["PagePropertiesId"].ToString()) > 0) { themeUsage.PagePropertyUsages.Add(Converter.ToInt32(rawData["PagePropertiesId"].ToString())); } 218 if (Converter.ToInt32(rawData["GridRowId"].ToString()) > 0) { themeUsage.GridRowUsages.Add(Converter.ToInt32(rawData["GridRowId"].ToString())); } 219 if (Converter.ToInt32(rawData["ParagraphId"].ToString()) > 0) { themeUsage.ParagraphUsages.Add(Converter.ToInt32(rawData["ParagraphId"].ToString())); } 220 } 221 } 222 223 private void UpdateAllUsages(List<ThemeUsage> themeUsages) 224 { 225 foreach (var themeUsage in themeUsages) 226 { 227 int websiteUsages = themeUsage?.WebsiteUsages.Count ?? 0; 228 int pageUsages = themeUsage?.PageUsages.Count ?? 0; 229 int pagePropertyUsages = themeUsage?.PagePropertyUsages.Count ?? 0; 230 int gridRowUsages = themeUsage?.GridRowUsages.Count ?? 0; 231 int paragraphUsages = themeUsage?.ParagraphUsages.Count ?? 0; 232 themeUsage.AllUsages = websiteUsages + pageUsages + pagePropertyUsages + gridRowUsages + paragraphUsages; 233 } 234 } 235 236 private ThemeUsage GetThemeUsageById(string themeId) 237 { 238 var themeUsages = GetAllThemeUsages(); 239 return themeUsages.FirstOrDefault(t => t.Id == themeId); 240 } 241 242 } 243 244 @{ 245 string themeName = !string.IsNullOrWhiteSpace(Model.Item.GetString("Name")) ? Model.Item.GetString("Name") : "Default"; 246 string themeClassName = !string.IsNullOrWhiteSpace(Model.Item.GetString("CSSClassName")) ? Model.Item.GetString("CSSClassName").Replace(" ", "").Trim().ToLower() : ""; 247 248 //Theme colors 249 string foregroundColor = Model.Item.GetString("ForegroundColor", "currentColor"); 250 string backgroundColor = Model.Item.GetString("BackgroundColor", "transparent"); 251 string accentColor = Model.Item.GetString("accentColor", "currentColor"); 252 string borderColor = Model.Item.GetString("BorderColor", "transparent"); 253 254 //Primary button 255 string buttonPrimaryForegroundColor = Model.Item.GetString("ButtonPrimaryForegroundColor", "currentColor"); 256 string buttonPrimaryBackgroundColor = Model.Item.GetString("ButtonPrimaryBackgroundColor", "transparent"); 257 string buttonPrimaryBorderColor = Model.Item.GetString("ButtonPrimaryBorderColor", "transparent"); 258 259 string buttonPrimaryHoverBackgroundColorAuto = "transparent"; 260 if (buttonPrimaryBackgroundColor != "transparent") 261 { 262 buttonPrimaryHoverBackgroundColorAuto = "hsl(" + GetColorVariation(buttonPrimaryBackgroundColor) + ")"; 263 } 264 string buttonPrimaryHoverForegroundColor = Model.Item.GetString("ButtonPrimaryHoverForegroundColor", buttonPrimaryForegroundColor); 265 string buttonPrimaryHoverBackgroundColor = Model.Item.GetString("ButtonPrimaryHoverBackgroundColor", buttonPrimaryHoverBackgroundColorAuto); 266 string buttonPrimaryHoverBorderColor = Model.Item.GetString("ButtonPrimaryHoverBorderColor", buttonPrimaryBorderColor); 267 268 //Secondary buton 269 string buttonSecondaryForegroundColor = Model.Item.GetString("ButtonSecondaryForegroundColor", "currentColor"); 270 string buttonSecondaryBackgroundColor = Model.Item.GetString("ButtonSecondaryBackgroundColor", "transparent"); 271 string buttonSecondaryBorderColor = Model.Item.GetString("ButtonSecondaryBorderColor", "transparent"); 272 273 string buttonSecondaryHoverBackgroundColorAuto = "transparent"; 274 if (buttonSecondaryBackgroundColor != "transparent") 275 { 276 buttonSecondaryHoverBackgroundColorAuto = "hsl(" + GetColorVariation(buttonSecondaryBackgroundColor) + ")"; 277 } 278 string buttonSecondaryHoverForegroundColor = Model.Item.GetString("ButtonSecondaryHoverForegroundColor", buttonSecondaryForegroundColor); 279 string buttonSecondaryHoverBackgroundColor = Model.Item.GetString("ButtonSecondaryHoverBackgroundColor", buttonSecondaryHoverBackgroundColorAuto); 280 string buttonSecondaryHoverBorderColor = Model.Item.GetString("ButtonSecondaryHoverBorderColor", buttonSecondaryBorderColor); 281 282 //Link buton 283 string buttonLinkColor = Model.Item.GetString("ButtonLinkColor", "currentColor"); 284 string buttonLinkHoverColorAuto = "currentColor"; 285 if (buttonLinkColor != "currentColor") 286 { 287 buttonLinkHoverColorAuto = "hsl(" + GetColorVariation(buttonLinkColor) + ")"; 288 } 289 string buttonLinkHoverColor = Model.Item.GetString("ButtonLinkHoverColor", buttonLinkHoverColorAuto); 290 291 string accessibilityOutlineColor = Model.Item.GetString("OutlineColor") != null ? Model.Item.GetString("OutlineColor") : ""; 292 293 if (!string.IsNullOrEmpty(themeClassName)) 294 { 295 var sb = new System.Text.StringBuilder(); 296 297 sb.AppendLine("." + themeClassName + "{"); 298 if (!string.IsNullOrEmpty(foregroundColor)) 299 { 300 sb.AppendLine($"--swift-foreground-color: {foregroundColor};"); 301 sb.AppendLine($"--swift-foreground-color-rgb: {HexToRGB(foregroundColor)};"); 302 } 303 if (!string.IsNullOrEmpty(backgroundColor)) 304 { 305 sb.AppendLine($"--swift-background-color: {backgroundColor};"); 306 sb.AppendLine($"--swift-background-color-rgb: {HexToRGB(backgroundColor)};"); 307 } 308 if (!string.IsNullOrEmpty(accentColor)) 309 { 310 sb.AppendLine($"--swift-accent-color: {accentColor};"); 311 sb.AppendLine($"--swift-accent-color-rgb: {HexToRGB(accentColor)};"); 312 } 313 if (!string.IsNullOrEmpty(borderColor)) 314 { 315 sb.AppendLine($"--swift-border-color: {borderColor};"); 316 sb.AppendLine($"--swift-border-color-rgb: {HexToRGB(borderColor)};"); 317 } 318 319 if (!string.IsNullOrEmpty(buttonPrimaryBackgroundColor)) 320 { 321 sb.AppendLine($"--swift-button-primary-background-color: {buttonPrimaryBackgroundColor};"); 322 sb.AppendLine($"--swift-button-primary-background-color-rgb: {HexToRGB(buttonPrimaryBackgroundColor)};"); 323 } 324 if (!string.IsNullOrEmpty(buttonPrimaryForegroundColor)) 325 { 326 sb.AppendLine($"--swift-button-primary-foreground-color: {buttonPrimaryForegroundColor};"); 327 sb.AppendLine($"--swift-button-primary-foreground-color-rgb: {HexToRGB(buttonPrimaryForegroundColor)};"); 328 } 329 if (!string.IsNullOrEmpty(buttonPrimaryBorderColor)) 330 { 331 sb.AppendLine($"--swift-button-primary-border-color: {buttonPrimaryBorderColor};"); 332 sb.AppendLine($"--swift-button-primary-border-color-rgb: {HexToRGB(buttonPrimaryBorderColor)};"); 333 } 334 335 if (!string.IsNullOrEmpty(buttonPrimaryHoverBackgroundColor)) 336 { 337 sb.AppendLine($"--swift-button-primary-hover-background-color: {buttonPrimaryHoverBackgroundColor};"); 338 sb.AppendLine($"--swift-button-primary-hover-background-color-rgb: {HexToRGB(buttonPrimaryHoverBackgroundColor)};"); 339 } 340 if (!string.IsNullOrEmpty(buttonPrimaryHoverForegroundColor)) 341 { 342 sb.AppendLine($"--swift-button-primary-hover-foreground-color: {buttonPrimaryHoverForegroundColor};"); 343 sb.AppendLine($"--swift-button-primary-hover-foreground-color-rgb: {HexToRGB(buttonPrimaryHoverForegroundColor)};"); 344 } 345 if (!string.IsNullOrEmpty(buttonPrimaryHoverBorderColor)) 346 { 347 sb.AppendLine($"--swift-button-primary-hover-border-color: {buttonPrimaryHoverBorderColor};"); 348 sb.AppendLine($"--swift-button-primary-hover-border-color-rgb: {HexToRGB(buttonPrimaryHoverBorderColor)};"); 349 } 350 351 if (!string.IsNullOrEmpty(buttonSecondaryBackgroundColor)) 352 { 353 sb.AppendLine($"--swift-button-secondary-background-color: {buttonSecondaryBackgroundColor};"); 354 sb.AppendLine($"--swift-button-secondary-background-color-rgb: {HexToRGB(buttonSecondaryBackgroundColor)};"); 355 } 356 if (!string.IsNullOrEmpty(buttonSecondaryForegroundColor)) 357 { 358 sb.AppendLine($"--swift-button-secondary-foreground-color: {buttonSecondaryForegroundColor};"); 359 sb.AppendLine($"--swift-button-secondary-foreground-color-rgb: {HexToRGB(buttonSecondaryForegroundColor)};"); 360 } 361 if (!string.IsNullOrEmpty(buttonSecondaryBorderColor)) 362 { 363 sb.AppendLine($"--swift-button-secondary-border-color: {buttonSecondaryBorderColor};"); 364 sb.AppendLine($"--swift-button-secondary-border-color-rgb: {HexToRGB(buttonSecondaryBorderColor)};"); 365 } 366 if (!string.IsNullOrEmpty(buttonSecondaryHoverBackgroundColor)) 367 { 368 sb.AppendLine($"--swift-button-secondary-hover-background-color: {buttonSecondaryHoverBackgroundColor};"); 369 sb.AppendLine($"--swift-button-secondary-hover-background-color-rgb: {HexToRGB(buttonSecondaryHoverBackgroundColor)};"); 370 } 371 if (!string.IsNullOrEmpty(buttonSecondaryHoverForegroundColor)) 372 { 373 sb.AppendLine($"--swift-button-secondary-hover-foreground-color: {buttonSecondaryHoverForegroundColor};"); 374 sb.AppendLine($"--swift-button-secondary-hover-foreground-color-rgb: {HexToRGB(buttonSecondaryHoverForegroundColor)};"); 375 } 376 if (!string.IsNullOrEmpty(buttonSecondaryHoverBorderColor)) 377 { 378 sb.AppendLine($"--swift-button-secondary-hover-border-color: {buttonSecondaryHoverBorderColor};"); 379 sb.AppendLine($"--swift-button-secondary-hover-border-color-rgb: {HexToRGB(buttonSecondaryHoverBorderColor)};"); 380 } 381 if (!string.IsNullOrEmpty(buttonLinkColor)) 382 { 383 sb.AppendLine($"--swift-button-link-color: {buttonLinkColor};"); 384 sb.AppendLine($"--swift-button-link-color-rgb: {HexToRGB(buttonLinkColor)};"); 385 } 386 if (!string.IsNullOrEmpty(buttonLinkHoverColor)) 387 { 388 sb.AppendLine($"--swift-button-link-hover-color: {buttonLinkHoverColor};"); 389 sb.AppendLine($"--swift-button-link-hover-color-rgb: {HexToRGB(buttonLinkHoverColor)};"); 390 } 391 if (!string.IsNullOrEmpty(accessibilityOutlineColor)) 392 { 393 sb.AppendLine($"--swift-a11y-outline-color: {accessibilityOutlineColor};"); 394 sb.AppendLine($"--swift-a11y-outline-color-rgb: {HexToRGB(accessibilityOutlineColor)};"); 395 } 396 sb.AppendLine("}"); 397 398 Dynamicweb.Core.Helpers.TextFileHelper.WriteTextFile(sb.ToString() + Environment.NewLine, Dynamicweb.Context.Current.Server.MapPath($"/Files/Templates/Designs/Swift/_parsed/Swift_css/Swift_theme_styles_{Dynamicweb.Content.Services.Pages.GetPage(Model.PageID).AreaId}.tmp"), true); 399 } 400 } 401 402 @if (themeClassName != "") 403 { 404 string iconPath = "/Files/Templates/Designs/Swift/Assets/icons/"; 405 406 <div class="g-col-12 g-col-lg-4"> 407 <div class="swift-checkered p-3"> 408 <div class="theme-option theme @themeClassName p-lg-3"> 409 <div class="mb-2 pb-1 border-bottom d-flex align-items-center"> 410 <span class="icon-3 me-2"> 411 @ReadFile(iconPath + "sun.svg") 412 </span> 413 <h4 class="m-0 p-0">@themeName</h4> 414 </div> 415 <div class="d-flex flex-column gap-1 mb-2"> 416 <p class="mb-0">This is the body text of the theme.</p> 417 <p class="mb-0" style="color: var(--swift-accent-color)">This is the accent color of the theme.</p> 418 </div> 419 <div> 420 <button class="btn btn-primary me-1">Primary</button> 421 <button class="btn btn-secondary">Secondary</button> 422 <button class="btn btn-link">Link</button> 423 </div> 424 </div> 425 </div> 426 </div> 427 <div class="g-col-12 g-col-lg-8 mb-4 mb-lg-0"> 428 <div class="grid fs-7"> 429 <div class="g-col-12 g-col-lg-3"> 430 <table class="table table-borderless table-sm w-100"> 431 <thead> 432 <tr> 433 <th colspan="2" class="fw-bold">@Translate("Base")</th> 434 </tr> 435 </thead> 436 <tr> 437 <td>@Translate("Foreground")</td> 438 <td>@GetColorSquare(foregroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@foregroundColor');">@foregroundColor</a></td> 439 </tr> 440 <tr> 441 <td>@Translate("Background")</td> 442 <td>@GetColorSquare(backgroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@backgroundColor');">@backgroundColor</a></td> 443 </tr> 444 <tr> 445 <td>@Translate("Accent")</td> 446 <td>@GetColorSquare(accentColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@accentColor');">@accentColor</a></td> 447 </tr> 448 <tr> 449 <td>@Translate("Border")</td> 450 <td>@GetColorSquare(borderColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@borderColor');">@borderColor</a></td> 451 </tr> 452 </table> 453 </div> 454 <div class="g-col-12 g-col-lg-3"> 455 <table class="table table-borderless table-sm w-100"> 456 <thead> 457 <tr> 458 <th colspan="2" class="fw-bold">@Translate("Primary button")</th> 459 </tr> 460 </thead> 461 <tr> 462 <td>@Translate("Foreground")</td> 463 <td>@GetColorSquare(buttonPrimaryForegroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonPrimaryForegroundColor');">@buttonPrimaryForegroundColor</a></td> 464 </tr> 465 <tr> 466 <td>@Translate("Background")</td> 467 <td>@GetColorSquare(buttonPrimaryBackgroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonPrimaryBackgroundColor');">@buttonPrimaryBackgroundColor</a></td> 468 </tr> 469 @if (!string.IsNullOrEmpty(buttonPrimaryBorderColor)) 470 { 471 <tr> 472 <td>@Translate("Border")</td> 473 <td>@GetColorSquare(buttonPrimaryBorderColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonPrimaryBorderColor');">@buttonPrimaryBorderColor</a></td> 474 </tr> 475 } 476 <thead> 477 <tr> 478 <th colspan="2" class="fw-bold">@Translate("Primary button hover")</th> 479 </tr> 480 </thead> 481 @if (!string.IsNullOrEmpty(buttonPrimaryHoverForegroundColor)) 482 { 483 <tr> 484 <td>@Translate("Foreground")</td> 485 <td>@GetColorSquare(buttonPrimaryHoverForegroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonPrimaryHoverForegroundColor');">@buttonPrimaryHoverForegroundColor</a></td> 486 </tr> 487 } 488 @if (!string.IsNullOrEmpty(buttonPrimaryHoverBackgroundColor)) 489 { 490 <tr> 491 <td>@Translate("Background")</td> 492 <td>@GetColorSquare(buttonPrimaryHoverBackgroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonPrimaryHoverBackgroundColor');">@buttonPrimaryHoverBackgroundColor</a></td> 493 </tr> 494 } 495 @if (!string.IsNullOrEmpty(buttonPrimaryHoverBorderColor)) 496 { 497 <tr> 498 <td>@Translate("Border")</td> 499 <td>@GetColorSquare(buttonPrimaryHoverBorderColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonPrimaryHoverBorderColor');">@buttonPrimaryHoverBorderColor</a></td> 500 </tr> 501 } 502 </table> 503 </div> 504 <div class="g-col-12 g-col-lg-3"> 505 <table class="table table-borderless table-sm w-100"> 506 <thead> 507 <tr> 508 <th colspan="2" class="fw-bold">@Translate("Secondary button")</th> 509 </tr> 510 </thead> 511 <tr> 512 <td>@Translate("Foreground")</td> 513 <td>@GetColorSquare(buttonSecondaryForegroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonSecondaryForegroundColor');">@buttonSecondaryForegroundColor</a></td> 514 </tr> 515 <tr> 516 <td>@Translate("Background")</td> 517 <td>@GetColorSquare(buttonSecondaryBackgroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonSecondaryBackgroundColor');">@buttonSecondaryBackgroundColor</a></td> 518 </tr> 519 @if (!string.IsNullOrEmpty(buttonSecondaryBorderColor)) 520 { 521 <tr> 522 <td>@Translate("Border")</td> 523 <td>@GetColorSquare(buttonSecondaryBorderColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonSecondaryBorderColor');">@buttonSecondaryBorderColor</a></td> 524 </tr> 525 } 526 <thead> 527 <tr> 528 <th colspan="2" class="fw-bold">@Translate("Secondary button hover")</th> 529 </tr> 530 </thead> 531 @if (!string.IsNullOrEmpty(buttonSecondaryHoverForegroundColor)) 532 { 533 <tr> 534 <td>@Translate("Foreground")</td> 535 <td>@GetColorSquare(buttonSecondaryHoverForegroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonSecondaryHoverForegroundColor');">@buttonSecondaryHoverForegroundColor</a></td> 536 </tr> 537 } 538 @if (!string.IsNullOrEmpty(buttonSecondaryHoverBackgroundColor)) 539 { 540 <tr> 541 <td>@Translate("Background")</td> 542 <td>@GetColorSquare(buttonSecondaryHoverBackgroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonSecondaryHoverBackgroundColor');">@buttonSecondaryHoverBackgroundColor</a></td> 543 </tr> 544 } 545 @if (!string.IsNullOrEmpty(buttonSecondaryHoverBorderColor)) 546 { 547 <tr> 548 <td>@Translate("Border")</td> 549 <td>@GetColorSquare(buttonSecondaryHoverBorderColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonSecondaryHoverBorderColor');">@buttonSecondaryHoverBorderColor</a></td> 550 </tr> 551 } 552 @if (!string.IsNullOrEmpty(accessibilityOutlineColor)) 553 { 554 <tr> 555 <td>@Translate("Focus outline")</td> 556 <td>@GetColorSquare(accessibilityOutlineColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@accessibilityOutlineColor');">@accessibilityOutlineColor</a></td> 557 </tr> 558 } 559 </table> 560 </div> 561 <div class="g-col-12 g-col-lg-3"> 562 <table class="table table-borderless table-sm w-100"> 563 <thead> 564 <tr> 565 <th colspan="2" class="fw-bold">@Translate("Link button")</th> 566 </tr> 567 </thead> 568 <tr> 569 <td>@Translate("Link color")</td> 570 <td>@GetColorSquare(buttonLinkColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonLinkColor');">@buttonLinkColor</a></td> 571 </tr> 572 <thead> 573 <tr> 574 <th colspan="2" class="fw-bold">@Translate("Link button hover")</th> 575 </tr> 576 </thead> 577 @if (!string.IsNullOrEmpty(buttonLinkHoverColor)) 578 { 579 <tr> 580 <td>@Translate("Link hover color")</td> 581 <td>@GetColorSquare(buttonLinkHoverColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonLinkHoverColor');">@buttonLinkHoverColor</a></td> 582 </tr> 583 } 584 585 @if (!string.IsNullOrEmpty(accessibilityOutlineColor)) 586 { 587 <tr> 588 <td>@Translate("Focus outline")</td> 589 <td>@GetColorSquare(accessibilityOutlineColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@accessibilityOutlineColor');">@accessibilityOutlineColor</a></td> 590 </tr> 591 } 592 </table> 593 </div> 594 <div class="g-col-12 g-col-lg-3"> 595 <table class="table table-borderless table-sm w-100"> 596 <tr> 597 <td class="fw-bold">@Translate("Implementation")</td> 598 </tr> 599 <tr> 600 <td> 601 @{ 602 string implementation = $"<div class=\"theme {themeClassName}\"></div>"; 603 } 604 <div class="text-muted"> 605 <code class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@themeClassName');"> 606 @Dynamicweb.Core.Encoders.HtmlEncoder.HtmlEncode(implementation) 607 </code> 608 </div> 609 </td> 610 </tr> 611 </table> 612 </div> 613 @{ 614 bool hasUsageData = Converter.ToBoolean(Dynamicweb.Context.Current.Request["auditUsages"]); 615 if (hasUsageData) 616 { 617 var themeUsage = GetThemeUsageById(themeClassName); 618 int allUsages = themeUsage?.AllUsages ?? 0; 619 string buttonAttributes = allUsages > 0 ? $"data-bs-toggle=\"modal\" data-bs-target=\"#themeUsage_{Model.ID}\"" : string.Empty; 620 string badgeStyle = allUsages > 0 ? "bg-success" : "bg-danger"; 621 622 <div class="g-col-12 g-col-lg-9 position-relative"> 623 <button type="button" class="btn btn-primary btn-sm position-absolute end-0" @buttonAttributes> 624 Usages 625 <span class="position-absolute top-0 start-100 translate-middle badge rounded-pill text-white @badgeStyle">@allUsages</span> 626 </button> 627 628 @if (allUsages > 0) 629 { 630 int websiteUsages = themeUsage?.WebsiteUsages.Count ?? 0; 631 int pageUsages = themeUsage?.PageUsages.Count ?? 0; 632 int pagePropertyUsages = themeUsage?.PagePropertyUsages.Count ?? 0; 633 int gridRowUsages = themeUsage?.GridRowUsages.Count ?? 0; 634 int paragraphUsages = themeUsage?.ParagraphUsages.Count ?? 0; 635 636 <!-- Modal --> 637 <div class="modal fade" id="themeUsage_@(Model.ID)" tabindex="-1" aria-labelledby="usagesModelLabel" aria-hidden="true"> 638 <div class="modal-dialog modal-xl modal-dialog-centered modal-dialog-scrollable"> 639 <div class="modal-content"> 640 <div class="modal-header"> 641 <h5 class="modal-title" id="usagesModelLabel">@allUsages Usages of '@(themeName)' (@(themeClassName))</h5> 642 <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> 643 </div> 644 <div class="modal-body"> 645 <div class="accordion" id="accordionWrapper"> 646 @if(websiteUsages > 0) 647 { 648 <div class="accordion-item"> 649 <h2 class="accordion-header" id="headingWebsites"> 650 <button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#collapseWebsites" aria-expanded="true" aria-controls="collapseWebsites"> 651 <span class="pe-2">Websites</span><span class="badge rounded-pill bg-secondary text-light">@websiteUsages</span> 652 </button> 653 </h2> 654 <div id="collapseWebsites" class="accordion-collapse collapse show" aria-labelledby="headingWebsites" data-bs-parent="#accordionWrapper"> 655 <div class="accordion-body"> 656 <ul> 657 @foreach (var usage in themeUsage.WebsiteUsages) 658 { 659 var website = Dynamicweb.Content.Services.Areas.GetArea(usage); 660 <li><span class="fw-bold">@website.Name</span>@($" (ID: {usage})")</li> 661 } 662 </ul> 663 </div> 664 </div> 665 </div> 666 } 667 @if (pageUsages > 0) 668 { 669 var pages = Dynamicweb.Content.Services.Pages.GetPages(themeUsage.PageUsages.ToArray()); 670 671 <div class="accordion-item"> 672 <h2 class="accordion-header" id="headingPages"> 673 <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapsePages" aria-expanded="false" aria-controls="collapsePages"> 674 <span class="pe-2">Pages</span><span class="badge rounded-pill bg-secondary text-light">@pageUsages</span> 675 </button> 676 </h2> 677 <div id="collapsePages" class="accordion-collapse collapse" aria-labelledby="headingPages" data-bs-parent="#accordionWrapper"> 678 <div class="accordion-body"> 679 <ul> 680 @foreach (var usage in themeUsage.PageUsages) 681 { 682 <li><span class="fw-bold">@pages.FirstOrDefault(p => p.ID == usage).GetDisplayName()</span>@($" (ID: {usage})")</li> 683 } 684 </ul> 685 </div> 686 </div> 687 </div> 688 } 689 @if (pagePropertyUsages > 0) 690 { 691 var pages = Dynamicweb.Content.Services.Pages.GetPages(themeUsage.PageUsages.ToArray()); 692 693 <div class="accordion-item"> 694 <h2 class="accordion-header" id="headingPageProperties"> 695 <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapsePageProperties" aria-expanded="false" aria-controls="collapsePageProperties"> 696 <span class="pe-2">Page Properties</span><span class="badge rounded-pill bg-secondary text-light">@pagePropertyUsages</span> 697 </button> 698 </h2> 699 <div id="collapsePageProperties" class="accordion-collapse collapse" aria-labelledby="headingPageProperties" data-bs-parent="#accordionWrapper"> 700 <div class="accordion-body"> 701 <ul> 702 @foreach (var usage in themeUsage.PagePropertyUsages) 703 { 704 <li><span class="fw-bold">@pages.FirstOrDefault(p => p.ID == usage).GetDisplayName()</span>@($" (ID: {usage})")</li> 705 } 706 </ul> 707 </div> 708 </div> 709 </div> 710 } 711 @if (gridRowUsages > 0) 712 { 713 var rows = Dynamicweb.Content.Services.Grids.GetGridRows().Where(r => themeUsage.GridRowUsages.Contains(r.ID)).ToList(); 714 715 <div class="accordion-item"> 716 <h2 class="accordion-header" id="headingRows"> 717 <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseRows" aria-expanded="false" aria-controls="collapseRows"> 718 <span class="pe-2">Rows</span><span class="badge rounded-pill bg-secondary text-light">@gridRowUsages</span> 719 </button> 720 </h2> 721 <div id="collapseRows" class="accordion-collapse collapse" aria-labelledby="headingRows" data-bs-parent="#accordionWrapper"> 722 <div class="accordion-body"> 723 <ul> 724 @foreach (var usage in themeUsage.GridRowUsages) 725 { 726 var row = rows.FirstOrDefault(r => r.ID == usage); 727 var page = Dynamicweb.Content.Services.Pages.GetPage(row.PageId); 728 <li>Page: <span class="fw-bold">@(page.GetDisplayName())</span>@($"( ID: {page.ID}) - Row: ")<span class="fw-bold">@(row.DefinitionId)</span>@($" (ID: {usage})")</li> 729 } 730 </ul> 731 </div> 732 </div> 733 </div> 734 } 735 @if (paragraphUsages > 0) 736 { 737 var paragraphs = Dynamicweb.Content.Services.Paragraphs.GetParagraphs().Where(p => themeUsage.ParagraphUsages.Contains(p.ID)).ToList(); 738 739 <div class="accordion-item"> 740 <h2 class="accordion-header" id="headingParagraphs"> 741 <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseParagraphs" aria-expanded="false" aria-controls="collapseParagraphs"> 742 <span class="pe-2">Paragraphs</span><span class="badge rounded-pill bg-secondary text-light">@paragraphUsages</span> 743 </button> 744 </h2> 745 <div id="collapseParagraphs" class="accordion-collapse collapse" aria-labelledby="headingParagraphs" data-bs-parent="#accordionWrapper"> 746 <div class="accordion-body"> 747 <ul> 748 @foreach (var usage in themeUsage.ParagraphUsages) 749 { 750 var paragraph = paragraphs.FirstOrDefault(p => p.ID == usage); 751 var page = Dynamicweb.Content.Services.Pages.GetPage(paragraph.PageID); 752 <li>Page: <span class="fw-bold">@(page.GetDisplayName())</span>@($"( ID: {page.ID}) - Paragraph: ")<span class="fw-bold">@paragraph.Header</span>@($" (ID: {usage})")</li> 753 } 754 </ul> 755 </div> 756 </div> 757 </div> 758 } 759 </div> 760 </div> 761 </div> 762 </div> 763 </div> 764 } 765 </div> 766 } 767 } 768 </div> 769 </div> 770 } 771 <div class="g-col-12"> 772 <hr /> 773 </div> 774
Error executing template "Designs/Swift/Paragraph/Swift_Theme.cshtml" System.Data.SqlClient.SqlException (0x80131904): STRING_AGG aggregation result exceeded the limit of 8000 bytes. Use LOB types to avoid result truncation. at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction) at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose) at System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady) at System.Data.SqlClient.SqlDataReader.TryConsumeMetaData() at System.Data.SqlClient.SqlDataReader.get_MetaData() at System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString, Boolean isInternal, Boolean forDescribeParameterEncryption, Boolean shouldCacheForAlwaysEncrypted) at System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async, Int32 timeout, Task& task, Boolean asyncWrite, Boolean inRetry, SqlDataReader ds, Boolean describeParameterEncryptionRequest) at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, TaskCompletionSource`1 completion, Int32 timeout, Task& task, Boolean& usedCache, Boolean asyncWrite, Boolean inRetry) at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method) at System.Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior behavior, String method) at Dynamicweb.Data.Database.CreateDataReader(IDbCommand command, CommandBehavior behavior) at Dynamicweb.Data.Database.CreateDataReader(String sql, IDbConnection connection, IDbTransaction transaction, CommandBehavior behavior, Int32 commandTimeout, Dictionary`2 sqlParams) at Dynamicweb.Data.Database.CreateDataReader(String sql, IDbConnection connection, IDbTransaction transaction, Int32 commandTimeout, Dictionary`2 sqlParams) at Dynamicweb.Data.Database.CreateDataReader(String sql) at CompiledRazorTemplates.Dynamic.RazorEngine_8e3f1b11eb0041ceb2ca487c2be837e6.UpdateThemeUsages(String sqlQuery, List`1 themeUsages) in E:\Dynamicweb.net\Solutions\Dynamicweb\dw2022.cloud.dynamicweb-cms.com\Files\Templates\Designs\Swift\Paragraph\Swift_Theme.cshtml:line 202 at CompiledRazorTemplates.Dynamic.RazorEngine_8e3f1b11eb0041ceb2ca487c2be837e6.GetAllThemeUsages() in E:\Dynamicweb.net\Solutions\Dynamicweb\dw2022.cloud.dynamicweb-cms.com\Files\Templates\Designs\Swift\Paragraph\Swift_Theme.cshtml:line 184 at CompiledRazorTemplates.Dynamic.RazorEngine_8e3f1b11eb0041ceb2ca487c2be837e6.GetThemeUsageById(String themeId) in E:\Dynamicweb.net\Solutions\Dynamicweb\dw2022.cloud.dynamicweb-cms.com\Files\Templates\Designs\Swift\Paragraph\Swift_Theme.cshtml:line 238 at CompiledRazorTemplates.Dynamic.RazorEngine_8e3f1b11eb0041ceb2ca487c2be837e6.Execute() in E:\Dynamicweb.net\Solutions\Dynamicweb\dw2022.cloud.dynamicweb-cms.com\Files\Templates\Designs\Swift\Paragraph\Swift_Theme.cshtml:line 617 at RazorEngine.Templating.TemplateBase.RazorEngine.Templating.ITemplate.Run(ExecuteContext context, TextWriter reader) at RazorEngine.Templating.RazorEngineService.RunCompile(ITemplateKey key, TextWriter writer, Type modelType, Object model, DynamicViewBag viewBag) at RazorEngine.Templating.RazorEngineServiceExtensions.<>c__DisplayClass16_0.<RunCompile>b__0(TextWriter writer) at RazorEngine.Templating.RazorEngineServiceExtensions.WithWriter(Action`1 withWriter) at Dynamicweb.Rendering.RazorTemplateRenderingProvider.Render(Template template) at Dynamicweb.Rendering.TemplateRenderingService.Render(Template template) at Dynamicweb.Rendering.Template.RenderRazorTemplate() ClientConnectionId:b42d1cec-597c-4eed-bdc2-e0762a41101a Error Number:9829,State:1,Class:16
1 @inherits Dynamicweb.Rendering.ViewModelTemplate<Dynamicweb.Frontend.ParagraphViewModel> 2 @using System.Globalization 3 @using System.Drawing 4 @using Dynamicweb.Core 5 6 @functions{ 7 // Get Hex Color from color picker and translate to RGB color 8 public static string HexToRGB(string hexString) 9 { 10 if (hexString.Equals("none") || string.IsNullOrEmpty(hexString)) 11 return hexString; 12 13 //replace # occurences 14 if (hexString.IndexOf('#') != -1) 15 hexString = hexString.Replace("#", ""); 16 try 17 { 18 int r, g, b = 0; 19 r = int.Parse(hexString.Substring(0, 2), NumberStyles.AllowHexSpecifier); 20 g = int.Parse(hexString.Substring(2, 2), NumberStyles.AllowHexSpecifier); 21 b = int.Parse(hexString.Substring(4, 2), NumberStyles.AllowHexSpecifier); 22 23 string rgb = r + "," + g + "," + b; 24 return rgb; 25 } 26 catch (System.Exception) 27 { 28 return hexString; 29 } 30 } 31 32 public static string GetColorSquare(string hex) 33 { 34 return $"<div class=\"swift-checkered d-inline-block me-1\" style=\"height:1.25rem;width:1.25rem;\"><div style=\"background-color: {hex};border:.0625rem solid grey\" class=\"w-100 h-100\"></div></div>"; 35 } 36 37 public class HSL 38 { 39 public double h { get; set; } 40 public double s { get; set; } 41 public double l { get; set; } 42 } 43 44 //Convert HEX to HSL 45 public static HSL HexToHsl(string hexString) 46 { 47 System.Drawing.Color color = System.Drawing.ColorTranslator.FromHtml(hexString); 48 49 float _R = (color.R / 255f); 50 float _G = (color.G / 255f); 51 float _B = (color.B / 255f); 52 53 float _Min = Math.Min(Math.Min(_R, _G), _B); 54 float _Max = Math.Max(Math.Max(_R, _G), _B); 55 float _Delta = _Max - _Min; 56 57 float S = 0; 58 float L = (float)((_Max + _Min) / 2.0f); 59 60 if (_Delta != 0) 61 { 62 if (L < 0.5f) 63 { 64 S = (float)(_Delta / (_Max + _Min)); 65 } 66 else 67 { 68 S = (float)(_Delta / (2.0f - _Max - _Min)); 69 } 70 } 71 72 HSL hsl = new HSL(); 73 hsl.h = Math.Round(color.GetHue(), 2); 74 hsl.s = Math.Round(S, 2) * 100; 75 hsl.l = Math.Round(L, 2) * 100; 76 77 return hsl; 78 } 79 80 //Find contrast color (white, black) 81 public static Color GetContrastColor(string hexString) 82 { 83 System.Drawing.Color bg = System.Drawing.ColorTranslator.FromHtml(hexString); 84 85 int nThreshold = 105; 86 int bgDelta = Convert.ToInt32((bg.R * 0.299) + (bg.G * 0.587) + 87 (bg.B * 0.114)); 88 89 Color foreColor = (255 - bgDelta < nThreshold) ? Color.Black : Color.White; 90 return foreColor; 91 } 92 93 public string GetColorVariation(string hexString) 94 { 95 var contrast = GetContrastColor(hexString); 96 HSL currentHslColor = HexToHsl(hexString); 97 HSL variantHslColor = currentHslColor; 98 99 if (contrast == Color.Black) 100 { 101 variantHslColor.l = 85; //The background is dark - Color should be light 102 } 103 else 104 { 105 variantHslColor.l = 40; //The background is light - Color should be less light 106 } 107 108 //Color is very light 109 if (currentHslColor.l > 85) 110 { 111 variantHslColor.l = 95; 112 } 113 114 string colorString = variantHslColor.h + ", " + variantHslColor.s + "%, " + variantHslColor.l + "%"; 115 return colorString; 116 } 117 118 private class ThemeDatabaseUsage 119 { 120 public string TableName { get; set; } 121 public string ColumnName { get; set; } 122 } 123 124 private class ThemeUsage 125 { 126 public string Id { get; set; } 127 public List<int> WebsiteUsages { get; set; } = new List<int>(); 128 public List<int> PageUsages { get; set; } = new List<int>(); 129 public List<int> PagePropertyUsages { get; set; } = new List<int>(); 130 public List<int> GridRowUsages { get; set; } = new List<int>(); 131 public List<int> ParagraphUsages { get; set; } = new List<int>(); 132 public int AllUsages { get; set; } = 0; 133 } 134 135 private List<ThemeDatabaseUsage> GetThemeColumnsFromSchema() 136 { 137 string cacheKey = "ThemesFromDatabase"; 138 if (Dynamicweb.Context.Current.Items.Contains(cacheKey)) 139 { 140 return (List<ThemeDatabaseUsage>)Dynamicweb.Context.Current.Items[cacheKey]; 141 } 142 var schema = Dynamicweb.Data.Database.CreateDataReader("SELECT table_name, column_name FROM information_schema.columns WHERE column_name LIKE '%Theme%'"); 143 144 var rawData = new List<ThemeDatabaseUsage>(); 145 while (schema.Read()) { 146 rawData.Add(new ThemeDatabaseUsage {TableName = schema["table_name"].ToString(), ColumnName = schema["column_name"].ToString() }); 147 } 148 Dynamicweb.Context.Current.Items[cacheKey] = rawData; 149 return rawData; 150 } 151 152 private List<ThemeUsage> GetAllThemeUsages() 153 { 154 string cacheKey = "ThemeUsages"; 155 if (Dynamicweb.Context.Current.Items.Contains(cacheKey)) 156 { 157 return (List<ThemeUsage>)Dynamicweb.Context.Current.Items[cacheKey]; 158 } 159 160 var rawData = GetThemeColumnsFromSchema(); 161 var themeUsages = new List<ThemeUsage>(); 162 163 var sqlQuery = ""; 164 foreach (var row in rawData) 165 { 166 if (!string.IsNullOrEmpty(sqlQuery)) { sqlQuery += " UNION ALL "; } 167 sqlQuery += $"SELECT '{row.TableName}' AS TableName, '{row.ColumnName}' AS ColumnName, {row.ColumnName} AS ColumnValue, Id, AreaId, Page.PageId, PageProperties.PageId as 'PagePropertiesId', GridRowId, ParagraphId" + 168 $" FROM [{row.TableName}]" + 169 $" LEFT JOIN Area ON AreaItemType = '{row.TableName.Replace("ItemType_","")}' AND AreaItemId = Id" + 170 $" LEFT JOIN Page ON PageItemType = '{row.TableName.Replace("ItemType_","")}' AND PageItemId = Id" + 171 $" LEFT JOIN Page as PageProperties ON AreaItemTypePageProperty = '{row.TableName.Replace("ItemType_","")}' AND PageProperties.PagePropertyItemId = Id" + 172 $" LEFT JOIN GridRow ON GridRowItemType = '{row.TableName.Replace("ItemType_","")}' AND GridRowItemId = Id" + 173 $" LEFT JOIN Paragraph ON ParagraphItemType = '{row.TableName.Replace("ItemType_","")}' AND ParagraphItemId = Id" + 174 $" WHERE {row.ColumnName} != '' AND {row.ColumnName} IS NOT NULL" + 175 $" AND (AreaId IS NULL OR AreaId = {Pageview.AreaID})" + 176 $" AND (Page.PageId IS NULL OR Page.PageAreaId = {Pageview.AreaID})" + 177 $" AND (PageProperties.PageId IS NULL OR PageProperties.PageAreaId = {Pageview.AreaID})" + 178 $" AND (GridRowId IS NULL OR GridRowPageId IN (SELECT value From string_split(@pageIds, ',')))" + 179 $" AND (ParagraphId IS NULL OR ParagraphPageId IN (SELECT value From string_split(@pageIds, ',')))"; 180 181 var maxMsSqlServerCharLimit = 60000; 182 if (sqlQuery.Length > maxMsSqlServerCharLimit) 183 { 184 UpdateThemeUsages(sqlQuery, themeUsages); 185 sqlQuery = ""; 186 } 187 } 188 189 if (!string.IsNullOrEmpty(sqlQuery)) 190 { 191 UpdateThemeUsages(sqlQuery, themeUsages); 192 } 193 UpdateAllUsages(themeUsages); 194 195 Dynamicweb.Context.Current.Items[cacheKey] = themeUsages; 196 return themeUsages; 197 } 198 199 private void UpdateThemeUsages(string sqlQuery, List<ThemeUsage> themeUsages) 200 { 201 sqlQuery = $"DECLARE @pageIds NVARCHAR(max) = (SELECT STRING_AGG(PageId,',') FROM Page WHERE PageAreaId = {Pageview.AreaID}) " + sqlQuery; 202 var rawData = Dynamicweb.Data.Database.CreateDataReader(sqlQuery); 203 while (rawData.Read()) 204 { 205 var themeId = rawData["ColumnValue"].ToString(); 206 var themeUsageExists = themeUsages.FirstOrDefault(t => t.Id == themeId) != null; 207 if (!themeUsageExists) 208 { 209 themeUsages.Add(new ThemeUsage { Id = themeId }); 210 } 211 212 var themeUsage = themeUsages.FirstOrDefault(t => t.Id == themeId); 213 if (themeUsage == null) continue; 214 215 if (Converter.ToInt32(rawData["AreaId"].ToString()) > 0) { themeUsage.WebsiteUsages.Add(Converter.ToInt32(rawData["AreaId"].ToString())); } 216 if (Converter.ToInt32(rawData["PageId"].ToString()) > 0) { themeUsage.PageUsages.Add(Converter.ToInt32(rawData["PageId"].ToString())); } 217 if (Converter.ToInt32(rawData["PagePropertiesId"].ToString()) > 0) { themeUsage.PagePropertyUsages.Add(Converter.ToInt32(rawData["PagePropertiesId"].ToString())); } 218 if (Converter.ToInt32(rawData["GridRowId"].ToString()) > 0) { themeUsage.GridRowUsages.Add(Converter.ToInt32(rawData["GridRowId"].ToString())); } 219 if (Converter.ToInt32(rawData["ParagraphId"].ToString()) > 0) { themeUsage.ParagraphUsages.Add(Converter.ToInt32(rawData["ParagraphId"].ToString())); } 220 } 221 } 222 223 private void UpdateAllUsages(List<ThemeUsage> themeUsages) 224 { 225 foreach (var themeUsage in themeUsages) 226 { 227 int websiteUsages = themeUsage?.WebsiteUsages.Count ?? 0; 228 int pageUsages = themeUsage?.PageUsages.Count ?? 0; 229 int pagePropertyUsages = themeUsage?.PagePropertyUsages.Count ?? 0; 230 int gridRowUsages = themeUsage?.GridRowUsages.Count ?? 0; 231 int paragraphUsages = themeUsage?.ParagraphUsages.Count ?? 0; 232 themeUsage.AllUsages = websiteUsages + pageUsages + pagePropertyUsages + gridRowUsages + paragraphUsages; 233 } 234 } 235 236 private ThemeUsage GetThemeUsageById(string themeId) 237 { 238 var themeUsages = GetAllThemeUsages(); 239 return themeUsages.FirstOrDefault(t => t.Id == themeId); 240 } 241 242 } 243 244 @{ 245 string themeName = !string.IsNullOrWhiteSpace(Model.Item.GetString("Name")) ? Model.Item.GetString("Name") : "Default"; 246 string themeClassName = !string.IsNullOrWhiteSpace(Model.Item.GetString("CSSClassName")) ? Model.Item.GetString("CSSClassName").Replace(" ", "").Trim().ToLower() : ""; 247 248 //Theme colors 249 string foregroundColor = Model.Item.GetString("ForegroundColor", "currentColor"); 250 string backgroundColor = Model.Item.GetString("BackgroundColor", "transparent"); 251 string accentColor = Model.Item.GetString("accentColor", "currentColor"); 252 string borderColor = Model.Item.GetString("BorderColor", "transparent"); 253 254 //Primary button 255 string buttonPrimaryForegroundColor = Model.Item.GetString("ButtonPrimaryForegroundColor", "currentColor"); 256 string buttonPrimaryBackgroundColor = Model.Item.GetString("ButtonPrimaryBackgroundColor", "transparent"); 257 string buttonPrimaryBorderColor = Model.Item.GetString("ButtonPrimaryBorderColor", "transparent"); 258 259 string buttonPrimaryHoverBackgroundColorAuto = "transparent"; 260 if (buttonPrimaryBackgroundColor != "transparent") 261 { 262 buttonPrimaryHoverBackgroundColorAuto = "hsl(" + GetColorVariation(buttonPrimaryBackgroundColor) + ")"; 263 } 264 string buttonPrimaryHoverForegroundColor = Model.Item.GetString("ButtonPrimaryHoverForegroundColor", buttonPrimaryForegroundColor); 265 string buttonPrimaryHoverBackgroundColor = Model.Item.GetString("ButtonPrimaryHoverBackgroundColor", buttonPrimaryHoverBackgroundColorAuto); 266 string buttonPrimaryHoverBorderColor = Model.Item.GetString("ButtonPrimaryHoverBorderColor", buttonPrimaryBorderColor); 267 268 //Secondary buton 269 string buttonSecondaryForegroundColor = Model.Item.GetString("ButtonSecondaryForegroundColor", "currentColor"); 270 string buttonSecondaryBackgroundColor = Model.Item.GetString("ButtonSecondaryBackgroundColor", "transparent"); 271 string buttonSecondaryBorderColor = Model.Item.GetString("ButtonSecondaryBorderColor", "transparent"); 272 273 string buttonSecondaryHoverBackgroundColorAuto = "transparent"; 274 if (buttonSecondaryBackgroundColor != "transparent") 275 { 276 buttonSecondaryHoverBackgroundColorAuto = "hsl(" + GetColorVariation(buttonSecondaryBackgroundColor) + ")"; 277 } 278 string buttonSecondaryHoverForegroundColor = Model.Item.GetString("ButtonSecondaryHoverForegroundColor", buttonSecondaryForegroundColor); 279 string buttonSecondaryHoverBackgroundColor = Model.Item.GetString("ButtonSecondaryHoverBackgroundColor", buttonSecondaryHoverBackgroundColorAuto); 280 string buttonSecondaryHoverBorderColor = Model.Item.GetString("ButtonSecondaryHoverBorderColor", buttonSecondaryBorderColor); 281 282 //Link buton 283 string buttonLinkColor = Model.Item.GetString("ButtonLinkColor", "currentColor"); 284 string buttonLinkHoverColorAuto = "currentColor"; 285 if (buttonLinkColor != "currentColor") 286 { 287 buttonLinkHoverColorAuto = "hsl(" + GetColorVariation(buttonLinkColor) + ")"; 288 } 289 string buttonLinkHoverColor = Model.Item.GetString("ButtonLinkHoverColor", buttonLinkHoverColorAuto); 290 291 string accessibilityOutlineColor = Model.Item.GetString("OutlineColor") != null ? Model.Item.GetString("OutlineColor") : ""; 292 293 if (!string.IsNullOrEmpty(themeClassName)) 294 { 295 var sb = new System.Text.StringBuilder(); 296 297 sb.AppendLine("." + themeClassName + "{"); 298 if (!string.IsNullOrEmpty(foregroundColor)) 299 { 300 sb.AppendLine($"--swift-foreground-color: {foregroundColor};"); 301 sb.AppendLine($"--swift-foreground-color-rgb: {HexToRGB(foregroundColor)};"); 302 } 303 if (!string.IsNullOrEmpty(backgroundColor)) 304 { 305 sb.AppendLine($"--swift-background-color: {backgroundColor};"); 306 sb.AppendLine($"--swift-background-color-rgb: {HexToRGB(backgroundColor)};"); 307 } 308 if (!string.IsNullOrEmpty(accentColor)) 309 { 310 sb.AppendLine($"--swift-accent-color: {accentColor};"); 311 sb.AppendLine($"--swift-accent-color-rgb: {HexToRGB(accentColor)};"); 312 } 313 if (!string.IsNullOrEmpty(borderColor)) 314 { 315 sb.AppendLine($"--swift-border-color: {borderColor};"); 316 sb.AppendLine($"--swift-border-color-rgb: {HexToRGB(borderColor)};"); 317 } 318 319 if (!string.IsNullOrEmpty(buttonPrimaryBackgroundColor)) 320 { 321 sb.AppendLine($"--swift-button-primary-background-color: {buttonPrimaryBackgroundColor};"); 322 sb.AppendLine($"--swift-button-primary-background-color-rgb: {HexToRGB(buttonPrimaryBackgroundColor)};"); 323 } 324 if (!string.IsNullOrEmpty(buttonPrimaryForegroundColor)) 325 { 326 sb.AppendLine($"--swift-button-primary-foreground-color: {buttonPrimaryForegroundColor};"); 327 sb.AppendLine($"--swift-button-primary-foreground-color-rgb: {HexToRGB(buttonPrimaryForegroundColor)};"); 328 } 329 if (!string.IsNullOrEmpty(buttonPrimaryBorderColor)) 330 { 331 sb.AppendLine($"--swift-button-primary-border-color: {buttonPrimaryBorderColor};"); 332 sb.AppendLine($"--swift-button-primary-border-color-rgb: {HexToRGB(buttonPrimaryBorderColor)};"); 333 } 334 335 if (!string.IsNullOrEmpty(buttonPrimaryHoverBackgroundColor)) 336 { 337 sb.AppendLine($"--swift-button-primary-hover-background-color: {buttonPrimaryHoverBackgroundColor};"); 338 sb.AppendLine($"--swift-button-primary-hover-background-color-rgb: {HexToRGB(buttonPrimaryHoverBackgroundColor)};"); 339 } 340 if (!string.IsNullOrEmpty(buttonPrimaryHoverForegroundColor)) 341 { 342 sb.AppendLine($"--swift-button-primary-hover-foreground-color: {buttonPrimaryHoverForegroundColor};"); 343 sb.AppendLine($"--swift-button-primary-hover-foreground-color-rgb: {HexToRGB(buttonPrimaryHoverForegroundColor)};"); 344 } 345 if (!string.IsNullOrEmpty(buttonPrimaryHoverBorderColor)) 346 { 347 sb.AppendLine($"--swift-button-primary-hover-border-color: {buttonPrimaryHoverBorderColor};"); 348 sb.AppendLine($"--swift-button-primary-hover-border-color-rgb: {HexToRGB(buttonPrimaryHoverBorderColor)};"); 349 } 350 351 if (!string.IsNullOrEmpty(buttonSecondaryBackgroundColor)) 352 { 353 sb.AppendLine($"--swift-button-secondary-background-color: {buttonSecondaryBackgroundColor};"); 354 sb.AppendLine($"--swift-button-secondary-background-color-rgb: {HexToRGB(buttonSecondaryBackgroundColor)};"); 355 } 356 if (!string.IsNullOrEmpty(buttonSecondaryForegroundColor)) 357 { 358 sb.AppendLine($"--swift-button-secondary-foreground-color: {buttonSecondaryForegroundColor};"); 359 sb.AppendLine($"--swift-button-secondary-foreground-color-rgb: {HexToRGB(buttonSecondaryForegroundColor)};"); 360 } 361 if (!string.IsNullOrEmpty(buttonSecondaryBorderColor)) 362 { 363 sb.AppendLine($"--swift-button-secondary-border-color: {buttonSecondaryBorderColor};"); 364 sb.AppendLine($"--swift-button-secondary-border-color-rgb: {HexToRGB(buttonSecondaryBorderColor)};"); 365 } 366 if (!string.IsNullOrEmpty(buttonSecondaryHoverBackgroundColor)) 367 { 368 sb.AppendLine($"--swift-button-secondary-hover-background-color: {buttonSecondaryHoverBackgroundColor};"); 369 sb.AppendLine($"--swift-button-secondary-hover-background-color-rgb: {HexToRGB(buttonSecondaryHoverBackgroundColor)};"); 370 } 371 if (!string.IsNullOrEmpty(buttonSecondaryHoverForegroundColor)) 372 { 373 sb.AppendLine($"--swift-button-secondary-hover-foreground-color: {buttonSecondaryHoverForegroundColor};"); 374 sb.AppendLine($"--swift-button-secondary-hover-foreground-color-rgb: {HexToRGB(buttonSecondaryHoverForegroundColor)};"); 375 } 376 if (!string.IsNullOrEmpty(buttonSecondaryHoverBorderColor)) 377 { 378 sb.AppendLine($"--swift-button-secondary-hover-border-color: {buttonSecondaryHoverBorderColor};"); 379 sb.AppendLine($"--swift-button-secondary-hover-border-color-rgb: {HexToRGB(buttonSecondaryHoverBorderColor)};"); 380 } 381 if (!string.IsNullOrEmpty(buttonLinkColor)) 382 { 383 sb.AppendLine($"--swift-button-link-color: {buttonLinkColor};"); 384 sb.AppendLine($"--swift-button-link-color-rgb: {HexToRGB(buttonLinkColor)};"); 385 } 386 if (!string.IsNullOrEmpty(buttonLinkHoverColor)) 387 { 388 sb.AppendLine($"--swift-button-link-hover-color: {buttonLinkHoverColor};"); 389 sb.AppendLine($"--swift-button-link-hover-color-rgb: {HexToRGB(buttonLinkHoverColor)};"); 390 } 391 if (!string.IsNullOrEmpty(accessibilityOutlineColor)) 392 { 393 sb.AppendLine($"--swift-a11y-outline-color: {accessibilityOutlineColor};"); 394 sb.AppendLine($"--swift-a11y-outline-color-rgb: {HexToRGB(accessibilityOutlineColor)};"); 395 } 396 sb.AppendLine("}"); 397 398 Dynamicweb.Core.Helpers.TextFileHelper.WriteTextFile(sb.ToString() + Environment.NewLine, Dynamicweb.Context.Current.Server.MapPath($"/Files/Templates/Designs/Swift/_parsed/Swift_css/Swift_theme_styles_{Dynamicweb.Content.Services.Pages.GetPage(Model.PageID).AreaId}.tmp"), true); 399 } 400 } 401 402 @if (themeClassName != "") 403 { 404 string iconPath = "/Files/Templates/Designs/Swift/Assets/icons/"; 405 406 <div class="g-col-12 g-col-lg-4"> 407 <div class="swift-checkered p-3"> 408 <div class="theme-option theme @themeClassName p-lg-3"> 409 <div class="mb-2 pb-1 border-bottom d-flex align-items-center"> 410 <span class="icon-3 me-2"> 411 @ReadFile(iconPath + "sun.svg") 412 </span> 413 <h4 class="m-0 p-0">@themeName</h4> 414 </div> 415 <div class="d-flex flex-column gap-1 mb-2"> 416 <p class="mb-0">This is the body text of the theme.</p> 417 <p class="mb-0" style="color: var(--swift-accent-color)">This is the accent color of the theme.</p> 418 </div> 419 <div> 420 <button class="btn btn-primary me-1">Primary</button> 421 <button class="btn btn-secondary">Secondary</button> 422 <button class="btn btn-link">Link</button> 423 </div> 424 </div> 425 </div> 426 </div> 427 <div class="g-col-12 g-col-lg-8 mb-4 mb-lg-0"> 428 <div class="grid fs-7"> 429 <div class="g-col-12 g-col-lg-3"> 430 <table class="table table-borderless table-sm w-100"> 431 <thead> 432 <tr> 433 <th colspan="2" class="fw-bold">@Translate("Base")</th> 434 </tr> 435 </thead> 436 <tr> 437 <td>@Translate("Foreground")</td> 438 <td>@GetColorSquare(foregroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@foregroundColor');">@foregroundColor</a></td> 439 </tr> 440 <tr> 441 <td>@Translate("Background")</td> 442 <td>@GetColorSquare(backgroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@backgroundColor');">@backgroundColor</a></td> 443 </tr> 444 <tr> 445 <td>@Translate("Accent")</td> 446 <td>@GetColorSquare(accentColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@accentColor');">@accentColor</a></td> 447 </tr> 448 <tr> 449 <td>@Translate("Border")</td> 450 <td>@GetColorSquare(borderColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@borderColor');">@borderColor</a></td> 451 </tr> 452 </table> 453 </div> 454 <div class="g-col-12 g-col-lg-3"> 455 <table class="table table-borderless table-sm w-100"> 456 <thead> 457 <tr> 458 <th colspan="2" class="fw-bold">@Translate("Primary button")</th> 459 </tr> 460 </thead> 461 <tr> 462 <td>@Translate("Foreground")</td> 463 <td>@GetColorSquare(buttonPrimaryForegroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonPrimaryForegroundColor');">@buttonPrimaryForegroundColor</a></td> 464 </tr> 465 <tr> 466 <td>@Translate("Background")</td> 467 <td>@GetColorSquare(buttonPrimaryBackgroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonPrimaryBackgroundColor');">@buttonPrimaryBackgroundColor</a></td> 468 </tr> 469 @if (!string.IsNullOrEmpty(buttonPrimaryBorderColor)) 470 { 471 <tr> 472 <td>@Translate("Border")</td> 473 <td>@GetColorSquare(buttonPrimaryBorderColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonPrimaryBorderColor');">@buttonPrimaryBorderColor</a></td> 474 </tr> 475 } 476 <thead> 477 <tr> 478 <th colspan="2" class="fw-bold">@Translate("Primary button hover")</th> 479 </tr> 480 </thead> 481 @if (!string.IsNullOrEmpty(buttonPrimaryHoverForegroundColor)) 482 { 483 <tr> 484 <td>@Translate("Foreground")</td> 485 <td>@GetColorSquare(buttonPrimaryHoverForegroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonPrimaryHoverForegroundColor');">@buttonPrimaryHoverForegroundColor</a></td> 486 </tr> 487 } 488 @if (!string.IsNullOrEmpty(buttonPrimaryHoverBackgroundColor)) 489 { 490 <tr> 491 <td>@Translate("Background")</td> 492 <td>@GetColorSquare(buttonPrimaryHoverBackgroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonPrimaryHoverBackgroundColor');">@buttonPrimaryHoverBackgroundColor</a></td> 493 </tr> 494 } 495 @if (!string.IsNullOrEmpty(buttonPrimaryHoverBorderColor)) 496 { 497 <tr> 498 <td>@Translate("Border")</td> 499 <td>@GetColorSquare(buttonPrimaryHoverBorderColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonPrimaryHoverBorderColor');">@buttonPrimaryHoverBorderColor</a></td> 500 </tr> 501 } 502 </table> 503 </div> 504 <div class="g-col-12 g-col-lg-3"> 505 <table class="table table-borderless table-sm w-100"> 506 <thead> 507 <tr> 508 <th colspan="2" class="fw-bold">@Translate("Secondary button")</th> 509 </tr> 510 </thead> 511 <tr> 512 <td>@Translate("Foreground")</td> 513 <td>@GetColorSquare(buttonSecondaryForegroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonSecondaryForegroundColor');">@buttonSecondaryForegroundColor</a></td> 514 </tr> 515 <tr> 516 <td>@Translate("Background")</td> 517 <td>@GetColorSquare(buttonSecondaryBackgroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonSecondaryBackgroundColor');">@buttonSecondaryBackgroundColor</a></td> 518 </tr> 519 @if (!string.IsNullOrEmpty(buttonSecondaryBorderColor)) 520 { 521 <tr> 522 <td>@Translate("Border")</td> 523 <td>@GetColorSquare(buttonSecondaryBorderColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonSecondaryBorderColor');">@buttonSecondaryBorderColor</a></td> 524 </tr> 525 } 526 <thead> 527 <tr> 528 <th colspan="2" class="fw-bold">@Translate("Secondary button hover")</th> 529 </tr> 530 </thead> 531 @if (!string.IsNullOrEmpty(buttonSecondaryHoverForegroundColor)) 532 { 533 <tr> 534 <td>@Translate("Foreground")</td> 535 <td>@GetColorSquare(buttonSecondaryHoverForegroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonSecondaryHoverForegroundColor');">@buttonSecondaryHoverForegroundColor</a></td> 536 </tr> 537 } 538 @if (!string.IsNullOrEmpty(buttonSecondaryHoverBackgroundColor)) 539 { 540 <tr> 541 <td>@Translate("Background")</td> 542 <td>@GetColorSquare(buttonSecondaryHoverBackgroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonSecondaryHoverBackgroundColor');">@buttonSecondaryHoverBackgroundColor</a></td> 543 </tr> 544 } 545 @if (!string.IsNullOrEmpty(buttonSecondaryHoverBorderColor)) 546 { 547 <tr> 548 <td>@Translate("Border")</td> 549 <td>@GetColorSquare(buttonSecondaryHoverBorderColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonSecondaryHoverBorderColor');">@buttonSecondaryHoverBorderColor</a></td> 550 </tr> 551 } 552 @if (!string.IsNullOrEmpty(accessibilityOutlineColor)) 553 { 554 <tr> 555 <td>@Translate("Focus outline")</td> 556 <td>@GetColorSquare(accessibilityOutlineColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@accessibilityOutlineColor');">@accessibilityOutlineColor</a></td> 557 </tr> 558 } 559 </table> 560 </div> 561 <div class="g-col-12 g-col-lg-3"> 562 <table class="table table-borderless table-sm w-100"> 563 <thead> 564 <tr> 565 <th colspan="2" class="fw-bold">@Translate("Link button")</th> 566 </tr> 567 </thead> 568 <tr> 569 <td>@Translate("Link color")</td> 570 <td>@GetColorSquare(buttonLinkColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonLinkColor');">@buttonLinkColor</a></td> 571 </tr> 572 <thead> 573 <tr> 574 <th colspan="2" class="fw-bold">@Translate("Link button hover")</th> 575 </tr> 576 </thead> 577 @if (!string.IsNullOrEmpty(buttonLinkHoverColor)) 578 { 579 <tr> 580 <td>@Translate("Link hover color")</td> 581 <td>@GetColorSquare(buttonLinkHoverColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonLinkHoverColor');">@buttonLinkHoverColor</a></td> 582 </tr> 583 } 584 585 @if (!string.IsNullOrEmpty(accessibilityOutlineColor)) 586 { 587 <tr> 588 <td>@Translate("Focus outline")</td> 589 <td>@GetColorSquare(accessibilityOutlineColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@accessibilityOutlineColor');">@accessibilityOutlineColor</a></td> 590 </tr> 591 } 592 </table> 593 </div> 594 <div class="g-col-12 g-col-lg-3"> 595 <table class="table table-borderless table-sm w-100"> 596 <tr> 597 <td class="fw-bold">@Translate("Implementation")</td> 598 </tr> 599 <tr> 600 <td> 601 @{ 602 string implementation = $"<div class=\"theme {themeClassName}\"></div>"; 603 } 604 <div class="text-muted"> 605 <code class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@themeClassName');"> 606 @Dynamicweb.Core.Encoders.HtmlEncoder.HtmlEncode(implementation) 607 </code> 608 </div> 609 </td> 610 </tr> 611 </table> 612 </div> 613 @{ 614 bool hasUsageData = Converter.ToBoolean(Dynamicweb.Context.Current.Request["auditUsages"]); 615 if (hasUsageData) 616 { 617 var themeUsage = GetThemeUsageById(themeClassName); 618 int allUsages = themeUsage?.AllUsages ?? 0; 619 string buttonAttributes = allUsages > 0 ? $"data-bs-toggle=\"modal\" data-bs-target=\"#themeUsage_{Model.ID}\"" : string.Empty; 620 string badgeStyle = allUsages > 0 ? "bg-success" : "bg-danger"; 621 622 <div class="g-col-12 g-col-lg-9 position-relative"> 623 <button type="button" class="btn btn-primary btn-sm position-absolute end-0" @buttonAttributes> 624 Usages 625 <span class="position-absolute top-0 start-100 translate-middle badge rounded-pill text-white @badgeStyle">@allUsages</span> 626 </button> 627 628 @if (allUsages > 0) 629 { 630 int websiteUsages = themeUsage?.WebsiteUsages.Count ?? 0; 631 int pageUsages = themeUsage?.PageUsages.Count ?? 0; 632 int pagePropertyUsages = themeUsage?.PagePropertyUsages.Count ?? 0; 633 int gridRowUsages = themeUsage?.GridRowUsages.Count ?? 0; 634 int paragraphUsages = themeUsage?.ParagraphUsages.Count ?? 0; 635 636 <!-- Modal --> 637 <div class="modal fade" id="themeUsage_@(Model.ID)" tabindex="-1" aria-labelledby="usagesModelLabel" aria-hidden="true"> 638 <div class="modal-dialog modal-xl modal-dialog-centered modal-dialog-scrollable"> 639 <div class="modal-content"> 640 <div class="modal-header"> 641 <h5 class="modal-title" id="usagesModelLabel">@allUsages Usages of '@(themeName)' (@(themeClassName))</h5> 642 <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> 643 </div> 644 <div class="modal-body"> 645 <div class="accordion" id="accordionWrapper"> 646 @if(websiteUsages > 0) 647 { 648 <div class="accordion-item"> 649 <h2 class="accordion-header" id="headingWebsites"> 650 <button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#collapseWebsites" aria-expanded="true" aria-controls="collapseWebsites"> 651 <span class="pe-2">Websites</span><span class="badge rounded-pill bg-secondary text-light">@websiteUsages</span> 652 </button> 653 </h2> 654 <div id="collapseWebsites" class="accordion-collapse collapse show" aria-labelledby="headingWebsites" data-bs-parent="#accordionWrapper"> 655 <div class="accordion-body"> 656 <ul> 657 @foreach (var usage in themeUsage.WebsiteUsages) 658 { 659 var website = Dynamicweb.Content.Services.Areas.GetArea(usage); 660 <li><span class="fw-bold">@website.Name</span>@($" (ID: {usage})")</li> 661 } 662 </ul> 663 </div> 664 </div> 665 </div> 666 } 667 @if (pageUsages > 0) 668 { 669 var pages = Dynamicweb.Content.Services.Pages.GetPages(themeUsage.PageUsages.ToArray()); 670 671 <div class="accordion-item"> 672 <h2 class="accordion-header" id="headingPages"> 673 <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapsePages" aria-expanded="false" aria-controls="collapsePages"> 674 <span class="pe-2">Pages</span><span class="badge rounded-pill bg-secondary text-light">@pageUsages</span> 675 </button> 676 </h2> 677 <div id="collapsePages" class="accordion-collapse collapse" aria-labelledby="headingPages" data-bs-parent="#accordionWrapper"> 678 <div class="accordion-body"> 679 <ul> 680 @foreach (var usage in themeUsage.PageUsages) 681 { 682 <li><span class="fw-bold">@pages.FirstOrDefault(p => p.ID == usage).GetDisplayName()</span>@($" (ID: {usage})")</li> 683 } 684 </ul> 685 </div> 686 </div> 687 </div> 688 } 689 @if (pagePropertyUsages > 0) 690 { 691 var pages = Dynamicweb.Content.Services.Pages.GetPages(themeUsage.PageUsages.ToArray()); 692 693 <div class="accordion-item"> 694 <h2 class="accordion-header" id="headingPageProperties"> 695 <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapsePageProperties" aria-expanded="false" aria-controls="collapsePageProperties"> 696 <span class="pe-2">Page Properties</span><span class="badge rounded-pill bg-secondary text-light">@pagePropertyUsages</span> 697 </button> 698 </h2> 699 <div id="collapsePageProperties" class="accordion-collapse collapse" aria-labelledby="headingPageProperties" data-bs-parent="#accordionWrapper"> 700 <div class="accordion-body"> 701 <ul> 702 @foreach (var usage in themeUsage.PagePropertyUsages) 703 { 704 <li><span class="fw-bold">@pages.FirstOrDefault(p => p.ID == usage).GetDisplayName()</span>@($" (ID: {usage})")</li> 705 } 706 </ul> 707 </div> 708 </div> 709 </div> 710 } 711 @if (gridRowUsages > 0) 712 { 713 var rows = Dynamicweb.Content.Services.Grids.GetGridRows().Where(r => themeUsage.GridRowUsages.Contains(r.ID)).ToList(); 714 715 <div class="accordion-item"> 716 <h2 class="accordion-header" id="headingRows"> 717 <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseRows" aria-expanded="false" aria-controls="collapseRows"> 718 <span class="pe-2">Rows</span><span class="badge rounded-pill bg-secondary text-light">@gridRowUsages</span> 719 </button> 720 </h2> 721 <div id="collapseRows" class="accordion-collapse collapse" aria-labelledby="headingRows" data-bs-parent="#accordionWrapper"> 722 <div class="accordion-body"> 723 <ul> 724 @foreach (var usage in themeUsage.GridRowUsages) 725 { 726 var row = rows.FirstOrDefault(r => r.ID == usage); 727 var page = Dynamicweb.Content.Services.Pages.GetPage(row.PageId); 728 <li>Page: <span class="fw-bold">@(page.GetDisplayName())</span>@($"( ID: {page.ID}) - Row: ")<span class="fw-bold">@(row.DefinitionId)</span>@($" (ID: {usage})")</li> 729 } 730 </ul> 731 </div> 732 </div> 733 </div> 734 } 735 @if (paragraphUsages > 0) 736 { 737 var paragraphs = Dynamicweb.Content.Services.Paragraphs.GetParagraphs().Where(p => themeUsage.ParagraphUsages.Contains(p.ID)).ToList(); 738 739 <div class="accordion-item"> 740 <h2 class="accordion-header" id="headingParagraphs"> 741 <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseParagraphs" aria-expanded="false" aria-controls="collapseParagraphs"> 742 <span class="pe-2">Paragraphs</span><span class="badge rounded-pill bg-secondary text-light">@paragraphUsages</span> 743 </button> 744 </h2> 745 <div id="collapseParagraphs" class="accordion-collapse collapse" aria-labelledby="headingParagraphs" data-bs-parent="#accordionWrapper"> 746 <div class="accordion-body"> 747 <ul> 748 @foreach (var usage in themeUsage.ParagraphUsages) 749 { 750 var paragraph = paragraphs.FirstOrDefault(p => p.ID == usage); 751 var page = Dynamicweb.Content.Services.Pages.GetPage(paragraph.PageID); 752 <li>Page: <span class="fw-bold">@(page.GetDisplayName())</span>@($"( ID: {page.ID}) - Paragraph: ")<span class="fw-bold">@paragraph.Header</span>@($" (ID: {usage})")</li> 753 } 754 </ul> 755 </div> 756 </div> 757 </div> 758 } 759 </div> 760 </div> 761 </div> 762 </div> 763 </div> 764 } 765 </div> 766 } 767 } 768 </div> 769 </div> 770 } 771 <div class="g-col-12"> 772 <hr /> 773 </div> 774
Error executing template "Designs/Swift/Paragraph/Swift_Theme.cshtml" System.Data.SqlClient.SqlException (0x80131904): STRING_AGG aggregation result exceeded the limit of 8000 bytes. Use LOB types to avoid result truncation. at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction) at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose) at System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady) at System.Data.SqlClient.SqlDataReader.TryConsumeMetaData() at System.Data.SqlClient.SqlDataReader.get_MetaData() at System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString, Boolean isInternal, Boolean forDescribeParameterEncryption, Boolean shouldCacheForAlwaysEncrypted) at System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async, Int32 timeout, Task& task, Boolean asyncWrite, Boolean inRetry, SqlDataReader ds, Boolean describeParameterEncryptionRequest) at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, TaskCompletionSource`1 completion, Int32 timeout, Task& task, Boolean& usedCache, Boolean asyncWrite, Boolean inRetry) at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method) at System.Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior behavior, String method) at Dynamicweb.Data.Database.CreateDataReader(IDbCommand command, CommandBehavior behavior) at Dynamicweb.Data.Database.CreateDataReader(String sql, IDbConnection connection, IDbTransaction transaction, CommandBehavior behavior, Int32 commandTimeout, Dictionary`2 sqlParams) at Dynamicweb.Data.Database.CreateDataReader(String sql, IDbConnection connection, IDbTransaction transaction, Int32 commandTimeout, Dictionary`2 sqlParams) at Dynamicweb.Data.Database.CreateDataReader(String sql) at CompiledRazorTemplates.Dynamic.RazorEngine_8e3f1b11eb0041ceb2ca487c2be837e6.UpdateThemeUsages(String sqlQuery, List`1 themeUsages) in E:\Dynamicweb.net\Solutions\Dynamicweb\dw2022.cloud.dynamicweb-cms.com\Files\Templates\Designs\Swift\Paragraph\Swift_Theme.cshtml:line 202 at CompiledRazorTemplates.Dynamic.RazorEngine_8e3f1b11eb0041ceb2ca487c2be837e6.GetAllThemeUsages() in E:\Dynamicweb.net\Solutions\Dynamicweb\dw2022.cloud.dynamicweb-cms.com\Files\Templates\Designs\Swift\Paragraph\Swift_Theme.cshtml:line 184 at CompiledRazorTemplates.Dynamic.RazorEngine_8e3f1b11eb0041ceb2ca487c2be837e6.GetThemeUsageById(String themeId) in E:\Dynamicweb.net\Solutions\Dynamicweb\dw2022.cloud.dynamicweb-cms.com\Files\Templates\Designs\Swift\Paragraph\Swift_Theme.cshtml:line 238 at CompiledRazorTemplates.Dynamic.RazorEngine_8e3f1b11eb0041ceb2ca487c2be837e6.Execute() in E:\Dynamicweb.net\Solutions\Dynamicweb\dw2022.cloud.dynamicweb-cms.com\Files\Templates\Designs\Swift\Paragraph\Swift_Theme.cshtml:line 617 at RazorEngine.Templating.TemplateBase.RazorEngine.Templating.ITemplate.Run(ExecuteContext context, TextWriter reader) at RazorEngine.Templating.RazorEngineService.RunCompile(ITemplateKey key, TextWriter writer, Type modelType, Object model, DynamicViewBag viewBag) at RazorEngine.Templating.RazorEngineServiceExtensions.<>c__DisplayClass16_0.<RunCompile>b__0(TextWriter writer) at RazorEngine.Templating.RazorEngineServiceExtensions.WithWriter(Action`1 withWriter) at Dynamicweb.Rendering.RazorTemplateRenderingProvider.Render(Template template) at Dynamicweb.Rendering.TemplateRenderingService.Render(Template template) at Dynamicweb.Rendering.Template.RenderRazorTemplate() ClientConnectionId:b42d1cec-597c-4eed-bdc2-e0762a41101a Error Number:9829,State:1,Class:16
1 @inherits Dynamicweb.Rendering.ViewModelTemplate<Dynamicweb.Frontend.ParagraphViewModel> 2 @using System.Globalization 3 @using System.Drawing 4 @using Dynamicweb.Core 5 6 @functions{ 7 // Get Hex Color from color picker and translate to RGB color 8 public static string HexToRGB(string hexString) 9 { 10 if (hexString.Equals("none") || string.IsNullOrEmpty(hexString)) 11 return hexString; 12 13 //replace # occurences 14 if (hexString.IndexOf('#') != -1) 15 hexString = hexString.Replace("#", ""); 16 try 17 { 18 int r, g, b = 0; 19 r = int.Parse(hexString.Substring(0, 2), NumberStyles.AllowHexSpecifier); 20 g = int.Parse(hexString.Substring(2, 2), NumberStyles.AllowHexSpecifier); 21 b = int.Parse(hexString.Substring(4, 2), NumberStyles.AllowHexSpecifier); 22 23 string rgb = r + "," + g + "," + b; 24 return rgb; 25 } 26 catch (System.Exception) 27 { 28 return hexString; 29 } 30 } 31 32 public static string GetColorSquare(string hex) 33 { 34 return $"<div class=\"swift-checkered d-inline-block me-1\" style=\"height:1.25rem;width:1.25rem;\"><div style=\"background-color: {hex};border:.0625rem solid grey\" class=\"w-100 h-100\"></div></div>"; 35 } 36 37 public class HSL 38 { 39 public double h { get; set; } 40 public double s { get; set; } 41 public double l { get; set; } 42 } 43 44 //Convert HEX to HSL 45 public static HSL HexToHsl(string hexString) 46 { 47 System.Drawing.Color color = System.Drawing.ColorTranslator.FromHtml(hexString); 48 49 float _R = (color.R / 255f); 50 float _G = (color.G / 255f); 51 float _B = (color.B / 255f); 52 53 float _Min = Math.Min(Math.Min(_R, _G), _B); 54 float _Max = Math.Max(Math.Max(_R, _G), _B); 55 float _Delta = _Max - _Min; 56 57 float S = 0; 58 float L = (float)((_Max + _Min) / 2.0f); 59 60 if (_Delta != 0) 61 { 62 if (L < 0.5f) 63 { 64 S = (float)(_Delta / (_Max + _Min)); 65 } 66 else 67 { 68 S = (float)(_Delta / (2.0f - _Max - _Min)); 69 } 70 } 71 72 HSL hsl = new HSL(); 73 hsl.h = Math.Round(color.GetHue(), 2); 74 hsl.s = Math.Round(S, 2) * 100; 75 hsl.l = Math.Round(L, 2) * 100; 76 77 return hsl; 78 } 79 80 //Find contrast color (white, black) 81 public static Color GetContrastColor(string hexString) 82 { 83 System.Drawing.Color bg = System.Drawing.ColorTranslator.FromHtml(hexString); 84 85 int nThreshold = 105; 86 int bgDelta = Convert.ToInt32((bg.R * 0.299) + (bg.G * 0.587) + 87 (bg.B * 0.114)); 88 89 Color foreColor = (255 - bgDelta < nThreshold) ? Color.Black : Color.White; 90 return foreColor; 91 } 92 93 public string GetColorVariation(string hexString) 94 { 95 var contrast = GetContrastColor(hexString); 96 HSL currentHslColor = HexToHsl(hexString); 97 HSL variantHslColor = currentHslColor; 98 99 if (contrast == Color.Black) 100 { 101 variantHslColor.l = 85; //The background is dark - Color should be light 102 } 103 else 104 { 105 variantHslColor.l = 40; //The background is light - Color should be less light 106 } 107 108 //Color is very light 109 if (currentHslColor.l > 85) 110 { 111 variantHslColor.l = 95; 112 } 113 114 string colorString = variantHslColor.h + ", " + variantHslColor.s + "%, " + variantHslColor.l + "%"; 115 return colorString; 116 } 117 118 private class ThemeDatabaseUsage 119 { 120 public string TableName { get; set; } 121 public string ColumnName { get; set; } 122 } 123 124 private class ThemeUsage 125 { 126 public string Id { get; set; } 127 public List<int> WebsiteUsages { get; set; } = new List<int>(); 128 public List<int> PageUsages { get; set; } = new List<int>(); 129 public List<int> PagePropertyUsages { get; set; } = new List<int>(); 130 public List<int> GridRowUsages { get; set; } = new List<int>(); 131 public List<int> ParagraphUsages { get; set; } = new List<int>(); 132 public int AllUsages { get; set; } = 0; 133 } 134 135 private List<ThemeDatabaseUsage> GetThemeColumnsFromSchema() 136 { 137 string cacheKey = "ThemesFromDatabase"; 138 if (Dynamicweb.Context.Current.Items.Contains(cacheKey)) 139 { 140 return (List<ThemeDatabaseUsage>)Dynamicweb.Context.Current.Items[cacheKey]; 141 } 142 var schema = Dynamicweb.Data.Database.CreateDataReader("SELECT table_name, column_name FROM information_schema.columns WHERE column_name LIKE '%Theme%'"); 143 144 var rawData = new List<ThemeDatabaseUsage>(); 145 while (schema.Read()) { 146 rawData.Add(new ThemeDatabaseUsage {TableName = schema["table_name"].ToString(), ColumnName = schema["column_name"].ToString() }); 147 } 148 Dynamicweb.Context.Current.Items[cacheKey] = rawData; 149 return rawData; 150 } 151 152 private List<ThemeUsage> GetAllThemeUsages() 153 { 154 string cacheKey = "ThemeUsages"; 155 if (Dynamicweb.Context.Current.Items.Contains(cacheKey)) 156 { 157 return (List<ThemeUsage>)Dynamicweb.Context.Current.Items[cacheKey]; 158 } 159 160 var rawData = GetThemeColumnsFromSchema(); 161 var themeUsages = new List<ThemeUsage>(); 162 163 var sqlQuery = ""; 164 foreach (var row in rawData) 165 { 166 if (!string.IsNullOrEmpty(sqlQuery)) { sqlQuery += " UNION ALL "; } 167 sqlQuery += $"SELECT '{row.TableName}' AS TableName, '{row.ColumnName}' AS ColumnName, {row.ColumnName} AS ColumnValue, Id, AreaId, Page.PageId, PageProperties.PageId as 'PagePropertiesId', GridRowId, ParagraphId" + 168 $" FROM [{row.TableName}]" + 169 $" LEFT JOIN Area ON AreaItemType = '{row.TableName.Replace("ItemType_","")}' AND AreaItemId = Id" + 170 $" LEFT JOIN Page ON PageItemType = '{row.TableName.Replace("ItemType_","")}' AND PageItemId = Id" + 171 $" LEFT JOIN Page as PageProperties ON AreaItemTypePageProperty = '{row.TableName.Replace("ItemType_","")}' AND PageProperties.PagePropertyItemId = Id" + 172 $" LEFT JOIN GridRow ON GridRowItemType = '{row.TableName.Replace("ItemType_","")}' AND GridRowItemId = Id" + 173 $" LEFT JOIN Paragraph ON ParagraphItemType = '{row.TableName.Replace("ItemType_","")}' AND ParagraphItemId = Id" + 174 $" WHERE {row.ColumnName} != '' AND {row.ColumnName} IS NOT NULL" + 175 $" AND (AreaId IS NULL OR AreaId = {Pageview.AreaID})" + 176 $" AND (Page.PageId IS NULL OR Page.PageAreaId = {Pageview.AreaID})" + 177 $" AND (PageProperties.PageId IS NULL OR PageProperties.PageAreaId = {Pageview.AreaID})" + 178 $" AND (GridRowId IS NULL OR GridRowPageId IN (SELECT value From string_split(@pageIds, ',')))" + 179 $" AND (ParagraphId IS NULL OR ParagraphPageId IN (SELECT value From string_split(@pageIds, ',')))"; 180 181 var maxMsSqlServerCharLimit = 60000; 182 if (sqlQuery.Length > maxMsSqlServerCharLimit) 183 { 184 UpdateThemeUsages(sqlQuery, themeUsages); 185 sqlQuery = ""; 186 } 187 } 188 189 if (!string.IsNullOrEmpty(sqlQuery)) 190 { 191 UpdateThemeUsages(sqlQuery, themeUsages); 192 } 193 UpdateAllUsages(themeUsages); 194 195 Dynamicweb.Context.Current.Items[cacheKey] = themeUsages; 196 return themeUsages; 197 } 198 199 private void UpdateThemeUsages(string sqlQuery, List<ThemeUsage> themeUsages) 200 { 201 sqlQuery = $"DECLARE @pageIds NVARCHAR(max) = (SELECT STRING_AGG(PageId,',') FROM Page WHERE PageAreaId = {Pageview.AreaID}) " + sqlQuery; 202 var rawData = Dynamicweb.Data.Database.CreateDataReader(sqlQuery); 203 while (rawData.Read()) 204 { 205 var themeId = rawData["ColumnValue"].ToString(); 206 var themeUsageExists = themeUsages.FirstOrDefault(t => t.Id == themeId) != null; 207 if (!themeUsageExists) 208 { 209 themeUsages.Add(new ThemeUsage { Id = themeId }); 210 } 211 212 var themeUsage = themeUsages.FirstOrDefault(t => t.Id == themeId); 213 if (themeUsage == null) continue; 214 215 if (Converter.ToInt32(rawData["AreaId"].ToString()) > 0) { themeUsage.WebsiteUsages.Add(Converter.ToInt32(rawData["AreaId"].ToString())); } 216 if (Converter.ToInt32(rawData["PageId"].ToString()) > 0) { themeUsage.PageUsages.Add(Converter.ToInt32(rawData["PageId"].ToString())); } 217 if (Converter.ToInt32(rawData["PagePropertiesId"].ToString()) > 0) { themeUsage.PagePropertyUsages.Add(Converter.ToInt32(rawData["PagePropertiesId"].ToString())); } 218 if (Converter.ToInt32(rawData["GridRowId"].ToString()) > 0) { themeUsage.GridRowUsages.Add(Converter.ToInt32(rawData["GridRowId"].ToString())); } 219 if (Converter.ToInt32(rawData["ParagraphId"].ToString()) > 0) { themeUsage.ParagraphUsages.Add(Converter.ToInt32(rawData["ParagraphId"].ToString())); } 220 } 221 } 222 223 private void UpdateAllUsages(List<ThemeUsage> themeUsages) 224 { 225 foreach (var themeUsage in themeUsages) 226 { 227 int websiteUsages = themeUsage?.WebsiteUsages.Count ?? 0; 228 int pageUsages = themeUsage?.PageUsages.Count ?? 0; 229 int pagePropertyUsages = themeUsage?.PagePropertyUsages.Count ?? 0; 230 int gridRowUsages = themeUsage?.GridRowUsages.Count ?? 0; 231 int paragraphUsages = themeUsage?.ParagraphUsages.Count ?? 0; 232 themeUsage.AllUsages = websiteUsages + pageUsages + pagePropertyUsages + gridRowUsages + paragraphUsages; 233 } 234 } 235 236 private ThemeUsage GetThemeUsageById(string themeId) 237 { 238 var themeUsages = GetAllThemeUsages(); 239 return themeUsages.FirstOrDefault(t => t.Id == themeId); 240 } 241 242 } 243 244 @{ 245 string themeName = !string.IsNullOrWhiteSpace(Model.Item.GetString("Name")) ? Model.Item.GetString("Name") : "Default"; 246 string themeClassName = !string.IsNullOrWhiteSpace(Model.Item.GetString("CSSClassName")) ? Model.Item.GetString("CSSClassName").Replace(" ", "").Trim().ToLower() : ""; 247 248 //Theme colors 249 string foregroundColor = Model.Item.GetString("ForegroundColor", "currentColor"); 250 string backgroundColor = Model.Item.GetString("BackgroundColor", "transparent"); 251 string accentColor = Model.Item.GetString("accentColor", "currentColor"); 252 string borderColor = Model.Item.GetString("BorderColor", "transparent"); 253 254 //Primary button 255 string buttonPrimaryForegroundColor = Model.Item.GetString("ButtonPrimaryForegroundColor", "currentColor"); 256 string buttonPrimaryBackgroundColor = Model.Item.GetString("ButtonPrimaryBackgroundColor", "transparent"); 257 string buttonPrimaryBorderColor = Model.Item.GetString("ButtonPrimaryBorderColor", "transparent"); 258 259 string buttonPrimaryHoverBackgroundColorAuto = "transparent"; 260 if (buttonPrimaryBackgroundColor != "transparent") 261 { 262 buttonPrimaryHoverBackgroundColorAuto = "hsl(" + GetColorVariation(buttonPrimaryBackgroundColor) + ")"; 263 } 264 string buttonPrimaryHoverForegroundColor = Model.Item.GetString("ButtonPrimaryHoverForegroundColor", buttonPrimaryForegroundColor); 265 string buttonPrimaryHoverBackgroundColor = Model.Item.GetString("ButtonPrimaryHoverBackgroundColor", buttonPrimaryHoverBackgroundColorAuto); 266 string buttonPrimaryHoverBorderColor = Model.Item.GetString("ButtonPrimaryHoverBorderColor", buttonPrimaryBorderColor); 267 268 //Secondary buton 269 string buttonSecondaryForegroundColor = Model.Item.GetString("ButtonSecondaryForegroundColor", "currentColor"); 270 string buttonSecondaryBackgroundColor = Model.Item.GetString("ButtonSecondaryBackgroundColor", "transparent"); 271 string buttonSecondaryBorderColor = Model.Item.GetString("ButtonSecondaryBorderColor", "transparent"); 272 273 string buttonSecondaryHoverBackgroundColorAuto = "transparent"; 274 if (buttonSecondaryBackgroundColor != "transparent") 275 { 276 buttonSecondaryHoverBackgroundColorAuto = "hsl(" + GetColorVariation(buttonSecondaryBackgroundColor) + ")"; 277 } 278 string buttonSecondaryHoverForegroundColor = Model.Item.GetString("ButtonSecondaryHoverForegroundColor", buttonSecondaryForegroundColor); 279 string buttonSecondaryHoverBackgroundColor = Model.Item.GetString("ButtonSecondaryHoverBackgroundColor", buttonSecondaryHoverBackgroundColorAuto); 280 string buttonSecondaryHoverBorderColor = Model.Item.GetString("ButtonSecondaryHoverBorderColor", buttonSecondaryBorderColor); 281 282 //Link buton 283 string buttonLinkColor = Model.Item.GetString("ButtonLinkColor", "currentColor"); 284 string buttonLinkHoverColorAuto = "currentColor"; 285 if (buttonLinkColor != "currentColor") 286 { 287 buttonLinkHoverColorAuto = "hsl(" + GetColorVariation(buttonLinkColor) + ")"; 288 } 289 string buttonLinkHoverColor = Model.Item.GetString("ButtonLinkHoverColor", buttonLinkHoverColorAuto); 290 291 string accessibilityOutlineColor = Model.Item.GetString("OutlineColor") != null ? Model.Item.GetString("OutlineColor") : ""; 292 293 if (!string.IsNullOrEmpty(themeClassName)) 294 { 295 var sb = new System.Text.StringBuilder(); 296 297 sb.AppendLine("." + themeClassName + "{"); 298 if (!string.IsNullOrEmpty(foregroundColor)) 299 { 300 sb.AppendLine($"--swift-foreground-color: {foregroundColor};"); 301 sb.AppendLine($"--swift-foreground-color-rgb: {HexToRGB(foregroundColor)};"); 302 } 303 if (!string.IsNullOrEmpty(backgroundColor)) 304 { 305 sb.AppendLine($"--swift-background-color: {backgroundColor};"); 306 sb.AppendLine($"--swift-background-color-rgb: {HexToRGB(backgroundColor)};"); 307 } 308 if (!string.IsNullOrEmpty(accentColor)) 309 { 310 sb.AppendLine($"--swift-accent-color: {accentColor};"); 311 sb.AppendLine($"--swift-accent-color-rgb: {HexToRGB(accentColor)};"); 312 } 313 if (!string.IsNullOrEmpty(borderColor)) 314 { 315 sb.AppendLine($"--swift-border-color: {borderColor};"); 316 sb.AppendLine($"--swift-border-color-rgb: {HexToRGB(borderColor)};"); 317 } 318 319 if (!string.IsNullOrEmpty(buttonPrimaryBackgroundColor)) 320 { 321 sb.AppendLine($"--swift-button-primary-background-color: {buttonPrimaryBackgroundColor};"); 322 sb.AppendLine($"--swift-button-primary-background-color-rgb: {HexToRGB(buttonPrimaryBackgroundColor)};"); 323 } 324 if (!string.IsNullOrEmpty(buttonPrimaryForegroundColor)) 325 { 326 sb.AppendLine($"--swift-button-primary-foreground-color: {buttonPrimaryForegroundColor};"); 327 sb.AppendLine($"--swift-button-primary-foreground-color-rgb: {HexToRGB(buttonPrimaryForegroundColor)};"); 328 } 329 if (!string.IsNullOrEmpty(buttonPrimaryBorderColor)) 330 { 331 sb.AppendLine($"--swift-button-primary-border-color: {buttonPrimaryBorderColor};"); 332 sb.AppendLine($"--swift-button-primary-border-color-rgb: {HexToRGB(buttonPrimaryBorderColor)};"); 333 } 334 335 if (!string.IsNullOrEmpty(buttonPrimaryHoverBackgroundColor)) 336 { 337 sb.AppendLine($"--swift-button-primary-hover-background-color: {buttonPrimaryHoverBackgroundColor};"); 338 sb.AppendLine($"--swift-button-primary-hover-background-color-rgb: {HexToRGB(buttonPrimaryHoverBackgroundColor)};"); 339 } 340 if (!string.IsNullOrEmpty(buttonPrimaryHoverForegroundColor)) 341 { 342 sb.AppendLine($"--swift-button-primary-hover-foreground-color: {buttonPrimaryHoverForegroundColor};"); 343 sb.AppendLine($"--swift-button-primary-hover-foreground-color-rgb: {HexToRGB(buttonPrimaryHoverForegroundColor)};"); 344 } 345 if (!string.IsNullOrEmpty(buttonPrimaryHoverBorderColor)) 346 { 347 sb.AppendLine($"--swift-button-primary-hover-border-color: {buttonPrimaryHoverBorderColor};"); 348 sb.AppendLine($"--swift-button-primary-hover-border-color-rgb: {HexToRGB(buttonPrimaryHoverBorderColor)};"); 349 } 350 351 if (!string.IsNullOrEmpty(buttonSecondaryBackgroundColor)) 352 { 353 sb.AppendLine($"--swift-button-secondary-background-color: {buttonSecondaryBackgroundColor};"); 354 sb.AppendLine($"--swift-button-secondary-background-color-rgb: {HexToRGB(buttonSecondaryBackgroundColor)};"); 355 } 356 if (!string.IsNullOrEmpty(buttonSecondaryForegroundColor)) 357 { 358 sb.AppendLine($"--swift-button-secondary-foreground-color: {buttonSecondaryForegroundColor};"); 359 sb.AppendLine($"--swift-button-secondary-foreground-color-rgb: {HexToRGB(buttonSecondaryForegroundColor)};"); 360 } 361 if (!string.IsNullOrEmpty(buttonSecondaryBorderColor)) 362 { 363 sb.AppendLine($"--swift-button-secondary-border-color: {buttonSecondaryBorderColor};"); 364 sb.AppendLine($"--swift-button-secondary-border-color-rgb: {HexToRGB(buttonSecondaryBorderColor)};"); 365 } 366 if (!string.IsNullOrEmpty(buttonSecondaryHoverBackgroundColor)) 367 { 368 sb.AppendLine($"--swift-button-secondary-hover-background-color: {buttonSecondaryHoverBackgroundColor};"); 369 sb.AppendLine($"--swift-button-secondary-hover-background-color-rgb: {HexToRGB(buttonSecondaryHoverBackgroundColor)};"); 370 } 371 if (!string.IsNullOrEmpty(buttonSecondaryHoverForegroundColor)) 372 { 373 sb.AppendLine($"--swift-button-secondary-hover-foreground-color: {buttonSecondaryHoverForegroundColor};"); 374 sb.AppendLine($"--swift-button-secondary-hover-foreground-color-rgb: {HexToRGB(buttonSecondaryHoverForegroundColor)};"); 375 } 376 if (!string.IsNullOrEmpty(buttonSecondaryHoverBorderColor)) 377 { 378 sb.AppendLine($"--swift-button-secondary-hover-border-color: {buttonSecondaryHoverBorderColor};"); 379 sb.AppendLine($"--swift-button-secondary-hover-border-color-rgb: {HexToRGB(buttonSecondaryHoverBorderColor)};"); 380 } 381 if (!string.IsNullOrEmpty(buttonLinkColor)) 382 { 383 sb.AppendLine($"--swift-button-link-color: {buttonLinkColor};"); 384 sb.AppendLine($"--swift-button-link-color-rgb: {HexToRGB(buttonLinkColor)};"); 385 } 386 if (!string.IsNullOrEmpty(buttonLinkHoverColor)) 387 { 388 sb.AppendLine($"--swift-button-link-hover-color: {buttonLinkHoverColor};"); 389 sb.AppendLine($"--swift-button-link-hover-color-rgb: {HexToRGB(buttonLinkHoverColor)};"); 390 } 391 if (!string.IsNullOrEmpty(accessibilityOutlineColor)) 392 { 393 sb.AppendLine($"--swift-a11y-outline-color: {accessibilityOutlineColor};"); 394 sb.AppendLine($"--swift-a11y-outline-color-rgb: {HexToRGB(accessibilityOutlineColor)};"); 395 } 396 sb.AppendLine("}"); 397 398 Dynamicweb.Core.Helpers.TextFileHelper.WriteTextFile(sb.ToString() + Environment.NewLine, Dynamicweb.Context.Current.Server.MapPath($"/Files/Templates/Designs/Swift/_parsed/Swift_css/Swift_theme_styles_{Dynamicweb.Content.Services.Pages.GetPage(Model.PageID).AreaId}.tmp"), true); 399 } 400 } 401 402 @if (themeClassName != "") 403 { 404 string iconPath = "/Files/Templates/Designs/Swift/Assets/icons/"; 405 406 <div class="g-col-12 g-col-lg-4"> 407 <div class="swift-checkered p-3"> 408 <div class="theme-option theme @themeClassName p-lg-3"> 409 <div class="mb-2 pb-1 border-bottom d-flex align-items-center"> 410 <span class="icon-3 me-2"> 411 @ReadFile(iconPath + "sun.svg") 412 </span> 413 <h4 class="m-0 p-0">@themeName</h4> 414 </div> 415 <div class="d-flex flex-column gap-1 mb-2"> 416 <p class="mb-0">This is the body text of the theme.</p> 417 <p class="mb-0" style="color: var(--swift-accent-color)">This is the accent color of the theme.</p> 418 </div> 419 <div> 420 <button class="btn btn-primary me-1">Primary</button> 421 <button class="btn btn-secondary">Secondary</button> 422 <button class="btn btn-link">Link</button> 423 </div> 424 </div> 425 </div> 426 </div> 427 <div class="g-col-12 g-col-lg-8 mb-4 mb-lg-0"> 428 <div class="grid fs-7"> 429 <div class="g-col-12 g-col-lg-3"> 430 <table class="table table-borderless table-sm w-100"> 431 <thead> 432 <tr> 433 <th colspan="2" class="fw-bold">@Translate("Base")</th> 434 </tr> 435 </thead> 436 <tr> 437 <td>@Translate("Foreground")</td> 438 <td>@GetColorSquare(foregroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@foregroundColor');">@foregroundColor</a></td> 439 </tr> 440 <tr> 441 <td>@Translate("Background")</td> 442 <td>@GetColorSquare(backgroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@backgroundColor');">@backgroundColor</a></td> 443 </tr> 444 <tr> 445 <td>@Translate("Accent")</td> 446 <td>@GetColorSquare(accentColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@accentColor');">@accentColor</a></td> 447 </tr> 448 <tr> 449 <td>@Translate("Border")</td> 450 <td>@GetColorSquare(borderColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@borderColor');">@borderColor</a></td> 451 </tr> 452 </table> 453 </div> 454 <div class="g-col-12 g-col-lg-3"> 455 <table class="table table-borderless table-sm w-100"> 456 <thead> 457 <tr> 458 <th colspan="2" class="fw-bold">@Translate("Primary button")</th> 459 </tr> 460 </thead> 461 <tr> 462 <td>@Translate("Foreground")</td> 463 <td>@GetColorSquare(buttonPrimaryForegroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonPrimaryForegroundColor');">@buttonPrimaryForegroundColor</a></td> 464 </tr> 465 <tr> 466 <td>@Translate("Background")</td> 467 <td>@GetColorSquare(buttonPrimaryBackgroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonPrimaryBackgroundColor');">@buttonPrimaryBackgroundColor</a></td> 468 </tr> 469 @if (!string.IsNullOrEmpty(buttonPrimaryBorderColor)) 470 { 471 <tr> 472 <td>@Translate("Border")</td> 473 <td>@GetColorSquare(buttonPrimaryBorderColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonPrimaryBorderColor');">@buttonPrimaryBorderColor</a></td> 474 </tr> 475 } 476 <thead> 477 <tr> 478 <th colspan="2" class="fw-bold">@Translate("Primary button hover")</th> 479 </tr> 480 </thead> 481 @if (!string.IsNullOrEmpty(buttonPrimaryHoverForegroundColor)) 482 { 483 <tr> 484 <td>@Translate("Foreground")</td> 485 <td>@GetColorSquare(buttonPrimaryHoverForegroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonPrimaryHoverForegroundColor');">@buttonPrimaryHoverForegroundColor</a></td> 486 </tr> 487 } 488 @if (!string.IsNullOrEmpty(buttonPrimaryHoverBackgroundColor)) 489 { 490 <tr> 491 <td>@Translate("Background")</td> 492 <td>@GetColorSquare(buttonPrimaryHoverBackgroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonPrimaryHoverBackgroundColor');">@buttonPrimaryHoverBackgroundColor</a></td> 493 </tr> 494 } 495 @if (!string.IsNullOrEmpty(buttonPrimaryHoverBorderColor)) 496 { 497 <tr> 498 <td>@Translate("Border")</td> 499 <td>@GetColorSquare(buttonPrimaryHoverBorderColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonPrimaryHoverBorderColor');">@buttonPrimaryHoverBorderColor</a></td> 500 </tr> 501 } 502 </table> 503 </div> 504 <div class="g-col-12 g-col-lg-3"> 505 <table class="table table-borderless table-sm w-100"> 506 <thead> 507 <tr> 508 <th colspan="2" class="fw-bold">@Translate("Secondary button")</th> 509 </tr> 510 </thead> 511 <tr> 512 <td>@Translate("Foreground")</td> 513 <td>@GetColorSquare(buttonSecondaryForegroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonSecondaryForegroundColor');">@buttonSecondaryForegroundColor</a></td> 514 </tr> 515 <tr> 516 <td>@Translate("Background")</td> 517 <td>@GetColorSquare(buttonSecondaryBackgroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonSecondaryBackgroundColor');">@buttonSecondaryBackgroundColor</a></td> 518 </tr> 519 @if (!string.IsNullOrEmpty(buttonSecondaryBorderColor)) 520 { 521 <tr> 522 <td>@Translate("Border")</td> 523 <td>@GetColorSquare(buttonSecondaryBorderColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonSecondaryBorderColor');">@buttonSecondaryBorderColor</a></td> 524 </tr> 525 } 526 <thead> 527 <tr> 528 <th colspan="2" class="fw-bold">@Translate("Secondary button hover")</th> 529 </tr> 530 </thead> 531 @if (!string.IsNullOrEmpty(buttonSecondaryHoverForegroundColor)) 532 { 533 <tr> 534 <td>@Translate("Foreground")</td> 535 <td>@GetColorSquare(buttonSecondaryHoverForegroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonSecondaryHoverForegroundColor');">@buttonSecondaryHoverForegroundColor</a></td> 536 </tr> 537 } 538 @if (!string.IsNullOrEmpty(buttonSecondaryHoverBackgroundColor)) 539 { 540 <tr> 541 <td>@Translate("Background")</td> 542 <td>@GetColorSquare(buttonSecondaryHoverBackgroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonSecondaryHoverBackgroundColor');">@buttonSecondaryHoverBackgroundColor</a></td> 543 </tr> 544 } 545 @if (!string.IsNullOrEmpty(buttonSecondaryHoverBorderColor)) 546 { 547 <tr> 548 <td>@Translate("Border")</td> 549 <td>@GetColorSquare(buttonSecondaryHoverBorderColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonSecondaryHoverBorderColor');">@buttonSecondaryHoverBorderColor</a></td> 550 </tr> 551 } 552 @if (!string.IsNullOrEmpty(accessibilityOutlineColor)) 553 { 554 <tr> 555 <td>@Translate("Focus outline")</td> 556 <td>@GetColorSquare(accessibilityOutlineColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@accessibilityOutlineColor');">@accessibilityOutlineColor</a></td> 557 </tr> 558 } 559 </table> 560 </div> 561 <div class="g-col-12 g-col-lg-3"> 562 <table class="table table-borderless table-sm w-100"> 563 <thead> 564 <tr> 565 <th colspan="2" class="fw-bold">@Translate("Link button")</th> 566 </tr> 567 </thead> 568 <tr> 569 <td>@Translate("Link color")</td> 570 <td>@GetColorSquare(buttonLinkColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonLinkColor');">@buttonLinkColor</a></td> 571 </tr> 572 <thead> 573 <tr> 574 <th colspan="2" class="fw-bold">@Translate("Link button hover")</th> 575 </tr> 576 </thead> 577 @if (!string.IsNullOrEmpty(buttonLinkHoverColor)) 578 { 579 <tr> 580 <td>@Translate("Link hover color")</td> 581 <td>@GetColorSquare(buttonLinkHoverColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonLinkHoverColor');">@buttonLinkHoverColor</a></td> 582 </tr> 583 } 584 585 @if (!string.IsNullOrEmpty(accessibilityOutlineColor)) 586 { 587 <tr> 588 <td>@Translate("Focus outline")</td> 589 <td>@GetColorSquare(accessibilityOutlineColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@accessibilityOutlineColor');">@accessibilityOutlineColor</a></td> 590 </tr> 591 } 592 </table> 593 </div> 594 <div class="g-col-12 g-col-lg-3"> 595 <table class="table table-borderless table-sm w-100"> 596 <tr> 597 <td class="fw-bold">@Translate("Implementation")</td> 598 </tr> 599 <tr> 600 <td> 601 @{ 602 string implementation = $"<div class=\"theme {themeClassName}\"></div>"; 603 } 604 <div class="text-muted"> 605 <code class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@themeClassName');"> 606 @Dynamicweb.Core.Encoders.HtmlEncoder.HtmlEncode(implementation) 607 </code> 608 </div> 609 </td> 610 </tr> 611 </table> 612 </div> 613 @{ 614 bool hasUsageData = Converter.ToBoolean(Dynamicweb.Context.Current.Request["auditUsages"]); 615 if (hasUsageData) 616 { 617 var themeUsage = GetThemeUsageById(themeClassName); 618 int allUsages = themeUsage?.AllUsages ?? 0; 619 string buttonAttributes = allUsages > 0 ? $"data-bs-toggle=\"modal\" data-bs-target=\"#themeUsage_{Model.ID}\"" : string.Empty; 620 string badgeStyle = allUsages > 0 ? "bg-success" : "bg-danger"; 621 622 <div class="g-col-12 g-col-lg-9 position-relative"> 623 <button type="button" class="btn btn-primary btn-sm position-absolute end-0" @buttonAttributes> 624 Usages 625 <span class="position-absolute top-0 start-100 translate-middle badge rounded-pill text-white @badgeStyle">@allUsages</span> 626 </button> 627 628 @if (allUsages > 0) 629 { 630 int websiteUsages = themeUsage?.WebsiteUsages.Count ?? 0; 631 int pageUsages = themeUsage?.PageUsages.Count ?? 0; 632 int pagePropertyUsages = themeUsage?.PagePropertyUsages.Count ?? 0; 633 int gridRowUsages = themeUsage?.GridRowUsages.Count ?? 0; 634 int paragraphUsages = themeUsage?.ParagraphUsages.Count ?? 0; 635 636 <!-- Modal --> 637 <div class="modal fade" id="themeUsage_@(Model.ID)" tabindex="-1" aria-labelledby="usagesModelLabel" aria-hidden="true"> 638 <div class="modal-dialog modal-xl modal-dialog-centered modal-dialog-scrollable"> 639 <div class="modal-content"> 640 <div class="modal-header"> 641 <h5 class="modal-title" id="usagesModelLabel">@allUsages Usages of '@(themeName)' (@(themeClassName))</h5> 642 <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> 643 </div> 644 <div class="modal-body"> 645 <div class="accordion" id="accordionWrapper"> 646 @if(websiteUsages > 0) 647 { 648 <div class="accordion-item"> 649 <h2 class="accordion-header" id="headingWebsites"> 650 <button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#collapseWebsites" aria-expanded="true" aria-controls="collapseWebsites"> 651 <span class="pe-2">Websites</span><span class="badge rounded-pill bg-secondary text-light">@websiteUsages</span> 652 </button> 653 </h2> 654 <div id="collapseWebsites" class="accordion-collapse collapse show" aria-labelledby="headingWebsites" data-bs-parent="#accordionWrapper"> 655 <div class="accordion-body"> 656 <ul> 657 @foreach (var usage in themeUsage.WebsiteUsages) 658 { 659 var website = Dynamicweb.Content.Services.Areas.GetArea(usage); 660 <li><span class="fw-bold">@website.Name</span>@($" (ID: {usage})")</li> 661 } 662 </ul> 663 </div> 664 </div> 665 </div> 666 } 667 @if (pageUsages > 0) 668 { 669 var pages = Dynamicweb.Content.Services.Pages.GetPages(themeUsage.PageUsages.ToArray()); 670 671 <div class="accordion-item"> 672 <h2 class="accordion-header" id="headingPages"> 673 <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapsePages" aria-expanded="false" aria-controls="collapsePages"> 674 <span class="pe-2">Pages</span><span class="badge rounded-pill bg-secondary text-light">@pageUsages</span> 675 </button> 676 </h2> 677 <div id="collapsePages" class="accordion-collapse collapse" aria-labelledby="headingPages" data-bs-parent="#accordionWrapper"> 678 <div class="accordion-body"> 679 <ul> 680 @foreach (var usage in themeUsage.PageUsages) 681 { 682 <li><span class="fw-bold">@pages.FirstOrDefault(p => p.ID == usage).GetDisplayName()</span>@($" (ID: {usage})")</li> 683 } 684 </ul> 685 </div> 686 </div> 687 </div> 688 } 689 @if (pagePropertyUsages > 0) 690 { 691 var pages = Dynamicweb.Content.Services.Pages.GetPages(themeUsage.PageUsages.ToArray()); 692 693 <div class="accordion-item"> 694 <h2 class="accordion-header" id="headingPageProperties"> 695 <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapsePageProperties" aria-expanded="false" aria-controls="collapsePageProperties"> 696 <span class="pe-2">Page Properties</span><span class="badge rounded-pill bg-secondary text-light">@pagePropertyUsages</span> 697 </button> 698 </h2> 699 <div id="collapsePageProperties" class="accordion-collapse collapse" aria-labelledby="headingPageProperties" data-bs-parent="#accordionWrapper"> 700 <div class="accordion-body"> 701 <ul> 702 @foreach (var usage in themeUsage.PagePropertyUsages) 703 { 704 <li><span class="fw-bold">@pages.FirstOrDefault(p => p.ID == usage).GetDisplayName()</span>@($" (ID: {usage})")</li> 705 } 706 </ul> 707 </div> 708 </div> 709 </div> 710 } 711 @if (gridRowUsages > 0) 712 { 713 var rows = Dynamicweb.Content.Services.Grids.GetGridRows().Where(r => themeUsage.GridRowUsages.Contains(r.ID)).ToList(); 714 715 <div class="accordion-item"> 716 <h2 class="accordion-header" id="headingRows"> 717 <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseRows" aria-expanded="false" aria-controls="collapseRows"> 718 <span class="pe-2">Rows</span><span class="badge rounded-pill bg-secondary text-light">@gridRowUsages</span> 719 </button> 720 </h2> 721 <div id="collapseRows" class="accordion-collapse collapse" aria-labelledby="headingRows" data-bs-parent="#accordionWrapper"> 722 <div class="accordion-body"> 723 <ul> 724 @foreach (var usage in themeUsage.GridRowUsages) 725 { 726 var row = rows.FirstOrDefault(r => r.ID == usage); 727 var page = Dynamicweb.Content.Services.Pages.GetPage(row.PageId); 728 <li>Page: <span class="fw-bold">@(page.GetDisplayName())</span>@($"( ID: {page.ID}) - Row: ")<span class="fw-bold">@(row.DefinitionId)</span>@($" (ID: {usage})")</li> 729 } 730 </ul> 731 </div> 732 </div> 733 </div> 734 } 735 @if (paragraphUsages > 0) 736 { 737 var paragraphs = Dynamicweb.Content.Services.Paragraphs.GetParagraphs().Where(p => themeUsage.ParagraphUsages.Contains(p.ID)).ToList(); 738 739 <div class="accordion-item"> 740 <h2 class="accordion-header" id="headingParagraphs"> 741 <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseParagraphs" aria-expanded="false" aria-controls="collapseParagraphs"> 742 <span class="pe-2">Paragraphs</span><span class="badge rounded-pill bg-secondary text-light">@paragraphUsages</span> 743 </button> 744 </h2> 745 <div id="collapseParagraphs" class="accordion-collapse collapse" aria-labelledby="headingParagraphs" data-bs-parent="#accordionWrapper"> 746 <div class="accordion-body"> 747 <ul> 748 @foreach (var usage in themeUsage.ParagraphUsages) 749 { 750 var paragraph = paragraphs.FirstOrDefault(p => p.ID == usage); 751 var page = Dynamicweb.Content.Services.Pages.GetPage(paragraph.PageID); 752 <li>Page: <span class="fw-bold">@(page.GetDisplayName())</span>@($"( ID: {page.ID}) - Paragraph: ")<span class="fw-bold">@paragraph.Header</span>@($" (ID: {usage})")</li> 753 } 754 </ul> 755 </div> 756 </div> 757 </div> 758 } 759 </div> 760 </div> 761 </div> 762 </div> 763 </div> 764 } 765 </div> 766 } 767 } 768 </div> 769 </div> 770 } 771 <div class="g-col-12"> 772 <hr /> 773 </div> 774
Error executing template "Designs/Swift/Paragraph/Swift_Theme.cshtml" System.Data.SqlClient.SqlException (0x80131904): STRING_AGG aggregation result exceeded the limit of 8000 bytes. Use LOB types to avoid result truncation. at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction) at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose) at System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady) at System.Data.SqlClient.SqlDataReader.TryConsumeMetaData() at System.Data.SqlClient.SqlDataReader.get_MetaData() at System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString, Boolean isInternal, Boolean forDescribeParameterEncryption, Boolean shouldCacheForAlwaysEncrypted) at System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async, Int32 timeout, Task& task, Boolean asyncWrite, Boolean inRetry, SqlDataReader ds, Boolean describeParameterEncryptionRequest) at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, TaskCompletionSource`1 completion, Int32 timeout, Task& task, Boolean& usedCache, Boolean asyncWrite, Boolean inRetry) at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method) at System.Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior behavior, String method) at Dynamicweb.Data.Database.CreateDataReader(IDbCommand command, CommandBehavior behavior) at Dynamicweb.Data.Database.CreateDataReader(String sql, IDbConnection connection, IDbTransaction transaction, CommandBehavior behavior, Int32 commandTimeout, Dictionary`2 sqlParams) at Dynamicweb.Data.Database.CreateDataReader(String sql, IDbConnection connection, IDbTransaction transaction, Int32 commandTimeout, Dictionary`2 sqlParams) at Dynamicweb.Data.Database.CreateDataReader(String sql) at CompiledRazorTemplates.Dynamic.RazorEngine_8e3f1b11eb0041ceb2ca487c2be837e6.UpdateThemeUsages(String sqlQuery, List`1 themeUsages) in E:\Dynamicweb.net\Solutions\Dynamicweb\dw2022.cloud.dynamicweb-cms.com\Files\Templates\Designs\Swift\Paragraph\Swift_Theme.cshtml:line 202 at CompiledRazorTemplates.Dynamic.RazorEngine_8e3f1b11eb0041ceb2ca487c2be837e6.GetAllThemeUsages() in E:\Dynamicweb.net\Solutions\Dynamicweb\dw2022.cloud.dynamicweb-cms.com\Files\Templates\Designs\Swift\Paragraph\Swift_Theme.cshtml:line 184 at CompiledRazorTemplates.Dynamic.RazorEngine_8e3f1b11eb0041ceb2ca487c2be837e6.GetThemeUsageById(String themeId) in E:\Dynamicweb.net\Solutions\Dynamicweb\dw2022.cloud.dynamicweb-cms.com\Files\Templates\Designs\Swift\Paragraph\Swift_Theme.cshtml:line 238 at CompiledRazorTemplates.Dynamic.RazorEngine_8e3f1b11eb0041ceb2ca487c2be837e6.Execute() in E:\Dynamicweb.net\Solutions\Dynamicweb\dw2022.cloud.dynamicweb-cms.com\Files\Templates\Designs\Swift\Paragraph\Swift_Theme.cshtml:line 617 at RazorEngine.Templating.TemplateBase.RazorEngine.Templating.ITemplate.Run(ExecuteContext context, TextWriter reader) at RazorEngine.Templating.RazorEngineService.RunCompile(ITemplateKey key, TextWriter writer, Type modelType, Object model, DynamicViewBag viewBag) at RazorEngine.Templating.RazorEngineServiceExtensions.<>c__DisplayClass16_0.<RunCompile>b__0(TextWriter writer) at RazorEngine.Templating.RazorEngineServiceExtensions.WithWriter(Action`1 withWriter) at Dynamicweb.Rendering.RazorTemplateRenderingProvider.Render(Template template) at Dynamicweb.Rendering.TemplateRenderingService.Render(Template template) at Dynamicweb.Rendering.Template.RenderRazorTemplate() ClientConnectionId:b42d1cec-597c-4eed-bdc2-e0762a41101a Error Number:9829,State:1,Class:16
1 @inherits Dynamicweb.Rendering.ViewModelTemplate<Dynamicweb.Frontend.ParagraphViewModel> 2 @using System.Globalization 3 @using System.Drawing 4 @using Dynamicweb.Core 5 6 @functions{ 7 // Get Hex Color from color picker and translate to RGB color 8 public static string HexToRGB(string hexString) 9 { 10 if (hexString.Equals("none") || string.IsNullOrEmpty(hexString)) 11 return hexString; 12 13 //replace # occurences 14 if (hexString.IndexOf('#') != -1) 15 hexString = hexString.Replace("#", ""); 16 try 17 { 18 int r, g, b = 0; 19 r = int.Parse(hexString.Substring(0, 2), NumberStyles.AllowHexSpecifier); 20 g = int.Parse(hexString.Substring(2, 2), NumberStyles.AllowHexSpecifier); 21 b = int.Parse(hexString.Substring(4, 2), NumberStyles.AllowHexSpecifier); 22 23 string rgb = r + "," + g + "," + b; 24 return rgb; 25 } 26 catch (System.Exception) 27 { 28 return hexString; 29 } 30 } 31 32 public static string GetColorSquare(string hex) 33 { 34 return $"<div class=\"swift-checkered d-inline-block me-1\" style=\"height:1.25rem;width:1.25rem;\"><div style=\"background-color: {hex};border:.0625rem solid grey\" class=\"w-100 h-100\"></div></div>"; 35 } 36 37 public class HSL 38 { 39 public double h { get; set; } 40 public double s { get; set; } 41 public double l { get; set; } 42 } 43 44 //Convert HEX to HSL 45 public static HSL HexToHsl(string hexString) 46 { 47 System.Drawing.Color color = System.Drawing.ColorTranslator.FromHtml(hexString); 48 49 float _R = (color.R / 255f); 50 float _G = (color.G / 255f); 51 float _B = (color.B / 255f); 52 53 float _Min = Math.Min(Math.Min(_R, _G), _B); 54 float _Max = Math.Max(Math.Max(_R, _G), _B); 55 float _Delta = _Max - _Min; 56 57 float S = 0; 58 float L = (float)((_Max + _Min) / 2.0f); 59 60 if (_Delta != 0) 61 { 62 if (L < 0.5f) 63 { 64 S = (float)(_Delta / (_Max + _Min)); 65 } 66 else 67 { 68 S = (float)(_Delta / (2.0f - _Max - _Min)); 69 } 70 } 71 72 HSL hsl = new HSL(); 73 hsl.h = Math.Round(color.GetHue(), 2); 74 hsl.s = Math.Round(S, 2) * 100; 75 hsl.l = Math.Round(L, 2) * 100; 76 77 return hsl; 78 } 79 80 //Find contrast color (white, black) 81 public static Color GetContrastColor(string hexString) 82 { 83 System.Drawing.Color bg = System.Drawing.ColorTranslator.FromHtml(hexString); 84 85 int nThreshold = 105; 86 int bgDelta = Convert.ToInt32((bg.R * 0.299) + (bg.G * 0.587) + 87 (bg.B * 0.114)); 88 89 Color foreColor = (255 - bgDelta < nThreshold) ? Color.Black : Color.White; 90 return foreColor; 91 } 92 93 public string GetColorVariation(string hexString) 94 { 95 var contrast = GetContrastColor(hexString); 96 HSL currentHslColor = HexToHsl(hexString); 97 HSL variantHslColor = currentHslColor; 98 99 if (contrast == Color.Black) 100 { 101 variantHslColor.l = 85; //The background is dark - Color should be light 102 } 103 else 104 { 105 variantHslColor.l = 40; //The background is light - Color should be less light 106 } 107 108 //Color is very light 109 if (currentHslColor.l > 85) 110 { 111 variantHslColor.l = 95; 112 } 113 114 string colorString = variantHslColor.h + ", " + variantHslColor.s + "%, " + variantHslColor.l + "%"; 115 return colorString; 116 } 117 118 private class ThemeDatabaseUsage 119 { 120 public string TableName { get; set; } 121 public string ColumnName { get; set; } 122 } 123 124 private class ThemeUsage 125 { 126 public string Id { get; set; } 127 public List<int> WebsiteUsages { get; set; } = new List<int>(); 128 public List<int> PageUsages { get; set; } = new List<int>(); 129 public List<int> PagePropertyUsages { get; set; } = new List<int>(); 130 public List<int> GridRowUsages { get; set; } = new List<int>(); 131 public List<int> ParagraphUsages { get; set; } = new List<int>(); 132 public int AllUsages { get; set; } = 0; 133 } 134 135 private List<ThemeDatabaseUsage> GetThemeColumnsFromSchema() 136 { 137 string cacheKey = "ThemesFromDatabase"; 138 if (Dynamicweb.Context.Current.Items.Contains(cacheKey)) 139 { 140 return (List<ThemeDatabaseUsage>)Dynamicweb.Context.Current.Items[cacheKey]; 141 } 142 var schema = Dynamicweb.Data.Database.CreateDataReader("SELECT table_name, column_name FROM information_schema.columns WHERE column_name LIKE '%Theme%'"); 143 144 var rawData = new List<ThemeDatabaseUsage>(); 145 while (schema.Read()) { 146 rawData.Add(new ThemeDatabaseUsage {TableName = schema["table_name"].ToString(), ColumnName = schema["column_name"].ToString() }); 147 } 148 Dynamicweb.Context.Current.Items[cacheKey] = rawData; 149 return rawData; 150 } 151 152 private List<ThemeUsage> GetAllThemeUsages() 153 { 154 string cacheKey = "ThemeUsages"; 155 if (Dynamicweb.Context.Current.Items.Contains(cacheKey)) 156 { 157 return (List<ThemeUsage>)Dynamicweb.Context.Current.Items[cacheKey]; 158 } 159 160 var rawData = GetThemeColumnsFromSchema(); 161 var themeUsages = new List<ThemeUsage>(); 162 163 var sqlQuery = ""; 164 foreach (var row in rawData) 165 { 166 if (!string.IsNullOrEmpty(sqlQuery)) { sqlQuery += " UNION ALL "; } 167 sqlQuery += $"SELECT '{row.TableName}' AS TableName, '{row.ColumnName}' AS ColumnName, {row.ColumnName} AS ColumnValue, Id, AreaId, Page.PageId, PageProperties.PageId as 'PagePropertiesId', GridRowId, ParagraphId" + 168 $" FROM [{row.TableName}]" + 169 $" LEFT JOIN Area ON AreaItemType = '{row.TableName.Replace("ItemType_","")}' AND AreaItemId = Id" + 170 $" LEFT JOIN Page ON PageItemType = '{row.TableName.Replace("ItemType_","")}' AND PageItemId = Id" + 171 $" LEFT JOIN Page as PageProperties ON AreaItemTypePageProperty = '{row.TableName.Replace("ItemType_","")}' AND PageProperties.PagePropertyItemId = Id" + 172 $" LEFT JOIN GridRow ON GridRowItemType = '{row.TableName.Replace("ItemType_","")}' AND GridRowItemId = Id" + 173 $" LEFT JOIN Paragraph ON ParagraphItemType = '{row.TableName.Replace("ItemType_","")}' AND ParagraphItemId = Id" + 174 $" WHERE {row.ColumnName} != '' AND {row.ColumnName} IS NOT NULL" + 175 $" AND (AreaId IS NULL OR AreaId = {Pageview.AreaID})" + 176 $" AND (Page.PageId IS NULL OR Page.PageAreaId = {Pageview.AreaID})" + 177 $" AND (PageProperties.PageId IS NULL OR PageProperties.PageAreaId = {Pageview.AreaID})" + 178 $" AND (GridRowId IS NULL OR GridRowPageId IN (SELECT value From string_split(@pageIds, ',')))" + 179 $" AND (ParagraphId IS NULL OR ParagraphPageId IN (SELECT value From string_split(@pageIds, ',')))"; 180 181 var maxMsSqlServerCharLimit = 60000; 182 if (sqlQuery.Length > maxMsSqlServerCharLimit) 183 { 184 UpdateThemeUsages(sqlQuery, themeUsages); 185 sqlQuery = ""; 186 } 187 } 188 189 if (!string.IsNullOrEmpty(sqlQuery)) 190 { 191 UpdateThemeUsages(sqlQuery, themeUsages); 192 } 193 UpdateAllUsages(themeUsages); 194 195 Dynamicweb.Context.Current.Items[cacheKey] = themeUsages; 196 return themeUsages; 197 } 198 199 private void UpdateThemeUsages(string sqlQuery, List<ThemeUsage> themeUsages) 200 { 201 sqlQuery = $"DECLARE @pageIds NVARCHAR(max) = (SELECT STRING_AGG(PageId,',') FROM Page WHERE PageAreaId = {Pageview.AreaID}) " + sqlQuery; 202 var rawData = Dynamicweb.Data.Database.CreateDataReader(sqlQuery); 203 while (rawData.Read()) 204 { 205 var themeId = rawData["ColumnValue"].ToString(); 206 var themeUsageExists = themeUsages.FirstOrDefault(t => t.Id == themeId) != null; 207 if (!themeUsageExists) 208 { 209 themeUsages.Add(new ThemeUsage { Id = themeId }); 210 } 211 212 var themeUsage = themeUsages.FirstOrDefault(t => t.Id == themeId); 213 if (themeUsage == null) continue; 214 215 if (Converter.ToInt32(rawData["AreaId"].ToString()) > 0) { themeUsage.WebsiteUsages.Add(Converter.ToInt32(rawData["AreaId"].ToString())); } 216 if (Converter.ToInt32(rawData["PageId"].ToString()) > 0) { themeUsage.PageUsages.Add(Converter.ToInt32(rawData["PageId"].ToString())); } 217 if (Converter.ToInt32(rawData["PagePropertiesId"].ToString()) > 0) { themeUsage.PagePropertyUsages.Add(Converter.ToInt32(rawData["PagePropertiesId"].ToString())); } 218 if (Converter.ToInt32(rawData["GridRowId"].ToString()) > 0) { themeUsage.GridRowUsages.Add(Converter.ToInt32(rawData["GridRowId"].ToString())); } 219 if (Converter.ToInt32(rawData["ParagraphId"].ToString()) > 0) { themeUsage.ParagraphUsages.Add(Converter.ToInt32(rawData["ParagraphId"].ToString())); } 220 } 221 } 222 223 private void UpdateAllUsages(List<ThemeUsage> themeUsages) 224 { 225 foreach (var themeUsage in themeUsages) 226 { 227 int websiteUsages = themeUsage?.WebsiteUsages.Count ?? 0; 228 int pageUsages = themeUsage?.PageUsages.Count ?? 0; 229 int pagePropertyUsages = themeUsage?.PagePropertyUsages.Count ?? 0; 230 int gridRowUsages = themeUsage?.GridRowUsages.Count ?? 0; 231 int paragraphUsages = themeUsage?.ParagraphUsages.Count ?? 0; 232 themeUsage.AllUsages = websiteUsages + pageUsages + pagePropertyUsages + gridRowUsages + paragraphUsages; 233 } 234 } 235 236 private ThemeUsage GetThemeUsageById(string themeId) 237 { 238 var themeUsages = GetAllThemeUsages(); 239 return themeUsages.FirstOrDefault(t => t.Id == themeId); 240 } 241 242 } 243 244 @{ 245 string themeName = !string.IsNullOrWhiteSpace(Model.Item.GetString("Name")) ? Model.Item.GetString("Name") : "Default"; 246 string themeClassName = !string.IsNullOrWhiteSpace(Model.Item.GetString("CSSClassName")) ? Model.Item.GetString("CSSClassName").Replace(" ", "").Trim().ToLower() : ""; 247 248 //Theme colors 249 string foregroundColor = Model.Item.GetString("ForegroundColor", "currentColor"); 250 string backgroundColor = Model.Item.GetString("BackgroundColor", "transparent"); 251 string accentColor = Model.Item.GetString("accentColor", "currentColor"); 252 string borderColor = Model.Item.GetString("BorderColor", "transparent"); 253 254 //Primary button 255 string buttonPrimaryForegroundColor = Model.Item.GetString("ButtonPrimaryForegroundColor", "currentColor"); 256 string buttonPrimaryBackgroundColor = Model.Item.GetString("ButtonPrimaryBackgroundColor", "transparent"); 257 string buttonPrimaryBorderColor = Model.Item.GetString("ButtonPrimaryBorderColor", "transparent"); 258 259 string buttonPrimaryHoverBackgroundColorAuto = "transparent"; 260 if (buttonPrimaryBackgroundColor != "transparent") 261 { 262 buttonPrimaryHoverBackgroundColorAuto = "hsl(" + GetColorVariation(buttonPrimaryBackgroundColor) + ")"; 263 } 264 string buttonPrimaryHoverForegroundColor = Model.Item.GetString("ButtonPrimaryHoverForegroundColor", buttonPrimaryForegroundColor); 265 string buttonPrimaryHoverBackgroundColor = Model.Item.GetString("ButtonPrimaryHoverBackgroundColor", buttonPrimaryHoverBackgroundColorAuto); 266 string buttonPrimaryHoverBorderColor = Model.Item.GetString("ButtonPrimaryHoverBorderColor", buttonPrimaryBorderColor); 267 268 //Secondary buton 269 string buttonSecondaryForegroundColor = Model.Item.GetString("ButtonSecondaryForegroundColor", "currentColor"); 270 string buttonSecondaryBackgroundColor = Model.Item.GetString("ButtonSecondaryBackgroundColor", "transparent"); 271 string buttonSecondaryBorderColor = Model.Item.GetString("ButtonSecondaryBorderColor", "transparent"); 272 273 string buttonSecondaryHoverBackgroundColorAuto = "transparent"; 274 if (buttonSecondaryBackgroundColor != "transparent") 275 { 276 buttonSecondaryHoverBackgroundColorAuto = "hsl(" + GetColorVariation(buttonSecondaryBackgroundColor) + ")"; 277 } 278 string buttonSecondaryHoverForegroundColor = Model.Item.GetString("ButtonSecondaryHoverForegroundColor", buttonSecondaryForegroundColor); 279 string buttonSecondaryHoverBackgroundColor = Model.Item.GetString("ButtonSecondaryHoverBackgroundColor", buttonSecondaryHoverBackgroundColorAuto); 280 string buttonSecondaryHoverBorderColor = Model.Item.GetString("ButtonSecondaryHoverBorderColor", buttonSecondaryBorderColor); 281 282 //Link buton 283 string buttonLinkColor = Model.Item.GetString("ButtonLinkColor", "currentColor"); 284 string buttonLinkHoverColorAuto = "currentColor"; 285 if (buttonLinkColor != "currentColor") 286 { 287 buttonLinkHoverColorAuto = "hsl(" + GetColorVariation(buttonLinkColor) + ")"; 288 } 289 string buttonLinkHoverColor = Model.Item.GetString("ButtonLinkHoverColor", buttonLinkHoverColorAuto); 290 291 string accessibilityOutlineColor = Model.Item.GetString("OutlineColor") != null ? Model.Item.GetString("OutlineColor") : ""; 292 293 if (!string.IsNullOrEmpty(themeClassName)) 294 { 295 var sb = new System.Text.StringBuilder(); 296 297 sb.AppendLine("." + themeClassName + "{"); 298 if (!string.IsNullOrEmpty(foregroundColor)) 299 { 300 sb.AppendLine($"--swift-foreground-color: {foregroundColor};"); 301 sb.AppendLine($"--swift-foreground-color-rgb: {HexToRGB(foregroundColor)};"); 302 } 303 if (!string.IsNullOrEmpty(backgroundColor)) 304 { 305 sb.AppendLine($"--swift-background-color: {backgroundColor};"); 306 sb.AppendLine($"--swift-background-color-rgb: {HexToRGB(backgroundColor)};"); 307 } 308 if (!string.IsNullOrEmpty(accentColor)) 309 { 310 sb.AppendLine($"--swift-accent-color: {accentColor};"); 311 sb.AppendLine($"--swift-accent-color-rgb: {HexToRGB(accentColor)};"); 312 } 313 if (!string.IsNullOrEmpty(borderColor)) 314 { 315 sb.AppendLine($"--swift-border-color: {borderColor};"); 316 sb.AppendLine($"--swift-border-color-rgb: {HexToRGB(borderColor)};"); 317 } 318 319 if (!string.IsNullOrEmpty(buttonPrimaryBackgroundColor)) 320 { 321 sb.AppendLine($"--swift-button-primary-background-color: {buttonPrimaryBackgroundColor};"); 322 sb.AppendLine($"--swift-button-primary-background-color-rgb: {HexToRGB(buttonPrimaryBackgroundColor)};"); 323 } 324 if (!string.IsNullOrEmpty(buttonPrimaryForegroundColor)) 325 { 326 sb.AppendLine($"--swift-button-primary-foreground-color: {buttonPrimaryForegroundColor};"); 327 sb.AppendLine($"--swift-button-primary-foreground-color-rgb: {HexToRGB(buttonPrimaryForegroundColor)};"); 328 } 329 if (!string.IsNullOrEmpty(buttonPrimaryBorderColor)) 330 { 331 sb.AppendLine($"--swift-button-primary-border-color: {buttonPrimaryBorderColor};"); 332 sb.AppendLine($"--swift-button-primary-border-color-rgb: {HexToRGB(buttonPrimaryBorderColor)};"); 333 } 334 335 if (!string.IsNullOrEmpty(buttonPrimaryHoverBackgroundColor)) 336 { 337 sb.AppendLine($"--swift-button-primary-hover-background-color: {buttonPrimaryHoverBackgroundColor};"); 338 sb.AppendLine($"--swift-button-primary-hover-background-color-rgb: {HexToRGB(buttonPrimaryHoverBackgroundColor)};"); 339 } 340 if (!string.IsNullOrEmpty(buttonPrimaryHoverForegroundColor)) 341 { 342 sb.AppendLine($"--swift-button-primary-hover-foreground-color: {buttonPrimaryHoverForegroundColor};"); 343 sb.AppendLine($"--swift-button-primary-hover-foreground-color-rgb: {HexToRGB(buttonPrimaryHoverForegroundColor)};"); 344 } 345 if (!string.IsNullOrEmpty(buttonPrimaryHoverBorderColor)) 346 { 347 sb.AppendLine($"--swift-button-primary-hover-border-color: {buttonPrimaryHoverBorderColor};"); 348 sb.AppendLine($"--swift-button-primary-hover-border-color-rgb: {HexToRGB(buttonPrimaryHoverBorderColor)};"); 349 } 350 351 if (!string.IsNullOrEmpty(buttonSecondaryBackgroundColor)) 352 { 353 sb.AppendLine($"--swift-button-secondary-background-color: {buttonSecondaryBackgroundColor};"); 354 sb.AppendLine($"--swift-button-secondary-background-color-rgb: {HexToRGB(buttonSecondaryBackgroundColor)};"); 355 } 356 if (!string.IsNullOrEmpty(buttonSecondaryForegroundColor)) 357 { 358 sb.AppendLine($"--swift-button-secondary-foreground-color: {buttonSecondaryForegroundColor};"); 359 sb.AppendLine($"--swift-button-secondary-foreground-color-rgb: {HexToRGB(buttonSecondaryForegroundColor)};"); 360 } 361 if (!string.IsNullOrEmpty(buttonSecondaryBorderColor)) 362 { 363 sb.AppendLine($"--swift-button-secondary-border-color: {buttonSecondaryBorderColor};"); 364 sb.AppendLine($"--swift-button-secondary-border-color-rgb: {HexToRGB(buttonSecondaryBorderColor)};"); 365 } 366 if (!string.IsNullOrEmpty(buttonSecondaryHoverBackgroundColor)) 367 { 368 sb.AppendLine($"--swift-button-secondary-hover-background-color: {buttonSecondaryHoverBackgroundColor};"); 369 sb.AppendLine($"--swift-button-secondary-hover-background-color-rgb: {HexToRGB(buttonSecondaryHoverBackgroundColor)};"); 370 } 371 if (!string.IsNullOrEmpty(buttonSecondaryHoverForegroundColor)) 372 { 373 sb.AppendLine($"--swift-button-secondary-hover-foreground-color: {buttonSecondaryHoverForegroundColor};"); 374 sb.AppendLine($"--swift-button-secondary-hover-foreground-color-rgb: {HexToRGB(buttonSecondaryHoverForegroundColor)};"); 375 } 376 if (!string.IsNullOrEmpty(buttonSecondaryHoverBorderColor)) 377 { 378 sb.AppendLine($"--swift-button-secondary-hover-border-color: {buttonSecondaryHoverBorderColor};"); 379 sb.AppendLine($"--swift-button-secondary-hover-border-color-rgb: {HexToRGB(buttonSecondaryHoverBorderColor)};"); 380 } 381 if (!string.IsNullOrEmpty(buttonLinkColor)) 382 { 383 sb.AppendLine($"--swift-button-link-color: {buttonLinkColor};"); 384 sb.AppendLine($"--swift-button-link-color-rgb: {HexToRGB(buttonLinkColor)};"); 385 } 386 if (!string.IsNullOrEmpty(buttonLinkHoverColor)) 387 { 388 sb.AppendLine($"--swift-button-link-hover-color: {buttonLinkHoverColor};"); 389 sb.AppendLine($"--swift-button-link-hover-color-rgb: {HexToRGB(buttonLinkHoverColor)};"); 390 } 391 if (!string.IsNullOrEmpty(accessibilityOutlineColor)) 392 { 393 sb.AppendLine($"--swift-a11y-outline-color: {accessibilityOutlineColor};"); 394 sb.AppendLine($"--swift-a11y-outline-color-rgb: {HexToRGB(accessibilityOutlineColor)};"); 395 } 396 sb.AppendLine("}"); 397 398 Dynamicweb.Core.Helpers.TextFileHelper.WriteTextFile(sb.ToString() + Environment.NewLine, Dynamicweb.Context.Current.Server.MapPath($"/Files/Templates/Designs/Swift/_parsed/Swift_css/Swift_theme_styles_{Dynamicweb.Content.Services.Pages.GetPage(Model.PageID).AreaId}.tmp"), true); 399 } 400 } 401 402 @if (themeClassName != "") 403 { 404 string iconPath = "/Files/Templates/Designs/Swift/Assets/icons/"; 405 406 <div class="g-col-12 g-col-lg-4"> 407 <div class="swift-checkered p-3"> 408 <div class="theme-option theme @themeClassName p-lg-3"> 409 <div class="mb-2 pb-1 border-bottom d-flex align-items-center"> 410 <span class="icon-3 me-2"> 411 @ReadFile(iconPath + "sun.svg") 412 </span> 413 <h4 class="m-0 p-0">@themeName</h4> 414 </div> 415 <div class="d-flex flex-column gap-1 mb-2"> 416 <p class="mb-0">This is the body text of the theme.</p> 417 <p class="mb-0" style="color: var(--swift-accent-color)">This is the accent color of the theme.</p> 418 </div> 419 <div> 420 <button class="btn btn-primary me-1">Primary</button> 421 <button class="btn btn-secondary">Secondary</button> 422 <button class="btn btn-link">Link</button> 423 </div> 424 </div> 425 </div> 426 </div> 427 <div class="g-col-12 g-col-lg-8 mb-4 mb-lg-0"> 428 <div class="grid fs-7"> 429 <div class="g-col-12 g-col-lg-3"> 430 <table class="table table-borderless table-sm w-100"> 431 <thead> 432 <tr> 433 <th colspan="2" class="fw-bold">@Translate("Base")</th> 434 </tr> 435 </thead> 436 <tr> 437 <td>@Translate("Foreground")</td> 438 <td>@GetColorSquare(foregroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@foregroundColor');">@foregroundColor</a></td> 439 </tr> 440 <tr> 441 <td>@Translate("Background")</td> 442 <td>@GetColorSquare(backgroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@backgroundColor');">@backgroundColor</a></td> 443 </tr> 444 <tr> 445 <td>@Translate("Accent")</td> 446 <td>@GetColorSquare(accentColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@accentColor');">@accentColor</a></td> 447 </tr> 448 <tr> 449 <td>@Translate("Border")</td> 450 <td>@GetColorSquare(borderColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@borderColor');">@borderColor</a></td> 451 </tr> 452 </table> 453 </div> 454 <div class="g-col-12 g-col-lg-3"> 455 <table class="table table-borderless table-sm w-100"> 456 <thead> 457 <tr> 458 <th colspan="2" class="fw-bold">@Translate("Primary button")</th> 459 </tr> 460 </thead> 461 <tr> 462 <td>@Translate("Foreground")</td> 463 <td>@GetColorSquare(buttonPrimaryForegroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonPrimaryForegroundColor');">@buttonPrimaryForegroundColor</a></td> 464 </tr> 465 <tr> 466 <td>@Translate("Background")</td> 467 <td>@GetColorSquare(buttonPrimaryBackgroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonPrimaryBackgroundColor');">@buttonPrimaryBackgroundColor</a></td> 468 </tr> 469 @if (!string.IsNullOrEmpty(buttonPrimaryBorderColor)) 470 { 471 <tr> 472 <td>@Translate("Border")</td> 473 <td>@GetColorSquare(buttonPrimaryBorderColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonPrimaryBorderColor');">@buttonPrimaryBorderColor</a></td> 474 </tr> 475 } 476 <thead> 477 <tr> 478 <th colspan="2" class="fw-bold">@Translate("Primary button hover")</th> 479 </tr> 480 </thead> 481 @if (!string.IsNullOrEmpty(buttonPrimaryHoverForegroundColor)) 482 { 483 <tr> 484 <td>@Translate("Foreground")</td> 485 <td>@GetColorSquare(buttonPrimaryHoverForegroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonPrimaryHoverForegroundColor');">@buttonPrimaryHoverForegroundColor</a></td> 486 </tr> 487 } 488 @if (!string.IsNullOrEmpty(buttonPrimaryHoverBackgroundColor)) 489 { 490 <tr> 491 <td>@Translate("Background")</td> 492 <td>@GetColorSquare(buttonPrimaryHoverBackgroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonPrimaryHoverBackgroundColor');">@buttonPrimaryHoverBackgroundColor</a></td> 493 </tr> 494 } 495 @if (!string.IsNullOrEmpty(buttonPrimaryHoverBorderColor)) 496 { 497 <tr> 498 <td>@Translate("Border")</td> 499 <td>@GetColorSquare(buttonPrimaryHoverBorderColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonPrimaryHoverBorderColor');">@buttonPrimaryHoverBorderColor</a></td> 500 </tr> 501 } 502 </table> 503 </div> 504 <div class="g-col-12 g-col-lg-3"> 505 <table class="table table-borderless table-sm w-100"> 506 <thead> 507 <tr> 508 <th colspan="2" class="fw-bold">@Translate("Secondary button")</th> 509 </tr> 510 </thead> 511 <tr> 512 <td>@Translate("Foreground")</td> 513 <td>@GetColorSquare(buttonSecondaryForegroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonSecondaryForegroundColor');">@buttonSecondaryForegroundColor</a></td> 514 </tr> 515 <tr> 516 <td>@Translate("Background")</td> 517 <td>@GetColorSquare(buttonSecondaryBackgroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonSecondaryBackgroundColor');">@buttonSecondaryBackgroundColor</a></td> 518 </tr> 519 @if (!string.IsNullOrEmpty(buttonSecondaryBorderColor)) 520 { 521 <tr> 522 <td>@Translate("Border")</td> 523 <td>@GetColorSquare(buttonSecondaryBorderColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonSecondaryBorderColor');">@buttonSecondaryBorderColor</a></td> 524 </tr> 525 } 526 <thead> 527 <tr> 528 <th colspan="2" class="fw-bold">@Translate("Secondary button hover")</th> 529 </tr> 530 </thead> 531 @if (!string.IsNullOrEmpty(buttonSecondaryHoverForegroundColor)) 532 { 533 <tr> 534 <td>@Translate("Foreground")</td> 535 <td>@GetColorSquare(buttonSecondaryHoverForegroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonSecondaryHoverForegroundColor');">@buttonSecondaryHoverForegroundColor</a></td> 536 </tr> 537 } 538 @if (!string.IsNullOrEmpty(buttonSecondaryHoverBackgroundColor)) 539 { 540 <tr> 541 <td>@Translate("Background")</td> 542 <td>@GetColorSquare(buttonSecondaryHoverBackgroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonSecondaryHoverBackgroundColor');">@buttonSecondaryHoverBackgroundColor</a></td> 543 </tr> 544 } 545 @if (!string.IsNullOrEmpty(buttonSecondaryHoverBorderColor)) 546 { 547 <tr> 548 <td>@Translate("Border")</td> 549 <td>@GetColorSquare(buttonSecondaryHoverBorderColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonSecondaryHoverBorderColor');">@buttonSecondaryHoverBorderColor</a></td> 550 </tr> 551 } 552 @if (!string.IsNullOrEmpty(accessibilityOutlineColor)) 553 { 554 <tr> 555 <td>@Translate("Focus outline")</td> 556 <td>@GetColorSquare(accessibilityOutlineColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@accessibilityOutlineColor');">@accessibilityOutlineColor</a></td> 557 </tr> 558 } 559 </table> 560 </div> 561 <div class="g-col-12 g-col-lg-3"> 562 <table class="table table-borderless table-sm w-100"> 563 <thead> 564 <tr> 565 <th colspan="2" class="fw-bold">@Translate("Link button")</th> 566 </tr> 567 </thead> 568 <tr> 569 <td>@Translate("Link color")</td> 570 <td>@GetColorSquare(buttonLinkColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonLinkColor');">@buttonLinkColor</a></td> 571 </tr> 572 <thead> 573 <tr> 574 <th colspan="2" class="fw-bold">@Translate("Link button hover")</th> 575 </tr> 576 </thead> 577 @if (!string.IsNullOrEmpty(buttonLinkHoverColor)) 578 { 579 <tr> 580 <td>@Translate("Link hover color")</td> 581 <td>@GetColorSquare(buttonLinkHoverColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonLinkHoverColor');">@buttonLinkHoverColor</a></td> 582 </tr> 583 } 584 585 @if (!string.IsNullOrEmpty(accessibilityOutlineColor)) 586 { 587 <tr> 588 <td>@Translate("Focus outline")</td> 589 <td>@GetColorSquare(accessibilityOutlineColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@accessibilityOutlineColor');">@accessibilityOutlineColor</a></td> 590 </tr> 591 } 592 </table> 593 </div> 594 <div class="g-col-12 g-col-lg-3"> 595 <table class="table table-borderless table-sm w-100"> 596 <tr> 597 <td class="fw-bold">@Translate("Implementation")</td> 598 </tr> 599 <tr> 600 <td> 601 @{ 602 string implementation = $"<div class=\"theme {themeClassName}\"></div>"; 603 } 604 <div class="text-muted"> 605 <code class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@themeClassName');"> 606 @Dynamicweb.Core.Encoders.HtmlEncoder.HtmlEncode(implementation) 607 </code> 608 </div> 609 </td> 610 </tr> 611 </table> 612 </div> 613 @{ 614 bool hasUsageData = Converter.ToBoolean(Dynamicweb.Context.Current.Request["auditUsages"]); 615 if (hasUsageData) 616 { 617 var themeUsage = GetThemeUsageById(themeClassName); 618 int allUsages = themeUsage?.AllUsages ?? 0; 619 string buttonAttributes = allUsages > 0 ? $"data-bs-toggle=\"modal\" data-bs-target=\"#themeUsage_{Model.ID}\"" : string.Empty; 620 string badgeStyle = allUsages > 0 ? "bg-success" : "bg-danger"; 621 622 <div class="g-col-12 g-col-lg-9 position-relative"> 623 <button type="button" class="btn btn-primary btn-sm position-absolute end-0" @buttonAttributes> 624 Usages 625 <span class="position-absolute top-0 start-100 translate-middle badge rounded-pill text-white @badgeStyle">@allUsages</span> 626 </button> 627 628 @if (allUsages > 0) 629 { 630 int websiteUsages = themeUsage?.WebsiteUsages.Count ?? 0; 631 int pageUsages = themeUsage?.PageUsages.Count ?? 0; 632 int pagePropertyUsages = themeUsage?.PagePropertyUsages.Count ?? 0; 633 int gridRowUsages = themeUsage?.GridRowUsages.Count ?? 0; 634 int paragraphUsages = themeUsage?.ParagraphUsages.Count ?? 0; 635 636 <!-- Modal --> 637 <div class="modal fade" id="themeUsage_@(Model.ID)" tabindex="-1" aria-labelledby="usagesModelLabel" aria-hidden="true"> 638 <div class="modal-dialog modal-xl modal-dialog-centered modal-dialog-scrollable"> 639 <div class="modal-content"> 640 <div class="modal-header"> 641 <h5 class="modal-title" id="usagesModelLabel">@allUsages Usages of '@(themeName)' (@(themeClassName))</h5> 642 <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> 643 </div> 644 <div class="modal-body"> 645 <div class="accordion" id="accordionWrapper"> 646 @if(websiteUsages > 0) 647 { 648 <div class="accordion-item"> 649 <h2 class="accordion-header" id="headingWebsites"> 650 <button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#collapseWebsites" aria-expanded="true" aria-controls="collapseWebsites"> 651 <span class="pe-2">Websites</span><span class="badge rounded-pill bg-secondary text-light">@websiteUsages</span> 652 </button> 653 </h2> 654 <div id="collapseWebsites" class="accordion-collapse collapse show" aria-labelledby="headingWebsites" data-bs-parent="#accordionWrapper"> 655 <div class="accordion-body"> 656 <ul> 657 @foreach (var usage in themeUsage.WebsiteUsages) 658 { 659 var website = Dynamicweb.Content.Services.Areas.GetArea(usage); 660 <li><span class="fw-bold">@website.Name</span>@($" (ID: {usage})")</li> 661 } 662 </ul> 663 </div> 664 </div> 665 </div> 666 } 667 @if (pageUsages > 0) 668 { 669 var pages = Dynamicweb.Content.Services.Pages.GetPages(themeUsage.PageUsages.ToArray()); 670 671 <div class="accordion-item"> 672 <h2 class="accordion-header" id="headingPages"> 673 <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapsePages" aria-expanded="false" aria-controls="collapsePages"> 674 <span class="pe-2">Pages</span><span class="badge rounded-pill bg-secondary text-light">@pageUsages</span> 675 </button> 676 </h2> 677 <div id="collapsePages" class="accordion-collapse collapse" aria-labelledby="headingPages" data-bs-parent="#accordionWrapper"> 678 <div class="accordion-body"> 679 <ul> 680 @foreach (var usage in themeUsage.PageUsages) 681 { 682 <li><span class="fw-bold">@pages.FirstOrDefault(p => p.ID == usage).GetDisplayName()</span>@($" (ID: {usage})")</li> 683 } 684 </ul> 685 </div> 686 </div> 687 </div> 688 } 689 @if (pagePropertyUsages > 0) 690 { 691 var pages = Dynamicweb.Content.Services.Pages.GetPages(themeUsage.PageUsages.ToArray()); 692 693 <div class="accordion-item"> 694 <h2 class="accordion-header" id="headingPageProperties"> 695 <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapsePageProperties" aria-expanded="false" aria-controls="collapsePageProperties"> 696 <span class="pe-2">Page Properties</span><span class="badge rounded-pill bg-secondary text-light">@pagePropertyUsages</span> 697 </button> 698 </h2> 699 <div id="collapsePageProperties" class="accordion-collapse collapse" aria-labelledby="headingPageProperties" data-bs-parent="#accordionWrapper"> 700 <div class="accordion-body"> 701 <ul> 702 @foreach (var usage in themeUsage.PagePropertyUsages) 703 { 704 <li><span class="fw-bold">@pages.FirstOrDefault(p => p.ID == usage).GetDisplayName()</span>@($" (ID: {usage})")</li> 705 } 706 </ul> 707 </div> 708 </div> 709 </div> 710 } 711 @if (gridRowUsages > 0) 712 { 713 var rows = Dynamicweb.Content.Services.Grids.GetGridRows().Where(r => themeUsage.GridRowUsages.Contains(r.ID)).ToList(); 714 715 <div class="accordion-item"> 716 <h2 class="accordion-header" id="headingRows"> 717 <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseRows" aria-expanded="false" aria-controls="collapseRows"> 718 <span class="pe-2">Rows</span><span class="badge rounded-pill bg-secondary text-light">@gridRowUsages</span> 719 </button> 720 </h2> 721 <div id="collapseRows" class="accordion-collapse collapse" aria-labelledby="headingRows" data-bs-parent="#accordionWrapper"> 722 <div class="accordion-body"> 723 <ul> 724 @foreach (var usage in themeUsage.GridRowUsages) 725 { 726 var row = rows.FirstOrDefault(r => r.ID == usage); 727 var page = Dynamicweb.Content.Services.Pages.GetPage(row.PageId); 728 <li>Page: <span class="fw-bold">@(page.GetDisplayName())</span>@($"( ID: {page.ID}) - Row: ")<span class="fw-bold">@(row.DefinitionId)</span>@($" (ID: {usage})")</li> 729 } 730 </ul> 731 </div> 732 </div> 733 </div> 734 } 735 @if (paragraphUsages > 0) 736 { 737 var paragraphs = Dynamicweb.Content.Services.Paragraphs.GetParagraphs().Where(p => themeUsage.ParagraphUsages.Contains(p.ID)).ToList(); 738 739 <div class="accordion-item"> 740 <h2 class="accordion-header" id="headingParagraphs"> 741 <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseParagraphs" aria-expanded="false" aria-controls="collapseParagraphs"> 742 <span class="pe-2">Paragraphs</span><span class="badge rounded-pill bg-secondary text-light">@paragraphUsages</span> 743 </button> 744 </h2> 745 <div id="collapseParagraphs" class="accordion-collapse collapse" aria-labelledby="headingParagraphs" data-bs-parent="#accordionWrapper"> 746 <div class="accordion-body"> 747 <ul> 748 @foreach (var usage in themeUsage.ParagraphUsages) 749 { 750 var paragraph = paragraphs.FirstOrDefault(p => p.ID == usage); 751 var page = Dynamicweb.Content.Services.Pages.GetPage(paragraph.PageID); 752 <li>Page: <span class="fw-bold">@(page.GetDisplayName())</span>@($"( ID: {page.ID}) - Paragraph: ")<span class="fw-bold">@paragraph.Header</span>@($" (ID: {usage})")</li> 753 } 754 </ul> 755 </div> 756 </div> 757 </div> 758 } 759 </div> 760 </div> 761 </div> 762 </div> 763 </div> 764 } 765 </div> 766 } 767 } 768 </div> 769 </div> 770 } 771 <div class="g-col-12"> 772 <hr /> 773 </div> 774
Error executing template "Designs/Swift/Paragraph/Swift_Theme.cshtml" System.Data.SqlClient.SqlException (0x80131904): STRING_AGG aggregation result exceeded the limit of 8000 bytes. Use LOB types to avoid result truncation. at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction) at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose) at System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady) at System.Data.SqlClient.SqlDataReader.TryConsumeMetaData() at System.Data.SqlClient.SqlDataReader.get_MetaData() at System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString, Boolean isInternal, Boolean forDescribeParameterEncryption, Boolean shouldCacheForAlwaysEncrypted) at System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async, Int32 timeout, Task& task, Boolean asyncWrite, Boolean inRetry, SqlDataReader ds, Boolean describeParameterEncryptionRequest) at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, TaskCompletionSource`1 completion, Int32 timeout, Task& task, Boolean& usedCache, Boolean asyncWrite, Boolean inRetry) at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method) at System.Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior behavior, String method) at Dynamicweb.Data.Database.CreateDataReader(IDbCommand command, CommandBehavior behavior) at Dynamicweb.Data.Database.CreateDataReader(String sql, IDbConnection connection, IDbTransaction transaction, CommandBehavior behavior, Int32 commandTimeout, Dictionary`2 sqlParams) at Dynamicweb.Data.Database.CreateDataReader(String sql, IDbConnection connection, IDbTransaction transaction, Int32 commandTimeout, Dictionary`2 sqlParams) at Dynamicweb.Data.Database.CreateDataReader(String sql) at CompiledRazorTemplates.Dynamic.RazorEngine_8e3f1b11eb0041ceb2ca487c2be837e6.UpdateThemeUsages(String sqlQuery, List`1 themeUsages) in E:\Dynamicweb.net\Solutions\Dynamicweb\dw2022.cloud.dynamicweb-cms.com\Files\Templates\Designs\Swift\Paragraph\Swift_Theme.cshtml:line 202 at CompiledRazorTemplates.Dynamic.RazorEngine_8e3f1b11eb0041ceb2ca487c2be837e6.GetAllThemeUsages() in E:\Dynamicweb.net\Solutions\Dynamicweb\dw2022.cloud.dynamicweb-cms.com\Files\Templates\Designs\Swift\Paragraph\Swift_Theme.cshtml:line 184 at CompiledRazorTemplates.Dynamic.RazorEngine_8e3f1b11eb0041ceb2ca487c2be837e6.GetThemeUsageById(String themeId) in E:\Dynamicweb.net\Solutions\Dynamicweb\dw2022.cloud.dynamicweb-cms.com\Files\Templates\Designs\Swift\Paragraph\Swift_Theme.cshtml:line 238 at CompiledRazorTemplates.Dynamic.RazorEngine_8e3f1b11eb0041ceb2ca487c2be837e6.Execute() in E:\Dynamicweb.net\Solutions\Dynamicweb\dw2022.cloud.dynamicweb-cms.com\Files\Templates\Designs\Swift\Paragraph\Swift_Theme.cshtml:line 617 at RazorEngine.Templating.TemplateBase.RazorEngine.Templating.ITemplate.Run(ExecuteContext context, TextWriter reader) at RazorEngine.Templating.RazorEngineService.RunCompile(ITemplateKey key, TextWriter writer, Type modelType, Object model, DynamicViewBag viewBag) at RazorEngine.Templating.RazorEngineServiceExtensions.<>c__DisplayClass16_0.<RunCompile>b__0(TextWriter writer) at RazorEngine.Templating.RazorEngineServiceExtensions.WithWriter(Action`1 withWriter) at Dynamicweb.Rendering.RazorTemplateRenderingProvider.Render(Template template) at Dynamicweb.Rendering.TemplateRenderingService.Render(Template template) at Dynamicweb.Rendering.Template.RenderRazorTemplate() ClientConnectionId:b42d1cec-597c-4eed-bdc2-e0762a41101a Error Number:9829,State:1,Class:16
1 @inherits Dynamicweb.Rendering.ViewModelTemplate<Dynamicweb.Frontend.ParagraphViewModel> 2 @using System.Globalization 3 @using System.Drawing 4 @using Dynamicweb.Core 5 6 @functions{ 7 // Get Hex Color from color picker and translate to RGB color 8 public static string HexToRGB(string hexString) 9 { 10 if (hexString.Equals("none") || string.IsNullOrEmpty(hexString)) 11 return hexString; 12 13 //replace # occurences 14 if (hexString.IndexOf('#') != -1) 15 hexString = hexString.Replace("#", ""); 16 try 17 { 18 int r, g, b = 0; 19 r = int.Parse(hexString.Substring(0, 2), NumberStyles.AllowHexSpecifier); 20 g = int.Parse(hexString.Substring(2, 2), NumberStyles.AllowHexSpecifier); 21 b = int.Parse(hexString.Substring(4, 2), NumberStyles.AllowHexSpecifier); 22 23 string rgb = r + "," + g + "," + b; 24 return rgb; 25 } 26 catch (System.Exception) 27 { 28 return hexString; 29 } 30 } 31 32 public static string GetColorSquare(string hex) 33 { 34 return $"<div class=\"swift-checkered d-inline-block me-1\" style=\"height:1.25rem;width:1.25rem;\"><div style=\"background-color: {hex};border:.0625rem solid grey\" class=\"w-100 h-100\"></div></div>"; 35 } 36 37 public class HSL 38 { 39 public double h { get; set; } 40 public double s { get; set; } 41 public double l { get; set; } 42 } 43 44 //Convert HEX to HSL 45 public static HSL HexToHsl(string hexString) 46 { 47 System.Drawing.Color color = System.Drawing.ColorTranslator.FromHtml(hexString); 48 49 float _R = (color.R / 255f); 50 float _G = (color.G / 255f); 51 float _B = (color.B / 255f); 52 53 float _Min = Math.Min(Math.Min(_R, _G), _B); 54 float _Max = Math.Max(Math.Max(_R, _G), _B); 55 float _Delta = _Max - _Min; 56 57 float S = 0; 58 float L = (float)((_Max + _Min) / 2.0f); 59 60 if (_Delta != 0) 61 { 62 if (L < 0.5f) 63 { 64 S = (float)(_Delta / (_Max + _Min)); 65 } 66 else 67 { 68 S = (float)(_Delta / (2.0f - _Max - _Min)); 69 } 70 } 71 72 HSL hsl = new HSL(); 73 hsl.h = Math.Round(color.GetHue(), 2); 74 hsl.s = Math.Round(S, 2) * 100; 75 hsl.l = Math.Round(L, 2) * 100; 76 77 return hsl; 78 } 79 80 //Find contrast color (white, black) 81 public static Color GetContrastColor(string hexString) 82 { 83 System.Drawing.Color bg = System.Drawing.ColorTranslator.FromHtml(hexString); 84 85 int nThreshold = 105; 86 int bgDelta = Convert.ToInt32((bg.R * 0.299) + (bg.G * 0.587) + 87 (bg.B * 0.114)); 88 89 Color foreColor = (255 - bgDelta < nThreshold) ? Color.Black : Color.White; 90 return foreColor; 91 } 92 93 public string GetColorVariation(string hexString) 94 { 95 var contrast = GetContrastColor(hexString); 96 HSL currentHslColor = HexToHsl(hexString); 97 HSL variantHslColor = currentHslColor; 98 99 if (contrast == Color.Black) 100 { 101 variantHslColor.l = 85; //The background is dark - Color should be light 102 } 103 else 104 { 105 variantHslColor.l = 40; //The background is light - Color should be less light 106 } 107 108 //Color is very light 109 if (currentHslColor.l > 85) 110 { 111 variantHslColor.l = 95; 112 } 113 114 string colorString = variantHslColor.h + ", " + variantHslColor.s + "%, " + variantHslColor.l + "%"; 115 return colorString; 116 } 117 118 private class ThemeDatabaseUsage 119 { 120 public string TableName { get; set; } 121 public string ColumnName { get; set; } 122 } 123 124 private class ThemeUsage 125 { 126 public string Id { get; set; } 127 public List<int> WebsiteUsages { get; set; } = new List<int>(); 128 public List<int> PageUsages { get; set; } = new List<int>(); 129 public List<int> PagePropertyUsages { get; set; } = new List<int>(); 130 public List<int> GridRowUsages { get; set; } = new List<int>(); 131 public List<int> ParagraphUsages { get; set; } = new List<int>(); 132 public int AllUsages { get; set; } = 0; 133 } 134 135 private List<ThemeDatabaseUsage> GetThemeColumnsFromSchema() 136 { 137 string cacheKey = "ThemesFromDatabase"; 138 if (Dynamicweb.Context.Current.Items.Contains(cacheKey)) 139 { 140 return (List<ThemeDatabaseUsage>)Dynamicweb.Context.Current.Items[cacheKey]; 141 } 142 var schema = Dynamicweb.Data.Database.CreateDataReader("SELECT table_name, column_name FROM information_schema.columns WHERE column_name LIKE '%Theme%'"); 143 144 var rawData = new List<ThemeDatabaseUsage>(); 145 while (schema.Read()) { 146 rawData.Add(new ThemeDatabaseUsage {TableName = schema["table_name"].ToString(), ColumnName = schema["column_name"].ToString() }); 147 } 148 Dynamicweb.Context.Current.Items[cacheKey] = rawData; 149 return rawData; 150 } 151 152 private List<ThemeUsage> GetAllThemeUsages() 153 { 154 string cacheKey = "ThemeUsages"; 155 if (Dynamicweb.Context.Current.Items.Contains(cacheKey)) 156 { 157 return (List<ThemeUsage>)Dynamicweb.Context.Current.Items[cacheKey]; 158 } 159 160 var rawData = GetThemeColumnsFromSchema(); 161 var themeUsages = new List<ThemeUsage>(); 162 163 var sqlQuery = ""; 164 foreach (var row in rawData) 165 { 166 if (!string.IsNullOrEmpty(sqlQuery)) { sqlQuery += " UNION ALL "; } 167 sqlQuery += $"SELECT '{row.TableName}' AS TableName, '{row.ColumnName}' AS ColumnName, {row.ColumnName} AS ColumnValue, Id, AreaId, Page.PageId, PageProperties.PageId as 'PagePropertiesId', GridRowId, ParagraphId" + 168 $" FROM [{row.TableName}]" + 169 $" LEFT JOIN Area ON AreaItemType = '{row.TableName.Replace("ItemType_","")}' AND AreaItemId = Id" + 170 $" LEFT JOIN Page ON PageItemType = '{row.TableName.Replace("ItemType_","")}' AND PageItemId = Id" + 171 $" LEFT JOIN Page as PageProperties ON AreaItemTypePageProperty = '{row.TableName.Replace("ItemType_","")}' AND PageProperties.PagePropertyItemId = Id" + 172 $" LEFT JOIN GridRow ON GridRowItemType = '{row.TableName.Replace("ItemType_","")}' AND GridRowItemId = Id" + 173 $" LEFT JOIN Paragraph ON ParagraphItemType = '{row.TableName.Replace("ItemType_","")}' AND ParagraphItemId = Id" + 174 $" WHERE {row.ColumnName} != '' AND {row.ColumnName} IS NOT NULL" + 175 $" AND (AreaId IS NULL OR AreaId = {Pageview.AreaID})" + 176 $" AND (Page.PageId IS NULL OR Page.PageAreaId = {Pageview.AreaID})" + 177 $" AND (PageProperties.PageId IS NULL OR PageProperties.PageAreaId = {Pageview.AreaID})" + 178 $" AND (GridRowId IS NULL OR GridRowPageId IN (SELECT value From string_split(@pageIds, ',')))" + 179 $" AND (ParagraphId IS NULL OR ParagraphPageId IN (SELECT value From string_split(@pageIds, ',')))"; 180 181 var maxMsSqlServerCharLimit = 60000; 182 if (sqlQuery.Length > maxMsSqlServerCharLimit) 183 { 184 UpdateThemeUsages(sqlQuery, themeUsages); 185 sqlQuery = ""; 186 } 187 } 188 189 if (!string.IsNullOrEmpty(sqlQuery)) 190 { 191 UpdateThemeUsages(sqlQuery, themeUsages); 192 } 193 UpdateAllUsages(themeUsages); 194 195 Dynamicweb.Context.Current.Items[cacheKey] = themeUsages; 196 return themeUsages; 197 } 198 199 private void UpdateThemeUsages(string sqlQuery, List<ThemeUsage> themeUsages) 200 { 201 sqlQuery = $"DECLARE @pageIds NVARCHAR(max) = (SELECT STRING_AGG(PageId,',') FROM Page WHERE PageAreaId = {Pageview.AreaID}) " + sqlQuery; 202 var rawData = Dynamicweb.Data.Database.CreateDataReader(sqlQuery); 203 while (rawData.Read()) 204 { 205 var themeId = rawData["ColumnValue"].ToString(); 206 var themeUsageExists = themeUsages.FirstOrDefault(t => t.Id == themeId) != null; 207 if (!themeUsageExists) 208 { 209 themeUsages.Add(new ThemeUsage { Id = themeId }); 210 } 211 212 var themeUsage = themeUsages.FirstOrDefault(t => t.Id == themeId); 213 if (themeUsage == null) continue; 214 215 if (Converter.ToInt32(rawData["AreaId"].ToString()) > 0) { themeUsage.WebsiteUsages.Add(Converter.ToInt32(rawData["AreaId"].ToString())); } 216 if (Converter.ToInt32(rawData["PageId"].ToString()) > 0) { themeUsage.PageUsages.Add(Converter.ToInt32(rawData["PageId"].ToString())); } 217 if (Converter.ToInt32(rawData["PagePropertiesId"].ToString()) > 0) { themeUsage.PagePropertyUsages.Add(Converter.ToInt32(rawData["PagePropertiesId"].ToString())); } 218 if (Converter.ToInt32(rawData["GridRowId"].ToString()) > 0) { themeUsage.GridRowUsages.Add(Converter.ToInt32(rawData["GridRowId"].ToString())); } 219 if (Converter.ToInt32(rawData["ParagraphId"].ToString()) > 0) { themeUsage.ParagraphUsages.Add(Converter.ToInt32(rawData["ParagraphId"].ToString())); } 220 } 221 } 222 223 private void UpdateAllUsages(List<ThemeUsage> themeUsages) 224 { 225 foreach (var themeUsage in themeUsages) 226 { 227 int websiteUsages = themeUsage?.WebsiteUsages.Count ?? 0; 228 int pageUsages = themeUsage?.PageUsages.Count ?? 0; 229 int pagePropertyUsages = themeUsage?.PagePropertyUsages.Count ?? 0; 230 int gridRowUsages = themeUsage?.GridRowUsages.Count ?? 0; 231 int paragraphUsages = themeUsage?.ParagraphUsages.Count ?? 0; 232 themeUsage.AllUsages = websiteUsages + pageUsages + pagePropertyUsages + gridRowUsages + paragraphUsages; 233 } 234 } 235 236 private ThemeUsage GetThemeUsageById(string themeId) 237 { 238 var themeUsages = GetAllThemeUsages(); 239 return themeUsages.FirstOrDefault(t => t.Id == themeId); 240 } 241 242 } 243 244 @{ 245 string themeName = !string.IsNullOrWhiteSpace(Model.Item.GetString("Name")) ? Model.Item.GetString("Name") : "Default"; 246 string themeClassName = !string.IsNullOrWhiteSpace(Model.Item.GetString("CSSClassName")) ? Model.Item.GetString("CSSClassName").Replace(" ", "").Trim().ToLower() : ""; 247 248 //Theme colors 249 string foregroundColor = Model.Item.GetString("ForegroundColor", "currentColor"); 250 string backgroundColor = Model.Item.GetString("BackgroundColor", "transparent"); 251 string accentColor = Model.Item.GetString("accentColor", "currentColor"); 252 string borderColor = Model.Item.GetString("BorderColor", "transparent"); 253 254 //Primary button 255 string buttonPrimaryForegroundColor = Model.Item.GetString("ButtonPrimaryForegroundColor", "currentColor"); 256 string buttonPrimaryBackgroundColor = Model.Item.GetString("ButtonPrimaryBackgroundColor", "transparent"); 257 string buttonPrimaryBorderColor = Model.Item.GetString("ButtonPrimaryBorderColor", "transparent"); 258 259 string buttonPrimaryHoverBackgroundColorAuto = "transparent"; 260 if (buttonPrimaryBackgroundColor != "transparent") 261 { 262 buttonPrimaryHoverBackgroundColorAuto = "hsl(" + GetColorVariation(buttonPrimaryBackgroundColor) + ")"; 263 } 264 string buttonPrimaryHoverForegroundColor = Model.Item.GetString("ButtonPrimaryHoverForegroundColor", buttonPrimaryForegroundColor); 265 string buttonPrimaryHoverBackgroundColor = Model.Item.GetString("ButtonPrimaryHoverBackgroundColor", buttonPrimaryHoverBackgroundColorAuto); 266 string buttonPrimaryHoverBorderColor = Model.Item.GetString("ButtonPrimaryHoverBorderColor", buttonPrimaryBorderColor); 267 268 //Secondary buton 269 string buttonSecondaryForegroundColor = Model.Item.GetString("ButtonSecondaryForegroundColor", "currentColor"); 270 string buttonSecondaryBackgroundColor = Model.Item.GetString("ButtonSecondaryBackgroundColor", "transparent"); 271 string buttonSecondaryBorderColor = Model.Item.GetString("ButtonSecondaryBorderColor", "transparent"); 272 273 string buttonSecondaryHoverBackgroundColorAuto = "transparent"; 274 if (buttonSecondaryBackgroundColor != "transparent") 275 { 276 buttonSecondaryHoverBackgroundColorAuto = "hsl(" + GetColorVariation(buttonSecondaryBackgroundColor) + ")"; 277 } 278 string buttonSecondaryHoverForegroundColor = Model.Item.GetString("ButtonSecondaryHoverForegroundColor", buttonSecondaryForegroundColor); 279 string buttonSecondaryHoverBackgroundColor = Model.Item.GetString("ButtonSecondaryHoverBackgroundColor", buttonSecondaryHoverBackgroundColorAuto); 280 string buttonSecondaryHoverBorderColor = Model.Item.GetString("ButtonSecondaryHoverBorderColor", buttonSecondaryBorderColor); 281 282 //Link buton 283 string buttonLinkColor = Model.Item.GetString("ButtonLinkColor", "currentColor"); 284 string buttonLinkHoverColorAuto = "currentColor"; 285 if (buttonLinkColor != "currentColor") 286 { 287 buttonLinkHoverColorAuto = "hsl(" + GetColorVariation(buttonLinkColor) + ")"; 288 } 289 string buttonLinkHoverColor = Model.Item.GetString("ButtonLinkHoverColor", buttonLinkHoverColorAuto); 290 291 string accessibilityOutlineColor = Model.Item.GetString("OutlineColor") != null ? Model.Item.GetString("OutlineColor") : ""; 292 293 if (!string.IsNullOrEmpty(themeClassName)) 294 { 295 var sb = new System.Text.StringBuilder(); 296 297 sb.AppendLine("." + themeClassName + "{"); 298 if (!string.IsNullOrEmpty(foregroundColor)) 299 { 300 sb.AppendLine($"--swift-foreground-color: {foregroundColor};"); 301 sb.AppendLine($"--swift-foreground-color-rgb: {HexToRGB(foregroundColor)};"); 302 } 303 if (!string.IsNullOrEmpty(backgroundColor)) 304 { 305 sb.AppendLine($"--swift-background-color: {backgroundColor};"); 306 sb.AppendLine($"--swift-background-color-rgb: {HexToRGB(backgroundColor)};"); 307 } 308 if (!string.IsNullOrEmpty(accentColor)) 309 { 310 sb.AppendLine($"--swift-accent-color: {accentColor};"); 311 sb.AppendLine($"--swift-accent-color-rgb: {HexToRGB(accentColor)};"); 312 } 313 if (!string.IsNullOrEmpty(borderColor)) 314 { 315 sb.AppendLine($"--swift-border-color: {borderColor};"); 316 sb.AppendLine($"--swift-border-color-rgb: {HexToRGB(borderColor)};"); 317 } 318 319 if (!string.IsNullOrEmpty(buttonPrimaryBackgroundColor)) 320 { 321 sb.AppendLine($"--swift-button-primary-background-color: {buttonPrimaryBackgroundColor};"); 322 sb.AppendLine($"--swift-button-primary-background-color-rgb: {HexToRGB(buttonPrimaryBackgroundColor)};"); 323 } 324 if (!string.IsNullOrEmpty(buttonPrimaryForegroundColor)) 325 { 326 sb.AppendLine($"--swift-button-primary-foreground-color: {buttonPrimaryForegroundColor};"); 327 sb.AppendLine($"--swift-button-primary-foreground-color-rgb: {HexToRGB(buttonPrimaryForegroundColor)};"); 328 } 329 if (!string.IsNullOrEmpty(buttonPrimaryBorderColor)) 330 { 331 sb.AppendLine($"--swift-button-primary-border-color: {buttonPrimaryBorderColor};"); 332 sb.AppendLine($"--swift-button-primary-border-color-rgb: {HexToRGB(buttonPrimaryBorderColor)};"); 333 } 334 335 if (!string.IsNullOrEmpty(buttonPrimaryHoverBackgroundColor)) 336 { 337 sb.AppendLine($"--swift-button-primary-hover-background-color: {buttonPrimaryHoverBackgroundColor};"); 338 sb.AppendLine($"--swift-button-primary-hover-background-color-rgb: {HexToRGB(buttonPrimaryHoverBackgroundColor)};"); 339 } 340 if (!string.IsNullOrEmpty(buttonPrimaryHoverForegroundColor)) 341 { 342 sb.AppendLine($"--swift-button-primary-hover-foreground-color: {buttonPrimaryHoverForegroundColor};"); 343 sb.AppendLine($"--swift-button-primary-hover-foreground-color-rgb: {HexToRGB(buttonPrimaryHoverForegroundColor)};"); 344 } 345 if (!string.IsNullOrEmpty(buttonPrimaryHoverBorderColor)) 346 { 347 sb.AppendLine($"--swift-button-primary-hover-border-color: {buttonPrimaryHoverBorderColor};"); 348 sb.AppendLine($"--swift-button-primary-hover-border-color-rgb: {HexToRGB(buttonPrimaryHoverBorderColor)};"); 349 } 350 351 if (!string.IsNullOrEmpty(buttonSecondaryBackgroundColor)) 352 { 353 sb.AppendLine($"--swift-button-secondary-background-color: {buttonSecondaryBackgroundColor};"); 354 sb.AppendLine($"--swift-button-secondary-background-color-rgb: {HexToRGB(buttonSecondaryBackgroundColor)};"); 355 } 356 if (!string.IsNullOrEmpty(buttonSecondaryForegroundColor)) 357 { 358 sb.AppendLine($"--swift-button-secondary-foreground-color: {buttonSecondaryForegroundColor};"); 359 sb.AppendLine($"--swift-button-secondary-foreground-color-rgb: {HexToRGB(buttonSecondaryForegroundColor)};"); 360 } 361 if (!string.IsNullOrEmpty(buttonSecondaryBorderColor)) 362 { 363 sb.AppendLine($"--swift-button-secondary-border-color: {buttonSecondaryBorderColor};"); 364 sb.AppendLine($"--swift-button-secondary-border-color-rgb: {HexToRGB(buttonSecondaryBorderColor)};"); 365 } 366 if (!string.IsNullOrEmpty(buttonSecondaryHoverBackgroundColor)) 367 { 368 sb.AppendLine($"--swift-button-secondary-hover-background-color: {buttonSecondaryHoverBackgroundColor};"); 369 sb.AppendLine($"--swift-button-secondary-hover-background-color-rgb: {HexToRGB(buttonSecondaryHoverBackgroundColor)};"); 370 } 371 if (!string.IsNullOrEmpty(buttonSecondaryHoverForegroundColor)) 372 { 373 sb.AppendLine($"--swift-button-secondary-hover-foreground-color: {buttonSecondaryHoverForegroundColor};"); 374 sb.AppendLine($"--swift-button-secondary-hover-foreground-color-rgb: {HexToRGB(buttonSecondaryHoverForegroundColor)};"); 375 } 376 if (!string.IsNullOrEmpty(buttonSecondaryHoverBorderColor)) 377 { 378 sb.AppendLine($"--swift-button-secondary-hover-border-color: {buttonSecondaryHoverBorderColor};"); 379 sb.AppendLine($"--swift-button-secondary-hover-border-color-rgb: {HexToRGB(buttonSecondaryHoverBorderColor)};"); 380 } 381 if (!string.IsNullOrEmpty(buttonLinkColor)) 382 { 383 sb.AppendLine($"--swift-button-link-color: {buttonLinkColor};"); 384 sb.AppendLine($"--swift-button-link-color-rgb: {HexToRGB(buttonLinkColor)};"); 385 } 386 if (!string.IsNullOrEmpty(buttonLinkHoverColor)) 387 { 388 sb.AppendLine($"--swift-button-link-hover-color: {buttonLinkHoverColor};"); 389 sb.AppendLine($"--swift-button-link-hover-color-rgb: {HexToRGB(buttonLinkHoverColor)};"); 390 } 391 if (!string.IsNullOrEmpty(accessibilityOutlineColor)) 392 { 393 sb.AppendLine($"--swift-a11y-outline-color: {accessibilityOutlineColor};"); 394 sb.AppendLine($"--swift-a11y-outline-color-rgb: {HexToRGB(accessibilityOutlineColor)};"); 395 } 396 sb.AppendLine("}"); 397 398 Dynamicweb.Core.Helpers.TextFileHelper.WriteTextFile(sb.ToString() + Environment.NewLine, Dynamicweb.Context.Current.Server.MapPath($"/Files/Templates/Designs/Swift/_parsed/Swift_css/Swift_theme_styles_{Dynamicweb.Content.Services.Pages.GetPage(Model.PageID).AreaId}.tmp"), true); 399 } 400 } 401 402 @if (themeClassName != "") 403 { 404 string iconPath = "/Files/Templates/Designs/Swift/Assets/icons/"; 405 406 <div class="g-col-12 g-col-lg-4"> 407 <div class="swift-checkered p-3"> 408 <div class="theme-option theme @themeClassName p-lg-3"> 409 <div class="mb-2 pb-1 border-bottom d-flex align-items-center"> 410 <span class="icon-3 me-2"> 411 @ReadFile(iconPath + "sun.svg") 412 </span> 413 <h4 class="m-0 p-0">@themeName</h4> 414 </div> 415 <div class="d-flex flex-column gap-1 mb-2"> 416 <p class="mb-0">This is the body text of the theme.</p> 417 <p class="mb-0" style="color: var(--swift-accent-color)">This is the accent color of the theme.</p> 418 </div> 419 <div> 420 <button class="btn btn-primary me-1">Primary</button> 421 <button class="btn btn-secondary">Secondary</button> 422 <button class="btn btn-link">Link</button> 423 </div> 424 </div> 425 </div> 426 </div> 427 <div class="g-col-12 g-col-lg-8 mb-4 mb-lg-0"> 428 <div class="grid fs-7"> 429 <div class="g-col-12 g-col-lg-3"> 430 <table class="table table-borderless table-sm w-100"> 431 <thead> 432 <tr> 433 <th colspan="2" class="fw-bold">@Translate("Base")</th> 434 </tr> 435 </thead> 436 <tr> 437 <td>@Translate("Foreground")</td> 438 <td>@GetColorSquare(foregroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@foregroundColor');">@foregroundColor</a></td> 439 </tr> 440 <tr> 441 <td>@Translate("Background")</td> 442 <td>@GetColorSquare(backgroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@backgroundColor');">@backgroundColor</a></td> 443 </tr> 444 <tr> 445 <td>@Translate("Accent")</td> 446 <td>@GetColorSquare(accentColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@accentColor');">@accentColor</a></td> 447 </tr> 448 <tr> 449 <td>@Translate("Border")</td> 450 <td>@GetColorSquare(borderColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@borderColor');">@borderColor</a></td> 451 </tr> 452 </table> 453 </div> 454 <div class="g-col-12 g-col-lg-3"> 455 <table class="table table-borderless table-sm w-100"> 456 <thead> 457 <tr> 458 <th colspan="2" class="fw-bold">@Translate("Primary button")</th> 459 </tr> 460 </thead> 461 <tr> 462 <td>@Translate("Foreground")</td> 463 <td>@GetColorSquare(buttonPrimaryForegroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonPrimaryForegroundColor');">@buttonPrimaryForegroundColor</a></td> 464 </tr> 465 <tr> 466 <td>@Translate("Background")</td> 467 <td>@GetColorSquare(buttonPrimaryBackgroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonPrimaryBackgroundColor');">@buttonPrimaryBackgroundColor</a></td> 468 </tr> 469 @if (!string.IsNullOrEmpty(buttonPrimaryBorderColor)) 470 { 471 <tr> 472 <td>@Translate("Border")</td> 473 <td>@GetColorSquare(buttonPrimaryBorderColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonPrimaryBorderColor');">@buttonPrimaryBorderColor</a></td> 474 </tr> 475 } 476 <thead> 477 <tr> 478 <th colspan="2" class="fw-bold">@Translate("Primary button hover")</th> 479 </tr> 480 </thead> 481 @if (!string.IsNullOrEmpty(buttonPrimaryHoverForegroundColor)) 482 { 483 <tr> 484 <td>@Translate("Foreground")</td> 485 <td>@GetColorSquare(buttonPrimaryHoverForegroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonPrimaryHoverForegroundColor');">@buttonPrimaryHoverForegroundColor</a></td> 486 </tr> 487 } 488 @if (!string.IsNullOrEmpty(buttonPrimaryHoverBackgroundColor)) 489 { 490 <tr> 491 <td>@Translate("Background")</td> 492 <td>@GetColorSquare(buttonPrimaryHoverBackgroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonPrimaryHoverBackgroundColor');">@buttonPrimaryHoverBackgroundColor</a></td> 493 </tr> 494 } 495 @if (!string.IsNullOrEmpty(buttonPrimaryHoverBorderColor)) 496 { 497 <tr> 498 <td>@Translate("Border")</td> 499 <td>@GetColorSquare(buttonPrimaryHoverBorderColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonPrimaryHoverBorderColor');">@buttonPrimaryHoverBorderColor</a></td> 500 </tr> 501 } 502 </table> 503 </div> 504 <div class="g-col-12 g-col-lg-3"> 505 <table class="table table-borderless table-sm w-100"> 506 <thead> 507 <tr> 508 <th colspan="2" class="fw-bold">@Translate("Secondary button")</th> 509 </tr> 510 </thead> 511 <tr> 512 <td>@Translate("Foreground")</td> 513 <td>@GetColorSquare(buttonSecondaryForegroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonSecondaryForegroundColor');">@buttonSecondaryForegroundColor</a></td> 514 </tr> 515 <tr> 516 <td>@Translate("Background")</td> 517 <td>@GetColorSquare(buttonSecondaryBackgroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonSecondaryBackgroundColor');">@buttonSecondaryBackgroundColor</a></td> 518 </tr> 519 @if (!string.IsNullOrEmpty(buttonSecondaryBorderColor)) 520 { 521 <tr> 522 <td>@Translate("Border")</td> 523 <td>@GetColorSquare(buttonSecondaryBorderColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonSecondaryBorderColor');">@buttonSecondaryBorderColor</a></td> 524 </tr> 525 } 526 <thead> 527 <tr> 528 <th colspan="2" class="fw-bold">@Translate("Secondary button hover")</th> 529 </tr> 530 </thead> 531 @if (!string.IsNullOrEmpty(buttonSecondaryHoverForegroundColor)) 532 { 533 <tr> 534 <td>@Translate("Foreground")</td> 535 <td>@GetColorSquare(buttonSecondaryHoverForegroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonSecondaryHoverForegroundColor');">@buttonSecondaryHoverForegroundColor</a></td> 536 </tr> 537 } 538 @if (!string.IsNullOrEmpty(buttonSecondaryHoverBackgroundColor)) 539 { 540 <tr> 541 <td>@Translate("Background")</td> 542 <td>@GetColorSquare(buttonSecondaryHoverBackgroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonSecondaryHoverBackgroundColor');">@buttonSecondaryHoverBackgroundColor</a></td> 543 </tr> 544 } 545 @if (!string.IsNullOrEmpty(buttonSecondaryHoverBorderColor)) 546 { 547 <tr> 548 <td>@Translate("Border")</td> 549 <td>@GetColorSquare(buttonSecondaryHoverBorderColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonSecondaryHoverBorderColor');">@buttonSecondaryHoverBorderColor</a></td> 550 </tr> 551 } 552 @if (!string.IsNullOrEmpty(accessibilityOutlineColor)) 553 { 554 <tr> 555 <td>@Translate("Focus outline")</td> 556 <td>@GetColorSquare(accessibilityOutlineColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@accessibilityOutlineColor');">@accessibilityOutlineColor</a></td> 557 </tr> 558 } 559 </table> 560 </div> 561 <div class="g-col-12 g-col-lg-3"> 562 <table class="table table-borderless table-sm w-100"> 563 <thead> 564 <tr> 565 <th colspan="2" class="fw-bold">@Translate("Link button")</th> 566 </tr> 567 </thead> 568 <tr> 569 <td>@Translate("Link color")</td> 570 <td>@GetColorSquare(buttonLinkColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonLinkColor');">@buttonLinkColor</a></td> 571 </tr> 572 <thead> 573 <tr> 574 <th colspan="2" class="fw-bold">@Translate("Link button hover")</th> 575 </tr> 576 </thead> 577 @if (!string.IsNullOrEmpty(buttonLinkHoverColor)) 578 { 579 <tr> 580 <td>@Translate("Link hover color")</td> 581 <td>@GetColorSquare(buttonLinkHoverColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonLinkHoverColor');">@buttonLinkHoverColor</a></td> 582 </tr> 583 } 584 585 @if (!string.IsNullOrEmpty(accessibilityOutlineColor)) 586 { 587 <tr> 588 <td>@Translate("Focus outline")</td> 589 <td>@GetColorSquare(accessibilityOutlineColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@accessibilityOutlineColor');">@accessibilityOutlineColor</a></td> 590 </tr> 591 } 592 </table> 593 </div> 594 <div class="g-col-12 g-col-lg-3"> 595 <table class="table table-borderless table-sm w-100"> 596 <tr> 597 <td class="fw-bold">@Translate("Implementation")</td> 598 </tr> 599 <tr> 600 <td> 601 @{ 602 string implementation = $"<div class=\"theme {themeClassName}\"></div>"; 603 } 604 <div class="text-muted"> 605 <code class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@themeClassName');"> 606 @Dynamicweb.Core.Encoders.HtmlEncoder.HtmlEncode(implementation) 607 </code> 608 </div> 609 </td> 610 </tr> 611 </table> 612 </div> 613 @{ 614 bool hasUsageData = Converter.ToBoolean(Dynamicweb.Context.Current.Request["auditUsages"]); 615 if (hasUsageData) 616 { 617 var themeUsage = GetThemeUsageById(themeClassName); 618 int allUsages = themeUsage?.AllUsages ?? 0; 619 string buttonAttributes = allUsages > 0 ? $"data-bs-toggle=\"modal\" data-bs-target=\"#themeUsage_{Model.ID}\"" : string.Empty; 620 string badgeStyle = allUsages > 0 ? "bg-success" : "bg-danger"; 621 622 <div class="g-col-12 g-col-lg-9 position-relative"> 623 <button type="button" class="btn btn-primary btn-sm position-absolute end-0" @buttonAttributes> 624 Usages 625 <span class="position-absolute top-0 start-100 translate-middle badge rounded-pill text-white @badgeStyle">@allUsages</span> 626 </button> 627 628 @if (allUsages > 0) 629 { 630 int websiteUsages = themeUsage?.WebsiteUsages.Count ?? 0; 631 int pageUsages = themeUsage?.PageUsages.Count ?? 0; 632 int pagePropertyUsages = themeUsage?.PagePropertyUsages.Count ?? 0; 633 int gridRowUsages = themeUsage?.GridRowUsages.Count ?? 0; 634 int paragraphUsages = themeUsage?.ParagraphUsages.Count ?? 0; 635 636 <!-- Modal --> 637 <div class="modal fade" id="themeUsage_@(Model.ID)" tabindex="-1" aria-labelledby="usagesModelLabel" aria-hidden="true"> 638 <div class="modal-dialog modal-xl modal-dialog-centered modal-dialog-scrollable"> 639 <div class="modal-content"> 640 <div class="modal-header"> 641 <h5 class="modal-title" id="usagesModelLabel">@allUsages Usages of '@(themeName)' (@(themeClassName))</h5> 642 <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> 643 </div> 644 <div class="modal-body"> 645 <div class="accordion" id="accordionWrapper"> 646 @if(websiteUsages > 0) 647 { 648 <div class="accordion-item"> 649 <h2 class="accordion-header" id="headingWebsites"> 650 <button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#collapseWebsites" aria-expanded="true" aria-controls="collapseWebsites"> 651 <span class="pe-2">Websites</span><span class="badge rounded-pill bg-secondary text-light">@websiteUsages</span> 652 </button> 653 </h2> 654 <div id="collapseWebsites" class="accordion-collapse collapse show" aria-labelledby="headingWebsites" data-bs-parent="#accordionWrapper"> 655 <div class="accordion-body"> 656 <ul> 657 @foreach (var usage in themeUsage.WebsiteUsages) 658 { 659 var website = Dynamicweb.Content.Services.Areas.GetArea(usage); 660 <li><span class="fw-bold">@website.Name</span>@($" (ID: {usage})")</li> 661 } 662 </ul> 663 </div> 664 </div> 665 </div> 666 } 667 @if (pageUsages > 0) 668 { 669 var pages = Dynamicweb.Content.Services.Pages.GetPages(themeUsage.PageUsages.ToArray()); 670 671 <div class="accordion-item"> 672 <h2 class="accordion-header" id="headingPages"> 673 <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapsePages" aria-expanded="false" aria-controls="collapsePages"> 674 <span class="pe-2">Pages</span><span class="badge rounded-pill bg-secondary text-light">@pageUsages</span> 675 </button> 676 </h2> 677 <div id="collapsePages" class="accordion-collapse collapse" aria-labelledby="headingPages" data-bs-parent="#accordionWrapper"> 678 <div class="accordion-body"> 679 <ul> 680 @foreach (var usage in themeUsage.PageUsages) 681 { 682 <li><span class="fw-bold">@pages.FirstOrDefault(p => p.ID == usage).GetDisplayName()</span>@($" (ID: {usage})")</li> 683 } 684 </ul> 685 </div> 686 </div> 687 </div> 688 } 689 @if (pagePropertyUsages > 0) 690 { 691 var pages = Dynamicweb.Content.Services.Pages.GetPages(themeUsage.PageUsages.ToArray()); 692 693 <div class="accordion-item"> 694 <h2 class="accordion-header" id="headingPageProperties"> 695 <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapsePageProperties" aria-expanded="false" aria-controls="collapsePageProperties"> 696 <span class="pe-2">Page Properties</span><span class="badge rounded-pill bg-secondary text-light">@pagePropertyUsages</span> 697 </button> 698 </h2> 699 <div id="collapsePageProperties" class="accordion-collapse collapse" aria-labelledby="headingPageProperties" data-bs-parent="#accordionWrapper"> 700 <div class="accordion-body"> 701 <ul> 702 @foreach (var usage in themeUsage.PagePropertyUsages) 703 { 704 <li><span class="fw-bold">@pages.FirstOrDefault(p => p.ID == usage).GetDisplayName()</span>@($" (ID: {usage})")</li> 705 } 706 </ul> 707 </div> 708 </div> 709 </div> 710 } 711 @if (gridRowUsages > 0) 712 { 713 var rows = Dynamicweb.Content.Services.Grids.GetGridRows().Where(r => themeUsage.GridRowUsages.Contains(r.ID)).ToList(); 714 715 <div class="accordion-item"> 716 <h2 class="accordion-header" id="headingRows"> 717 <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseRows" aria-expanded="false" aria-controls="collapseRows"> 718 <span class="pe-2">Rows</span><span class="badge rounded-pill bg-secondary text-light">@gridRowUsages</span> 719 </button> 720 </h2> 721 <div id="collapseRows" class="accordion-collapse collapse" aria-labelledby="headingRows" data-bs-parent="#accordionWrapper"> 722 <div class="accordion-body"> 723 <ul> 724 @foreach (var usage in themeUsage.GridRowUsages) 725 { 726 var row = rows.FirstOrDefault(r => r.ID == usage); 727 var page = Dynamicweb.Content.Services.Pages.GetPage(row.PageId); 728 <li>Page: <span class="fw-bold">@(page.GetDisplayName())</span>@($"( ID: {page.ID}) - Row: ")<span class="fw-bold">@(row.DefinitionId)</span>@($" (ID: {usage})")</li> 729 } 730 </ul> 731 </div> 732 </div> 733 </div> 734 } 735 @if (paragraphUsages > 0) 736 { 737 var paragraphs = Dynamicweb.Content.Services.Paragraphs.GetParagraphs().Where(p => themeUsage.ParagraphUsages.Contains(p.ID)).ToList(); 738 739 <div class="accordion-item"> 740 <h2 class="accordion-header" id="headingParagraphs"> 741 <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseParagraphs" aria-expanded="false" aria-controls="collapseParagraphs"> 742 <span class="pe-2">Paragraphs</span><span class="badge rounded-pill bg-secondary text-light">@paragraphUsages</span> 743 </button> 744 </h2> 745 <div id="collapseParagraphs" class="accordion-collapse collapse" aria-labelledby="headingParagraphs" data-bs-parent="#accordionWrapper"> 746 <div class="accordion-body"> 747 <ul> 748 @foreach (var usage in themeUsage.ParagraphUsages) 749 { 750 var paragraph = paragraphs.FirstOrDefault(p => p.ID == usage); 751 var page = Dynamicweb.Content.Services.Pages.GetPage(paragraph.PageID); 752 <li>Page: <span class="fw-bold">@(page.GetDisplayName())</span>@($"( ID: {page.ID}) - Paragraph: ")<span class="fw-bold">@paragraph.Header</span>@($" (ID: {usage})")</li> 753 } 754 </ul> 755 </div> 756 </div> 757 </div> 758 } 759 </div> 760 </div> 761 </div> 762 </div> 763 </div> 764 } 765 </div> 766 } 767 } 768 </div> 769 </div> 770 } 771 <div class="g-col-12"> 772 <hr /> 773 </div> 774
Error executing template "Designs/Swift/Paragraph/Swift_Theme.cshtml" System.Data.SqlClient.SqlException (0x80131904): STRING_AGG aggregation result exceeded the limit of 8000 bytes. Use LOB types to avoid result truncation. at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction) at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose) at System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady) at System.Data.SqlClient.SqlDataReader.TryConsumeMetaData() at System.Data.SqlClient.SqlDataReader.get_MetaData() at System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString, Boolean isInternal, Boolean forDescribeParameterEncryption, Boolean shouldCacheForAlwaysEncrypted) at System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async, Int32 timeout, Task& task, Boolean asyncWrite, Boolean inRetry, SqlDataReader ds, Boolean describeParameterEncryptionRequest) at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, TaskCompletionSource`1 completion, Int32 timeout, Task& task, Boolean& usedCache, Boolean asyncWrite, Boolean inRetry) at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method) at System.Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior behavior, String method) at Dynamicweb.Data.Database.CreateDataReader(IDbCommand command, CommandBehavior behavior) at Dynamicweb.Data.Database.CreateDataReader(String sql, IDbConnection connection, IDbTransaction transaction, CommandBehavior behavior, Int32 commandTimeout, Dictionary`2 sqlParams) at Dynamicweb.Data.Database.CreateDataReader(String sql, IDbConnection connection, IDbTransaction transaction, Int32 commandTimeout, Dictionary`2 sqlParams) at Dynamicweb.Data.Database.CreateDataReader(String sql) at CompiledRazorTemplates.Dynamic.RazorEngine_8e3f1b11eb0041ceb2ca487c2be837e6.UpdateThemeUsages(String sqlQuery, List`1 themeUsages) in E:\Dynamicweb.net\Solutions\Dynamicweb\dw2022.cloud.dynamicweb-cms.com\Files\Templates\Designs\Swift\Paragraph\Swift_Theme.cshtml:line 202 at CompiledRazorTemplates.Dynamic.RazorEngine_8e3f1b11eb0041ceb2ca487c2be837e6.GetAllThemeUsages() in E:\Dynamicweb.net\Solutions\Dynamicweb\dw2022.cloud.dynamicweb-cms.com\Files\Templates\Designs\Swift\Paragraph\Swift_Theme.cshtml:line 184 at CompiledRazorTemplates.Dynamic.RazorEngine_8e3f1b11eb0041ceb2ca487c2be837e6.GetThemeUsageById(String themeId) in E:\Dynamicweb.net\Solutions\Dynamicweb\dw2022.cloud.dynamicweb-cms.com\Files\Templates\Designs\Swift\Paragraph\Swift_Theme.cshtml:line 238 at CompiledRazorTemplates.Dynamic.RazorEngine_8e3f1b11eb0041ceb2ca487c2be837e6.Execute() in E:\Dynamicweb.net\Solutions\Dynamicweb\dw2022.cloud.dynamicweb-cms.com\Files\Templates\Designs\Swift\Paragraph\Swift_Theme.cshtml:line 617 at RazorEngine.Templating.TemplateBase.RazorEngine.Templating.ITemplate.Run(ExecuteContext context, TextWriter reader) at RazorEngine.Templating.RazorEngineService.RunCompile(ITemplateKey key, TextWriter writer, Type modelType, Object model, DynamicViewBag viewBag) at RazorEngine.Templating.RazorEngineServiceExtensions.<>c__DisplayClass16_0.<RunCompile>b__0(TextWriter writer) at RazorEngine.Templating.RazorEngineServiceExtensions.WithWriter(Action`1 withWriter) at Dynamicweb.Rendering.RazorTemplateRenderingProvider.Render(Template template) at Dynamicweb.Rendering.TemplateRenderingService.Render(Template template) at Dynamicweb.Rendering.Template.RenderRazorTemplate() ClientConnectionId:b42d1cec-597c-4eed-bdc2-e0762a41101a Error Number:9829,State:1,Class:16
1 @inherits Dynamicweb.Rendering.ViewModelTemplate<Dynamicweb.Frontend.ParagraphViewModel> 2 @using System.Globalization 3 @using System.Drawing 4 @using Dynamicweb.Core 5 6 @functions{ 7 // Get Hex Color from color picker and translate to RGB color 8 public static string HexToRGB(string hexString) 9 { 10 if (hexString.Equals("none") || string.IsNullOrEmpty(hexString)) 11 return hexString; 12 13 //replace # occurences 14 if (hexString.IndexOf('#') != -1) 15 hexString = hexString.Replace("#", ""); 16 try 17 { 18 int r, g, b = 0; 19 r = int.Parse(hexString.Substring(0, 2), NumberStyles.AllowHexSpecifier); 20 g = int.Parse(hexString.Substring(2, 2), NumberStyles.AllowHexSpecifier); 21 b = int.Parse(hexString.Substring(4, 2), NumberStyles.AllowHexSpecifier); 22 23 string rgb = r + "," + g + "," + b; 24 return rgb; 25 } 26 catch (System.Exception) 27 { 28 return hexString; 29 } 30 } 31 32 public static string GetColorSquare(string hex) 33 { 34 return $"<div class=\"swift-checkered d-inline-block me-1\" style=\"height:1.25rem;width:1.25rem;\"><div style=\"background-color: {hex};border:.0625rem solid grey\" class=\"w-100 h-100\"></div></div>"; 35 } 36 37 public class HSL 38 { 39 public double h { get; set; } 40 public double s { get; set; } 41 public double l { get; set; } 42 } 43 44 //Convert HEX to HSL 45 public static HSL HexToHsl(string hexString) 46 { 47 System.Drawing.Color color = System.Drawing.ColorTranslator.FromHtml(hexString); 48 49 float _R = (color.R / 255f); 50 float _G = (color.G / 255f); 51 float _B = (color.B / 255f); 52 53 float _Min = Math.Min(Math.Min(_R, _G), _B); 54 float _Max = Math.Max(Math.Max(_R, _G), _B); 55 float _Delta = _Max - _Min; 56 57 float S = 0; 58 float L = (float)((_Max + _Min) / 2.0f); 59 60 if (_Delta != 0) 61 { 62 if (L < 0.5f) 63 { 64 S = (float)(_Delta / (_Max + _Min)); 65 } 66 else 67 { 68 S = (float)(_Delta / (2.0f - _Max - _Min)); 69 } 70 } 71 72 HSL hsl = new HSL(); 73 hsl.h = Math.Round(color.GetHue(), 2); 74 hsl.s = Math.Round(S, 2) * 100; 75 hsl.l = Math.Round(L, 2) * 100; 76 77 return hsl; 78 } 79 80 //Find contrast color (white, black) 81 public static Color GetContrastColor(string hexString) 82 { 83 System.Drawing.Color bg = System.Drawing.ColorTranslator.FromHtml(hexString); 84 85 int nThreshold = 105; 86 int bgDelta = Convert.ToInt32((bg.R * 0.299) + (bg.G * 0.587) + 87 (bg.B * 0.114)); 88 89 Color foreColor = (255 - bgDelta < nThreshold) ? Color.Black : Color.White; 90 return foreColor; 91 } 92 93 public string GetColorVariation(string hexString) 94 { 95 var contrast = GetContrastColor(hexString); 96 HSL currentHslColor = HexToHsl(hexString); 97 HSL variantHslColor = currentHslColor; 98 99 if (contrast == Color.Black) 100 { 101 variantHslColor.l = 85; //The background is dark - Color should be light 102 } 103 else 104 { 105 variantHslColor.l = 40; //The background is light - Color should be less light 106 } 107 108 //Color is very light 109 if (currentHslColor.l > 85) 110 { 111 variantHslColor.l = 95; 112 } 113 114 string colorString = variantHslColor.h + ", " + variantHslColor.s + "%, " + variantHslColor.l + "%"; 115 return colorString; 116 } 117 118 private class ThemeDatabaseUsage 119 { 120 public string TableName { get; set; } 121 public string ColumnName { get; set; } 122 } 123 124 private class ThemeUsage 125 { 126 public string Id { get; set; } 127 public List<int> WebsiteUsages { get; set; } = new List<int>(); 128 public List<int> PageUsages { get; set; } = new List<int>(); 129 public List<int> PagePropertyUsages { get; set; } = new List<int>(); 130 public List<int> GridRowUsages { get; set; } = new List<int>(); 131 public List<int> ParagraphUsages { get; set; } = new List<int>(); 132 public int AllUsages { get; set; } = 0; 133 } 134 135 private List<ThemeDatabaseUsage> GetThemeColumnsFromSchema() 136 { 137 string cacheKey = "ThemesFromDatabase"; 138 if (Dynamicweb.Context.Current.Items.Contains(cacheKey)) 139 { 140 return (List<ThemeDatabaseUsage>)Dynamicweb.Context.Current.Items[cacheKey]; 141 } 142 var schema = Dynamicweb.Data.Database.CreateDataReader("SELECT table_name, column_name FROM information_schema.columns WHERE column_name LIKE '%Theme%'"); 143 144 var rawData = new List<ThemeDatabaseUsage>(); 145 while (schema.Read()) { 146 rawData.Add(new ThemeDatabaseUsage {TableName = schema["table_name"].ToString(), ColumnName = schema["column_name"].ToString() }); 147 } 148 Dynamicweb.Context.Current.Items[cacheKey] = rawData; 149 return rawData; 150 } 151 152 private List<ThemeUsage> GetAllThemeUsages() 153 { 154 string cacheKey = "ThemeUsages"; 155 if (Dynamicweb.Context.Current.Items.Contains(cacheKey)) 156 { 157 return (List<ThemeUsage>)Dynamicweb.Context.Current.Items[cacheKey]; 158 } 159 160 var rawData = GetThemeColumnsFromSchema(); 161 var themeUsages = new List<ThemeUsage>(); 162 163 var sqlQuery = ""; 164 foreach (var row in rawData) 165 { 166 if (!string.IsNullOrEmpty(sqlQuery)) { sqlQuery += " UNION ALL "; } 167 sqlQuery += $"SELECT '{row.TableName}' AS TableName, '{row.ColumnName}' AS ColumnName, {row.ColumnName} AS ColumnValue, Id, AreaId, Page.PageId, PageProperties.PageId as 'PagePropertiesId', GridRowId, ParagraphId" + 168 $" FROM [{row.TableName}]" + 169 $" LEFT JOIN Area ON AreaItemType = '{row.TableName.Replace("ItemType_","")}' AND AreaItemId = Id" + 170 $" LEFT JOIN Page ON PageItemType = '{row.TableName.Replace("ItemType_","")}' AND PageItemId = Id" + 171 $" LEFT JOIN Page as PageProperties ON AreaItemTypePageProperty = '{row.TableName.Replace("ItemType_","")}' AND PageProperties.PagePropertyItemId = Id" + 172 $" LEFT JOIN GridRow ON GridRowItemType = '{row.TableName.Replace("ItemType_","")}' AND GridRowItemId = Id" + 173 $" LEFT JOIN Paragraph ON ParagraphItemType = '{row.TableName.Replace("ItemType_","")}' AND ParagraphItemId = Id" + 174 $" WHERE {row.ColumnName} != '' AND {row.ColumnName} IS NOT NULL" + 175 $" AND (AreaId IS NULL OR AreaId = {Pageview.AreaID})" + 176 $" AND (Page.PageId IS NULL OR Page.PageAreaId = {Pageview.AreaID})" + 177 $" AND (PageProperties.PageId IS NULL OR PageProperties.PageAreaId = {Pageview.AreaID})" + 178 $" AND (GridRowId IS NULL OR GridRowPageId IN (SELECT value From string_split(@pageIds, ',')))" + 179 $" AND (ParagraphId IS NULL OR ParagraphPageId IN (SELECT value From string_split(@pageIds, ',')))"; 180 181 var maxMsSqlServerCharLimit = 60000; 182 if (sqlQuery.Length > maxMsSqlServerCharLimit) 183 { 184 UpdateThemeUsages(sqlQuery, themeUsages); 185 sqlQuery = ""; 186 } 187 } 188 189 if (!string.IsNullOrEmpty(sqlQuery)) 190 { 191 UpdateThemeUsages(sqlQuery, themeUsages); 192 } 193 UpdateAllUsages(themeUsages); 194 195 Dynamicweb.Context.Current.Items[cacheKey] = themeUsages; 196 return themeUsages; 197 } 198 199 private void UpdateThemeUsages(string sqlQuery, List<ThemeUsage> themeUsages) 200 { 201 sqlQuery = $"DECLARE @pageIds NVARCHAR(max) = (SELECT STRING_AGG(PageId,',') FROM Page WHERE PageAreaId = {Pageview.AreaID}) " + sqlQuery; 202 var rawData = Dynamicweb.Data.Database.CreateDataReader(sqlQuery); 203 while (rawData.Read()) 204 { 205 var themeId = rawData["ColumnValue"].ToString(); 206 var themeUsageExists = themeUsages.FirstOrDefault(t => t.Id == themeId) != null; 207 if (!themeUsageExists) 208 { 209 themeUsages.Add(new ThemeUsage { Id = themeId }); 210 } 211 212 var themeUsage = themeUsages.FirstOrDefault(t => t.Id == themeId); 213 if (themeUsage == null) continue; 214 215 if (Converter.ToInt32(rawData["AreaId"].ToString()) > 0) { themeUsage.WebsiteUsages.Add(Converter.ToInt32(rawData["AreaId"].ToString())); } 216 if (Converter.ToInt32(rawData["PageId"].ToString()) > 0) { themeUsage.PageUsages.Add(Converter.ToInt32(rawData["PageId"].ToString())); } 217 if (Converter.ToInt32(rawData["PagePropertiesId"].ToString()) > 0) { themeUsage.PagePropertyUsages.Add(Converter.ToInt32(rawData["PagePropertiesId"].ToString())); } 218 if (Converter.ToInt32(rawData["GridRowId"].ToString()) > 0) { themeUsage.GridRowUsages.Add(Converter.ToInt32(rawData["GridRowId"].ToString())); } 219 if (Converter.ToInt32(rawData["ParagraphId"].ToString()) > 0) { themeUsage.ParagraphUsages.Add(Converter.ToInt32(rawData["ParagraphId"].ToString())); } 220 } 221 } 222 223 private void UpdateAllUsages(List<ThemeUsage> themeUsages) 224 { 225 foreach (var themeUsage in themeUsages) 226 { 227 int websiteUsages = themeUsage?.WebsiteUsages.Count ?? 0; 228 int pageUsages = themeUsage?.PageUsages.Count ?? 0; 229 int pagePropertyUsages = themeUsage?.PagePropertyUsages.Count ?? 0; 230 int gridRowUsages = themeUsage?.GridRowUsages.Count ?? 0; 231 int paragraphUsages = themeUsage?.ParagraphUsages.Count ?? 0; 232 themeUsage.AllUsages = websiteUsages + pageUsages + pagePropertyUsages + gridRowUsages + paragraphUsages; 233 } 234 } 235 236 private ThemeUsage GetThemeUsageById(string themeId) 237 { 238 var themeUsages = GetAllThemeUsages(); 239 return themeUsages.FirstOrDefault(t => t.Id == themeId); 240 } 241 242 } 243 244 @{ 245 string themeName = !string.IsNullOrWhiteSpace(Model.Item.GetString("Name")) ? Model.Item.GetString("Name") : "Default"; 246 string themeClassName = !string.IsNullOrWhiteSpace(Model.Item.GetString("CSSClassName")) ? Model.Item.GetString("CSSClassName").Replace(" ", "").Trim().ToLower() : ""; 247 248 //Theme colors 249 string foregroundColor = Model.Item.GetString("ForegroundColor", "currentColor"); 250 string backgroundColor = Model.Item.GetString("BackgroundColor", "transparent"); 251 string accentColor = Model.Item.GetString("accentColor", "currentColor"); 252 string borderColor = Model.Item.GetString("BorderColor", "transparent"); 253 254 //Primary button 255 string buttonPrimaryForegroundColor = Model.Item.GetString("ButtonPrimaryForegroundColor", "currentColor"); 256 string buttonPrimaryBackgroundColor = Model.Item.GetString("ButtonPrimaryBackgroundColor", "transparent"); 257 string buttonPrimaryBorderColor = Model.Item.GetString("ButtonPrimaryBorderColor", "transparent"); 258 259 string buttonPrimaryHoverBackgroundColorAuto = "transparent"; 260 if (buttonPrimaryBackgroundColor != "transparent") 261 { 262 buttonPrimaryHoverBackgroundColorAuto = "hsl(" + GetColorVariation(buttonPrimaryBackgroundColor) + ")"; 263 } 264 string buttonPrimaryHoverForegroundColor = Model.Item.GetString("ButtonPrimaryHoverForegroundColor", buttonPrimaryForegroundColor); 265 string buttonPrimaryHoverBackgroundColor = Model.Item.GetString("ButtonPrimaryHoverBackgroundColor", buttonPrimaryHoverBackgroundColorAuto); 266 string buttonPrimaryHoverBorderColor = Model.Item.GetString("ButtonPrimaryHoverBorderColor", buttonPrimaryBorderColor); 267 268 //Secondary buton 269 string buttonSecondaryForegroundColor = Model.Item.GetString("ButtonSecondaryForegroundColor", "currentColor"); 270 string buttonSecondaryBackgroundColor = Model.Item.GetString("ButtonSecondaryBackgroundColor", "transparent"); 271 string buttonSecondaryBorderColor = Model.Item.GetString("ButtonSecondaryBorderColor", "transparent"); 272 273 string buttonSecondaryHoverBackgroundColorAuto = "transparent"; 274 if (buttonSecondaryBackgroundColor != "transparent") 275 { 276 buttonSecondaryHoverBackgroundColorAuto = "hsl(" + GetColorVariation(buttonSecondaryBackgroundColor) + ")"; 277 } 278 string buttonSecondaryHoverForegroundColor = Model.Item.GetString("ButtonSecondaryHoverForegroundColor", buttonSecondaryForegroundColor); 279 string buttonSecondaryHoverBackgroundColor = Model.Item.GetString("ButtonSecondaryHoverBackgroundColor", buttonSecondaryHoverBackgroundColorAuto); 280 string buttonSecondaryHoverBorderColor = Model.Item.GetString("ButtonSecondaryHoverBorderColor", buttonSecondaryBorderColor); 281 282 //Link buton 283 string buttonLinkColor = Model.Item.GetString("ButtonLinkColor", "currentColor"); 284 string buttonLinkHoverColorAuto = "currentColor"; 285 if (buttonLinkColor != "currentColor") 286 { 287 buttonLinkHoverColorAuto = "hsl(" + GetColorVariation(buttonLinkColor) + ")"; 288 } 289 string buttonLinkHoverColor = Model.Item.GetString("ButtonLinkHoverColor", buttonLinkHoverColorAuto); 290 291 string accessibilityOutlineColor = Model.Item.GetString("OutlineColor") != null ? Model.Item.GetString("OutlineColor") : ""; 292 293 if (!string.IsNullOrEmpty(themeClassName)) 294 { 295 var sb = new System.Text.StringBuilder(); 296 297 sb.AppendLine("." + themeClassName + "{"); 298 if (!string.IsNullOrEmpty(foregroundColor)) 299 { 300 sb.AppendLine($"--swift-foreground-color: {foregroundColor};"); 301 sb.AppendLine($"--swift-foreground-color-rgb: {HexToRGB(foregroundColor)};"); 302 } 303 if (!string.IsNullOrEmpty(backgroundColor)) 304 { 305 sb.AppendLine($"--swift-background-color: {backgroundColor};"); 306 sb.AppendLine($"--swift-background-color-rgb: {HexToRGB(backgroundColor)};"); 307 } 308 if (!string.IsNullOrEmpty(accentColor)) 309 { 310 sb.AppendLine($"--swift-accent-color: {accentColor};"); 311 sb.AppendLine($"--swift-accent-color-rgb: {HexToRGB(accentColor)};"); 312 } 313 if (!string.IsNullOrEmpty(borderColor)) 314 { 315 sb.AppendLine($"--swift-border-color: {borderColor};"); 316 sb.AppendLine($"--swift-border-color-rgb: {HexToRGB(borderColor)};"); 317 } 318 319 if (!string.IsNullOrEmpty(buttonPrimaryBackgroundColor)) 320 { 321 sb.AppendLine($"--swift-button-primary-background-color: {buttonPrimaryBackgroundColor};"); 322 sb.AppendLine($"--swift-button-primary-background-color-rgb: {HexToRGB(buttonPrimaryBackgroundColor)};"); 323 } 324 if (!string.IsNullOrEmpty(buttonPrimaryForegroundColor)) 325 { 326 sb.AppendLine($"--swift-button-primary-foreground-color: {buttonPrimaryForegroundColor};"); 327 sb.AppendLine($"--swift-button-primary-foreground-color-rgb: {HexToRGB(buttonPrimaryForegroundColor)};"); 328 } 329 if (!string.IsNullOrEmpty(buttonPrimaryBorderColor)) 330 { 331 sb.AppendLine($"--swift-button-primary-border-color: {buttonPrimaryBorderColor};"); 332 sb.AppendLine($"--swift-button-primary-border-color-rgb: {HexToRGB(buttonPrimaryBorderColor)};"); 333 } 334 335 if (!string.IsNullOrEmpty(buttonPrimaryHoverBackgroundColor)) 336 { 337 sb.AppendLine($"--swift-button-primary-hover-background-color: {buttonPrimaryHoverBackgroundColor};"); 338 sb.AppendLine($"--swift-button-primary-hover-background-color-rgb: {HexToRGB(buttonPrimaryHoverBackgroundColor)};"); 339 } 340 if (!string.IsNullOrEmpty(buttonPrimaryHoverForegroundColor)) 341 { 342 sb.AppendLine($"--swift-button-primary-hover-foreground-color: {buttonPrimaryHoverForegroundColor};"); 343 sb.AppendLine($"--swift-button-primary-hover-foreground-color-rgb: {HexToRGB(buttonPrimaryHoverForegroundColor)};"); 344 } 345 if (!string.IsNullOrEmpty(buttonPrimaryHoverBorderColor)) 346 { 347 sb.AppendLine($"--swift-button-primary-hover-border-color: {buttonPrimaryHoverBorderColor};"); 348 sb.AppendLine($"--swift-button-primary-hover-border-color-rgb: {HexToRGB(buttonPrimaryHoverBorderColor)};"); 349 } 350 351 if (!string.IsNullOrEmpty(buttonSecondaryBackgroundColor)) 352 { 353 sb.AppendLine($"--swift-button-secondary-background-color: {buttonSecondaryBackgroundColor};"); 354 sb.AppendLine($"--swift-button-secondary-background-color-rgb: {HexToRGB(buttonSecondaryBackgroundColor)};"); 355 } 356 if (!string.IsNullOrEmpty(buttonSecondaryForegroundColor)) 357 { 358 sb.AppendLine($"--swift-button-secondary-foreground-color: {buttonSecondaryForegroundColor};"); 359 sb.AppendLine($"--swift-button-secondary-foreground-color-rgb: {HexToRGB(buttonSecondaryForegroundColor)};"); 360 } 361 if (!string.IsNullOrEmpty(buttonSecondaryBorderColor)) 362 { 363 sb.AppendLine($"--swift-button-secondary-border-color: {buttonSecondaryBorderColor};"); 364 sb.AppendLine($"--swift-button-secondary-border-color-rgb: {HexToRGB(buttonSecondaryBorderColor)};"); 365 } 366 if (!string.IsNullOrEmpty(buttonSecondaryHoverBackgroundColor)) 367 { 368 sb.AppendLine($"--swift-button-secondary-hover-background-color: {buttonSecondaryHoverBackgroundColor};"); 369 sb.AppendLine($"--swift-button-secondary-hover-background-color-rgb: {HexToRGB(buttonSecondaryHoverBackgroundColor)};"); 370 } 371 if (!string.IsNullOrEmpty(buttonSecondaryHoverForegroundColor)) 372 { 373 sb.AppendLine($"--swift-button-secondary-hover-foreground-color: {buttonSecondaryHoverForegroundColor};"); 374 sb.AppendLine($"--swift-button-secondary-hover-foreground-color-rgb: {HexToRGB(buttonSecondaryHoverForegroundColor)};"); 375 } 376 if (!string.IsNullOrEmpty(buttonSecondaryHoverBorderColor)) 377 { 378 sb.AppendLine($"--swift-button-secondary-hover-border-color: {buttonSecondaryHoverBorderColor};"); 379 sb.AppendLine($"--swift-button-secondary-hover-border-color-rgb: {HexToRGB(buttonSecondaryHoverBorderColor)};"); 380 } 381 if (!string.IsNullOrEmpty(buttonLinkColor)) 382 { 383 sb.AppendLine($"--swift-button-link-color: {buttonLinkColor};"); 384 sb.AppendLine($"--swift-button-link-color-rgb: {HexToRGB(buttonLinkColor)};"); 385 } 386 if (!string.IsNullOrEmpty(buttonLinkHoverColor)) 387 { 388 sb.AppendLine($"--swift-button-link-hover-color: {buttonLinkHoverColor};"); 389 sb.AppendLine($"--swift-button-link-hover-color-rgb: {HexToRGB(buttonLinkHoverColor)};"); 390 } 391 if (!string.IsNullOrEmpty(accessibilityOutlineColor)) 392 { 393 sb.AppendLine($"--swift-a11y-outline-color: {accessibilityOutlineColor};"); 394 sb.AppendLine($"--swift-a11y-outline-color-rgb: {HexToRGB(accessibilityOutlineColor)};"); 395 } 396 sb.AppendLine("}"); 397 398 Dynamicweb.Core.Helpers.TextFileHelper.WriteTextFile(sb.ToString() + Environment.NewLine, Dynamicweb.Context.Current.Server.MapPath($"/Files/Templates/Designs/Swift/_parsed/Swift_css/Swift_theme_styles_{Dynamicweb.Content.Services.Pages.GetPage(Model.PageID).AreaId}.tmp"), true); 399 } 400 } 401 402 @if (themeClassName != "") 403 { 404 string iconPath = "/Files/Templates/Designs/Swift/Assets/icons/"; 405 406 <div class="g-col-12 g-col-lg-4"> 407 <div class="swift-checkered p-3"> 408 <div class="theme-option theme @themeClassName p-lg-3"> 409 <div class="mb-2 pb-1 border-bottom d-flex align-items-center"> 410 <span class="icon-3 me-2"> 411 @ReadFile(iconPath + "sun.svg") 412 </span> 413 <h4 class="m-0 p-0">@themeName</h4> 414 </div> 415 <div class="d-flex flex-column gap-1 mb-2"> 416 <p class="mb-0">This is the body text of the theme.</p> 417 <p class="mb-0" style="color: var(--swift-accent-color)">This is the accent color of the theme.</p> 418 </div> 419 <div> 420 <button class="btn btn-primary me-1">Primary</button> 421 <button class="btn btn-secondary">Secondary</button> 422 <button class="btn btn-link">Link</button> 423 </div> 424 </div> 425 </div> 426 </div> 427 <div class="g-col-12 g-col-lg-8 mb-4 mb-lg-0"> 428 <div class="grid fs-7"> 429 <div class="g-col-12 g-col-lg-3"> 430 <table class="table table-borderless table-sm w-100"> 431 <thead> 432 <tr> 433 <th colspan="2" class="fw-bold">@Translate("Base")</th> 434 </tr> 435 </thead> 436 <tr> 437 <td>@Translate("Foreground")</td> 438 <td>@GetColorSquare(foregroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@foregroundColor');">@foregroundColor</a></td> 439 </tr> 440 <tr> 441 <td>@Translate("Background")</td> 442 <td>@GetColorSquare(backgroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@backgroundColor');">@backgroundColor</a></td> 443 </tr> 444 <tr> 445 <td>@Translate("Accent")</td> 446 <td>@GetColorSquare(accentColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@accentColor');">@accentColor</a></td> 447 </tr> 448 <tr> 449 <td>@Translate("Border")</td> 450 <td>@GetColorSquare(borderColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@borderColor');">@borderColor</a></td> 451 </tr> 452 </table> 453 </div> 454 <div class="g-col-12 g-col-lg-3"> 455 <table class="table table-borderless table-sm w-100"> 456 <thead> 457 <tr> 458 <th colspan="2" class="fw-bold">@Translate("Primary button")</th> 459 </tr> 460 </thead> 461 <tr> 462 <td>@Translate("Foreground")</td> 463 <td>@GetColorSquare(buttonPrimaryForegroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonPrimaryForegroundColor');">@buttonPrimaryForegroundColor</a></td> 464 </tr> 465 <tr> 466 <td>@Translate("Background")</td> 467 <td>@GetColorSquare(buttonPrimaryBackgroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonPrimaryBackgroundColor');">@buttonPrimaryBackgroundColor</a></td> 468 </tr> 469 @if (!string.IsNullOrEmpty(buttonPrimaryBorderColor)) 470 { 471 <tr> 472 <td>@Translate("Border")</td> 473 <td>@GetColorSquare(buttonPrimaryBorderColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonPrimaryBorderColor');">@buttonPrimaryBorderColor</a></td> 474 </tr> 475 } 476 <thead> 477 <tr> 478 <th colspan="2" class="fw-bold">@Translate("Primary button hover")</th> 479 </tr> 480 </thead> 481 @if (!string.IsNullOrEmpty(buttonPrimaryHoverForegroundColor)) 482 { 483 <tr> 484 <td>@Translate("Foreground")</td> 485 <td>@GetColorSquare(buttonPrimaryHoverForegroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonPrimaryHoverForegroundColor');">@buttonPrimaryHoverForegroundColor</a></td> 486 </tr> 487 } 488 @if (!string.IsNullOrEmpty(buttonPrimaryHoverBackgroundColor)) 489 { 490 <tr> 491 <td>@Translate("Background")</td> 492 <td>@GetColorSquare(buttonPrimaryHoverBackgroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonPrimaryHoverBackgroundColor');">@buttonPrimaryHoverBackgroundColor</a></td> 493 </tr> 494 } 495 @if (!string.IsNullOrEmpty(buttonPrimaryHoverBorderColor)) 496 { 497 <tr> 498 <td>@Translate("Border")</td> 499 <td>@GetColorSquare(buttonPrimaryHoverBorderColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonPrimaryHoverBorderColor');">@buttonPrimaryHoverBorderColor</a></td> 500 </tr> 501 } 502 </table> 503 </div> 504 <div class="g-col-12 g-col-lg-3"> 505 <table class="table table-borderless table-sm w-100"> 506 <thead> 507 <tr> 508 <th colspan="2" class="fw-bold">@Translate("Secondary button")</th> 509 </tr> 510 </thead> 511 <tr> 512 <td>@Translate("Foreground")</td> 513 <td>@GetColorSquare(buttonSecondaryForegroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonSecondaryForegroundColor');">@buttonSecondaryForegroundColor</a></td> 514 </tr> 515 <tr> 516 <td>@Translate("Background")</td> 517 <td>@GetColorSquare(buttonSecondaryBackgroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonSecondaryBackgroundColor');">@buttonSecondaryBackgroundColor</a></td> 518 </tr> 519 @if (!string.IsNullOrEmpty(buttonSecondaryBorderColor)) 520 { 521 <tr> 522 <td>@Translate("Border")</td> 523 <td>@GetColorSquare(buttonSecondaryBorderColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonSecondaryBorderColor');">@buttonSecondaryBorderColor</a></td> 524 </tr> 525 } 526 <thead> 527 <tr> 528 <th colspan="2" class="fw-bold">@Translate("Secondary button hover")</th> 529 </tr> 530 </thead> 531 @if (!string.IsNullOrEmpty(buttonSecondaryHoverForegroundColor)) 532 { 533 <tr> 534 <td>@Translate("Foreground")</td> 535 <td>@GetColorSquare(buttonSecondaryHoverForegroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonSecondaryHoverForegroundColor');">@buttonSecondaryHoverForegroundColor</a></td> 536 </tr> 537 } 538 @if (!string.IsNullOrEmpty(buttonSecondaryHoverBackgroundColor)) 539 { 540 <tr> 541 <td>@Translate("Background")</td> 542 <td>@GetColorSquare(buttonSecondaryHoverBackgroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonSecondaryHoverBackgroundColor');">@buttonSecondaryHoverBackgroundColor</a></td> 543 </tr> 544 } 545 @if (!string.IsNullOrEmpty(buttonSecondaryHoverBorderColor)) 546 { 547 <tr> 548 <td>@Translate("Border")</td> 549 <td>@GetColorSquare(buttonSecondaryHoverBorderColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonSecondaryHoverBorderColor');">@buttonSecondaryHoverBorderColor</a></td> 550 </tr> 551 } 552 @if (!string.IsNullOrEmpty(accessibilityOutlineColor)) 553 { 554 <tr> 555 <td>@Translate("Focus outline")</td> 556 <td>@GetColorSquare(accessibilityOutlineColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@accessibilityOutlineColor');">@accessibilityOutlineColor</a></td> 557 </tr> 558 } 559 </table> 560 </div> 561 <div class="g-col-12 g-col-lg-3"> 562 <table class="table table-borderless table-sm w-100"> 563 <thead> 564 <tr> 565 <th colspan="2" class="fw-bold">@Translate("Link button")</th> 566 </tr> 567 </thead> 568 <tr> 569 <td>@Translate("Link color")</td> 570 <td>@GetColorSquare(buttonLinkColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonLinkColor');">@buttonLinkColor</a></td> 571 </tr> 572 <thead> 573 <tr> 574 <th colspan="2" class="fw-bold">@Translate("Link button hover")</th> 575 </tr> 576 </thead> 577 @if (!string.IsNullOrEmpty(buttonLinkHoverColor)) 578 { 579 <tr> 580 <td>@Translate("Link hover color")</td> 581 <td>@GetColorSquare(buttonLinkHoverColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonLinkHoverColor');">@buttonLinkHoverColor</a></td> 582 </tr> 583 } 584 585 @if (!string.IsNullOrEmpty(accessibilityOutlineColor)) 586 { 587 <tr> 588 <td>@Translate("Focus outline")</td> 589 <td>@GetColorSquare(accessibilityOutlineColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@accessibilityOutlineColor');">@accessibilityOutlineColor</a></td> 590 </tr> 591 } 592 </table> 593 </div> 594 <div class="g-col-12 g-col-lg-3"> 595 <table class="table table-borderless table-sm w-100"> 596 <tr> 597 <td class="fw-bold">@Translate("Implementation")</td> 598 </tr> 599 <tr> 600 <td> 601 @{ 602 string implementation = $"<div class=\"theme {themeClassName}\"></div>"; 603 } 604 <div class="text-muted"> 605 <code class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@themeClassName');"> 606 @Dynamicweb.Core.Encoders.HtmlEncoder.HtmlEncode(implementation) 607 </code> 608 </div> 609 </td> 610 </tr> 611 </table> 612 </div> 613 @{ 614 bool hasUsageData = Converter.ToBoolean(Dynamicweb.Context.Current.Request["auditUsages"]); 615 if (hasUsageData) 616 { 617 var themeUsage = GetThemeUsageById(themeClassName); 618 int allUsages = themeUsage?.AllUsages ?? 0; 619 string buttonAttributes = allUsages > 0 ? $"data-bs-toggle=\"modal\" data-bs-target=\"#themeUsage_{Model.ID}\"" : string.Empty; 620 string badgeStyle = allUsages > 0 ? "bg-success" : "bg-danger"; 621 622 <div class="g-col-12 g-col-lg-9 position-relative"> 623 <button type="button" class="btn btn-primary btn-sm position-absolute end-0" @buttonAttributes> 624 Usages 625 <span class="position-absolute top-0 start-100 translate-middle badge rounded-pill text-white @badgeStyle">@allUsages</span> 626 </button> 627 628 @if (allUsages > 0) 629 { 630 int websiteUsages = themeUsage?.WebsiteUsages.Count ?? 0; 631 int pageUsages = themeUsage?.PageUsages.Count ?? 0; 632 int pagePropertyUsages = themeUsage?.PagePropertyUsages.Count ?? 0; 633 int gridRowUsages = themeUsage?.GridRowUsages.Count ?? 0; 634 int paragraphUsages = themeUsage?.ParagraphUsages.Count ?? 0; 635 636 <!-- Modal --> 637 <div class="modal fade" id="themeUsage_@(Model.ID)" tabindex="-1" aria-labelledby="usagesModelLabel" aria-hidden="true"> 638 <div class="modal-dialog modal-xl modal-dialog-centered modal-dialog-scrollable"> 639 <div class="modal-content"> 640 <div class="modal-header"> 641 <h5 class="modal-title" id="usagesModelLabel">@allUsages Usages of '@(themeName)' (@(themeClassName))</h5> 642 <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> 643 </div> 644 <div class="modal-body"> 645 <div class="accordion" id="accordionWrapper"> 646 @if(websiteUsages > 0) 647 { 648 <div class="accordion-item"> 649 <h2 class="accordion-header" id="headingWebsites"> 650 <button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#collapseWebsites" aria-expanded="true" aria-controls="collapseWebsites"> 651 <span class="pe-2">Websites</span><span class="badge rounded-pill bg-secondary text-light">@websiteUsages</span> 652 </button> 653 </h2> 654 <div id="collapseWebsites" class="accordion-collapse collapse show" aria-labelledby="headingWebsites" data-bs-parent="#accordionWrapper"> 655 <div class="accordion-body"> 656 <ul> 657 @foreach (var usage in themeUsage.WebsiteUsages) 658 { 659 var website = Dynamicweb.Content.Services.Areas.GetArea(usage); 660 <li><span class="fw-bold">@website.Name</span>@($" (ID: {usage})")</li> 661 } 662 </ul> 663 </div> 664 </div> 665 </div> 666 } 667 @if (pageUsages > 0) 668 { 669 var pages = Dynamicweb.Content.Services.Pages.GetPages(themeUsage.PageUsages.ToArray()); 670 671 <div class="accordion-item"> 672 <h2 class="accordion-header" id="headingPages"> 673 <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapsePages" aria-expanded="false" aria-controls="collapsePages"> 674 <span class="pe-2">Pages</span><span class="badge rounded-pill bg-secondary text-light">@pageUsages</span> 675 </button> 676 </h2> 677 <div id="collapsePages" class="accordion-collapse collapse" aria-labelledby="headingPages" data-bs-parent="#accordionWrapper"> 678 <div class="accordion-body"> 679 <ul> 680 @foreach (var usage in themeUsage.PageUsages) 681 { 682 <li><span class="fw-bold">@pages.FirstOrDefault(p => p.ID == usage).GetDisplayName()</span>@($" (ID: {usage})")</li> 683 } 684 </ul> 685 </div> 686 </div> 687 </div> 688 } 689 @if (pagePropertyUsages > 0) 690 { 691 var pages = Dynamicweb.Content.Services.Pages.GetPages(themeUsage.PageUsages.ToArray()); 692 693 <div class="accordion-item"> 694 <h2 class="accordion-header" id="headingPageProperties"> 695 <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapsePageProperties" aria-expanded="false" aria-controls="collapsePageProperties"> 696 <span class="pe-2">Page Properties</span><span class="badge rounded-pill bg-secondary text-light">@pagePropertyUsages</span> 697 </button> 698 </h2> 699 <div id="collapsePageProperties" class="accordion-collapse collapse" aria-labelledby="headingPageProperties" data-bs-parent="#accordionWrapper"> 700 <div class="accordion-body"> 701 <ul> 702 @foreach (var usage in themeUsage.PagePropertyUsages) 703 { 704 <li><span class="fw-bold">@pages.FirstOrDefault(p => p.ID == usage).GetDisplayName()</span>@($" (ID: {usage})")</li> 705 } 706 </ul> 707 </div> 708 </div> 709 </div> 710 } 711 @if (gridRowUsages > 0) 712 { 713 var rows = Dynamicweb.Content.Services.Grids.GetGridRows().Where(r => themeUsage.GridRowUsages.Contains(r.ID)).ToList(); 714 715 <div class="accordion-item"> 716 <h2 class="accordion-header" id="headingRows"> 717 <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseRows" aria-expanded="false" aria-controls="collapseRows"> 718 <span class="pe-2">Rows</span><span class="badge rounded-pill bg-secondary text-light">@gridRowUsages</span> 719 </button> 720 </h2> 721 <div id="collapseRows" class="accordion-collapse collapse" aria-labelledby="headingRows" data-bs-parent="#accordionWrapper"> 722 <div class="accordion-body"> 723 <ul> 724 @foreach (var usage in themeUsage.GridRowUsages) 725 { 726 var row = rows.FirstOrDefault(r => r.ID == usage); 727 var page = Dynamicweb.Content.Services.Pages.GetPage(row.PageId); 728 <li>Page: <span class="fw-bold">@(page.GetDisplayName())</span>@($"( ID: {page.ID}) - Row: ")<span class="fw-bold">@(row.DefinitionId)</span>@($" (ID: {usage})")</li> 729 } 730 </ul> 731 </div> 732 </div> 733 </div> 734 } 735 @if (paragraphUsages > 0) 736 { 737 var paragraphs = Dynamicweb.Content.Services.Paragraphs.GetParagraphs().Where(p => themeUsage.ParagraphUsages.Contains(p.ID)).ToList(); 738 739 <div class="accordion-item"> 740 <h2 class="accordion-header" id="headingParagraphs"> 741 <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseParagraphs" aria-expanded="false" aria-controls="collapseParagraphs"> 742 <span class="pe-2">Paragraphs</span><span class="badge rounded-pill bg-secondary text-light">@paragraphUsages</span> 743 </button> 744 </h2> 745 <div id="collapseParagraphs" class="accordion-collapse collapse" aria-labelledby="headingParagraphs" data-bs-parent="#accordionWrapper"> 746 <div class="accordion-body"> 747 <ul> 748 @foreach (var usage in themeUsage.ParagraphUsages) 749 { 750 var paragraph = paragraphs.FirstOrDefault(p => p.ID == usage); 751 var page = Dynamicweb.Content.Services.Pages.GetPage(paragraph.PageID); 752 <li>Page: <span class="fw-bold">@(page.GetDisplayName())</span>@($"( ID: {page.ID}) - Paragraph: ")<span class="fw-bold">@paragraph.Header</span>@($" (ID: {usage})")</li> 753 } 754 </ul> 755 </div> 756 </div> 757 </div> 758 } 759 </div> 760 </div> 761 </div> 762 </div> 763 </div> 764 } 765 </div> 766 } 767 } 768 </div> 769 </div> 770 } 771 <div class="g-col-12"> 772 <hr /> 773 </div> 774
Error executing template "Designs/Swift/Paragraph/Swift_Theme.cshtml" System.Data.SqlClient.SqlException (0x80131904): STRING_AGG aggregation result exceeded the limit of 8000 bytes. Use LOB types to avoid result truncation. at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction) at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose) at System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady) at System.Data.SqlClient.SqlDataReader.TryConsumeMetaData() at System.Data.SqlClient.SqlDataReader.get_MetaData() at System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString, Boolean isInternal, Boolean forDescribeParameterEncryption, Boolean shouldCacheForAlwaysEncrypted) at System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async, Int32 timeout, Task& task, Boolean asyncWrite, Boolean inRetry, SqlDataReader ds, Boolean describeParameterEncryptionRequest) at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, TaskCompletionSource`1 completion, Int32 timeout, Task& task, Boolean& usedCache, Boolean asyncWrite, Boolean inRetry) at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method) at System.Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior behavior, String method) at Dynamicweb.Data.Database.CreateDataReader(IDbCommand command, CommandBehavior behavior) at Dynamicweb.Data.Database.CreateDataReader(String sql, IDbConnection connection, IDbTransaction transaction, CommandBehavior behavior, Int32 commandTimeout, Dictionary`2 sqlParams) at Dynamicweb.Data.Database.CreateDataReader(String sql, IDbConnection connection, IDbTransaction transaction, Int32 commandTimeout, Dictionary`2 sqlParams) at Dynamicweb.Data.Database.CreateDataReader(String sql) at CompiledRazorTemplates.Dynamic.RazorEngine_8e3f1b11eb0041ceb2ca487c2be837e6.UpdateThemeUsages(String sqlQuery, List`1 themeUsages) in E:\Dynamicweb.net\Solutions\Dynamicweb\dw2022.cloud.dynamicweb-cms.com\Files\Templates\Designs\Swift\Paragraph\Swift_Theme.cshtml:line 202 at CompiledRazorTemplates.Dynamic.RazorEngine_8e3f1b11eb0041ceb2ca487c2be837e6.GetAllThemeUsages() in E:\Dynamicweb.net\Solutions\Dynamicweb\dw2022.cloud.dynamicweb-cms.com\Files\Templates\Designs\Swift\Paragraph\Swift_Theme.cshtml:line 184 at CompiledRazorTemplates.Dynamic.RazorEngine_8e3f1b11eb0041ceb2ca487c2be837e6.GetThemeUsageById(String themeId) in E:\Dynamicweb.net\Solutions\Dynamicweb\dw2022.cloud.dynamicweb-cms.com\Files\Templates\Designs\Swift\Paragraph\Swift_Theme.cshtml:line 238 at CompiledRazorTemplates.Dynamic.RazorEngine_8e3f1b11eb0041ceb2ca487c2be837e6.Execute() in E:\Dynamicweb.net\Solutions\Dynamicweb\dw2022.cloud.dynamicweb-cms.com\Files\Templates\Designs\Swift\Paragraph\Swift_Theme.cshtml:line 617 at RazorEngine.Templating.TemplateBase.RazorEngine.Templating.ITemplate.Run(ExecuteContext context, TextWriter reader) at RazorEngine.Templating.RazorEngineService.RunCompile(ITemplateKey key, TextWriter writer, Type modelType, Object model, DynamicViewBag viewBag) at RazorEngine.Templating.RazorEngineServiceExtensions.<>c__DisplayClass16_0.<RunCompile>b__0(TextWriter writer) at RazorEngine.Templating.RazorEngineServiceExtensions.WithWriter(Action`1 withWriter) at Dynamicweb.Rendering.RazorTemplateRenderingProvider.Render(Template template) at Dynamicweb.Rendering.TemplateRenderingService.Render(Template template) at Dynamicweb.Rendering.Template.RenderRazorTemplate() ClientConnectionId:b42d1cec-597c-4eed-bdc2-e0762a41101a Error Number:9829,State:1,Class:16
1 @inherits Dynamicweb.Rendering.ViewModelTemplate<Dynamicweb.Frontend.ParagraphViewModel> 2 @using System.Globalization 3 @using System.Drawing 4 @using Dynamicweb.Core 5 6 @functions{ 7 // Get Hex Color from color picker and translate to RGB color 8 public static string HexToRGB(string hexString) 9 { 10 if (hexString.Equals("none") || string.IsNullOrEmpty(hexString)) 11 return hexString; 12 13 //replace # occurences 14 if (hexString.IndexOf('#') != -1) 15 hexString = hexString.Replace("#", ""); 16 try 17 { 18 int r, g, b = 0; 19 r = int.Parse(hexString.Substring(0, 2), NumberStyles.AllowHexSpecifier); 20 g = int.Parse(hexString.Substring(2, 2), NumberStyles.AllowHexSpecifier); 21 b = int.Parse(hexString.Substring(4, 2), NumberStyles.AllowHexSpecifier); 22 23 string rgb = r + "," + g + "," + b; 24 return rgb; 25 } 26 catch (System.Exception) 27 { 28 return hexString; 29 } 30 } 31 32 public static string GetColorSquare(string hex) 33 { 34 return $"<div class=\"swift-checkered d-inline-block me-1\" style=\"height:1.25rem;width:1.25rem;\"><div style=\"background-color: {hex};border:.0625rem solid grey\" class=\"w-100 h-100\"></div></div>"; 35 } 36 37 public class HSL 38 { 39 public double h { get; set; } 40 public double s { get; set; } 41 public double l { get; set; } 42 } 43 44 //Convert HEX to HSL 45 public static HSL HexToHsl(string hexString) 46 { 47 System.Drawing.Color color = System.Drawing.ColorTranslator.FromHtml(hexString); 48 49 float _R = (color.R / 255f); 50 float _G = (color.G / 255f); 51 float _B = (color.B / 255f); 52 53 float _Min = Math.Min(Math.Min(_R, _G), _B); 54 float _Max = Math.Max(Math.Max(_R, _G), _B); 55 float _Delta = _Max - _Min; 56 57 float S = 0; 58 float L = (float)((_Max + _Min) / 2.0f); 59 60 if (_Delta != 0) 61 { 62 if (L < 0.5f) 63 { 64 S = (float)(_Delta / (_Max + _Min)); 65 } 66 else 67 { 68 S = (float)(_Delta / (2.0f - _Max - _Min)); 69 } 70 } 71 72 HSL hsl = new HSL(); 73 hsl.h = Math.Round(color.GetHue(), 2); 74 hsl.s = Math.Round(S, 2) * 100; 75 hsl.l = Math.Round(L, 2) * 100; 76 77 return hsl; 78 } 79 80 //Find contrast color (white, black) 81 public static Color GetContrastColor(string hexString) 82 { 83 System.Drawing.Color bg = System.Drawing.ColorTranslator.FromHtml(hexString); 84 85 int nThreshold = 105; 86 int bgDelta = Convert.ToInt32((bg.R * 0.299) + (bg.G * 0.587) + 87 (bg.B * 0.114)); 88 89 Color foreColor = (255 - bgDelta < nThreshold) ? Color.Black : Color.White; 90 return foreColor; 91 } 92 93 public string GetColorVariation(string hexString) 94 { 95 var contrast = GetContrastColor(hexString); 96 HSL currentHslColor = HexToHsl(hexString); 97 HSL variantHslColor = currentHslColor; 98 99 if (contrast == Color.Black) 100 { 101 variantHslColor.l = 85; //The background is dark - Color should be light 102 } 103 else 104 { 105 variantHslColor.l = 40; //The background is light - Color should be less light 106 } 107 108 //Color is very light 109 if (currentHslColor.l > 85) 110 { 111 variantHslColor.l = 95; 112 } 113 114 string colorString = variantHslColor.h + ", " + variantHslColor.s + "%, " + variantHslColor.l + "%"; 115 return colorString; 116 } 117 118 private class ThemeDatabaseUsage 119 { 120 public string TableName { get; set; } 121 public string ColumnName { get; set; } 122 } 123 124 private class ThemeUsage 125 { 126 public string Id { get; set; } 127 public List<int> WebsiteUsages { get; set; } = new List<int>(); 128 public List<int> PageUsages { get; set; } = new List<int>(); 129 public List<int> PagePropertyUsages { get; set; } = new List<int>(); 130 public List<int> GridRowUsages { get; set; } = new List<int>(); 131 public List<int> ParagraphUsages { get; set; } = new List<int>(); 132 public int AllUsages { get; set; } = 0; 133 } 134 135 private List<ThemeDatabaseUsage> GetThemeColumnsFromSchema() 136 { 137 string cacheKey = "ThemesFromDatabase"; 138 if (Dynamicweb.Context.Current.Items.Contains(cacheKey)) 139 { 140 return (List<ThemeDatabaseUsage>)Dynamicweb.Context.Current.Items[cacheKey]; 141 } 142 var schema = Dynamicweb.Data.Database.CreateDataReader("SELECT table_name, column_name FROM information_schema.columns WHERE column_name LIKE '%Theme%'"); 143 144 var rawData = new List<ThemeDatabaseUsage>(); 145 while (schema.Read()) { 146 rawData.Add(new ThemeDatabaseUsage {TableName = schema["table_name"].ToString(), ColumnName = schema["column_name"].ToString() }); 147 } 148 Dynamicweb.Context.Current.Items[cacheKey] = rawData; 149 return rawData; 150 } 151 152 private List<ThemeUsage> GetAllThemeUsages() 153 { 154 string cacheKey = "ThemeUsages"; 155 if (Dynamicweb.Context.Current.Items.Contains(cacheKey)) 156 { 157 return (List<ThemeUsage>)Dynamicweb.Context.Current.Items[cacheKey]; 158 } 159 160 var rawData = GetThemeColumnsFromSchema(); 161 var themeUsages = new List<ThemeUsage>(); 162 163 var sqlQuery = ""; 164 foreach (var row in rawData) 165 { 166 if (!string.IsNullOrEmpty(sqlQuery)) { sqlQuery += " UNION ALL "; } 167 sqlQuery += $"SELECT '{row.TableName}' AS TableName, '{row.ColumnName}' AS ColumnName, {row.ColumnName} AS ColumnValue, Id, AreaId, Page.PageId, PageProperties.PageId as 'PagePropertiesId', GridRowId, ParagraphId" + 168 $" FROM [{row.TableName}]" + 169 $" LEFT JOIN Area ON AreaItemType = '{row.TableName.Replace("ItemType_","")}' AND AreaItemId = Id" + 170 $" LEFT JOIN Page ON PageItemType = '{row.TableName.Replace("ItemType_","")}' AND PageItemId = Id" + 171 $" LEFT JOIN Page as PageProperties ON AreaItemTypePageProperty = '{row.TableName.Replace("ItemType_","")}' AND PageProperties.PagePropertyItemId = Id" + 172 $" LEFT JOIN GridRow ON GridRowItemType = '{row.TableName.Replace("ItemType_","")}' AND GridRowItemId = Id" + 173 $" LEFT JOIN Paragraph ON ParagraphItemType = '{row.TableName.Replace("ItemType_","")}' AND ParagraphItemId = Id" + 174 $" WHERE {row.ColumnName} != '' AND {row.ColumnName} IS NOT NULL" + 175 $" AND (AreaId IS NULL OR AreaId = {Pageview.AreaID})" + 176 $" AND (Page.PageId IS NULL OR Page.PageAreaId = {Pageview.AreaID})" + 177 $" AND (PageProperties.PageId IS NULL OR PageProperties.PageAreaId = {Pageview.AreaID})" + 178 $" AND (GridRowId IS NULL OR GridRowPageId IN (SELECT value From string_split(@pageIds, ',')))" + 179 $" AND (ParagraphId IS NULL OR ParagraphPageId IN (SELECT value From string_split(@pageIds, ',')))"; 180 181 var maxMsSqlServerCharLimit = 60000; 182 if (sqlQuery.Length > maxMsSqlServerCharLimit) 183 { 184 UpdateThemeUsages(sqlQuery, themeUsages); 185 sqlQuery = ""; 186 } 187 } 188 189 if (!string.IsNullOrEmpty(sqlQuery)) 190 { 191 UpdateThemeUsages(sqlQuery, themeUsages); 192 } 193 UpdateAllUsages(themeUsages); 194 195 Dynamicweb.Context.Current.Items[cacheKey] = themeUsages; 196 return themeUsages; 197 } 198 199 private void UpdateThemeUsages(string sqlQuery, List<ThemeUsage> themeUsages) 200 { 201 sqlQuery = $"DECLARE @pageIds NVARCHAR(max) = (SELECT STRING_AGG(PageId,',') FROM Page WHERE PageAreaId = {Pageview.AreaID}) " + sqlQuery; 202 var rawData = Dynamicweb.Data.Database.CreateDataReader(sqlQuery); 203 while (rawData.Read()) 204 { 205 var themeId = rawData["ColumnValue"].ToString(); 206 var themeUsageExists = themeUsages.FirstOrDefault(t => t.Id == themeId) != null; 207 if (!themeUsageExists) 208 { 209 themeUsages.Add(new ThemeUsage { Id = themeId }); 210 } 211 212 var themeUsage = themeUsages.FirstOrDefault(t => t.Id == themeId); 213 if (themeUsage == null) continue; 214 215 if (Converter.ToInt32(rawData["AreaId"].ToString()) > 0) { themeUsage.WebsiteUsages.Add(Converter.ToInt32(rawData["AreaId"].ToString())); } 216 if (Converter.ToInt32(rawData["PageId"].ToString()) > 0) { themeUsage.PageUsages.Add(Converter.ToInt32(rawData["PageId"].ToString())); } 217 if (Converter.ToInt32(rawData["PagePropertiesId"].ToString()) > 0) { themeUsage.PagePropertyUsages.Add(Converter.ToInt32(rawData["PagePropertiesId"].ToString())); } 218 if (Converter.ToInt32(rawData["GridRowId"].ToString()) > 0) { themeUsage.GridRowUsages.Add(Converter.ToInt32(rawData["GridRowId"].ToString())); } 219 if (Converter.ToInt32(rawData["ParagraphId"].ToString()) > 0) { themeUsage.ParagraphUsages.Add(Converter.ToInt32(rawData["ParagraphId"].ToString())); } 220 } 221 } 222 223 private void UpdateAllUsages(List<ThemeUsage> themeUsages) 224 { 225 foreach (var themeUsage in themeUsages) 226 { 227 int websiteUsages = themeUsage?.WebsiteUsages.Count ?? 0; 228 int pageUsages = themeUsage?.PageUsages.Count ?? 0; 229 int pagePropertyUsages = themeUsage?.PagePropertyUsages.Count ?? 0; 230 int gridRowUsages = themeUsage?.GridRowUsages.Count ?? 0; 231 int paragraphUsages = themeUsage?.ParagraphUsages.Count ?? 0; 232 themeUsage.AllUsages = websiteUsages + pageUsages + pagePropertyUsages + gridRowUsages + paragraphUsages; 233 } 234 } 235 236 private ThemeUsage GetThemeUsageById(string themeId) 237 { 238 var themeUsages = GetAllThemeUsages(); 239 return themeUsages.FirstOrDefault(t => t.Id == themeId); 240 } 241 242 } 243 244 @{ 245 string themeName = !string.IsNullOrWhiteSpace(Model.Item.GetString("Name")) ? Model.Item.GetString("Name") : "Default"; 246 string themeClassName = !string.IsNullOrWhiteSpace(Model.Item.GetString("CSSClassName")) ? Model.Item.GetString("CSSClassName").Replace(" ", "").Trim().ToLower() : ""; 247 248 //Theme colors 249 string foregroundColor = Model.Item.GetString("ForegroundColor", "currentColor"); 250 string backgroundColor = Model.Item.GetString("BackgroundColor", "transparent"); 251 string accentColor = Model.Item.GetString("accentColor", "currentColor"); 252 string borderColor = Model.Item.GetString("BorderColor", "transparent"); 253 254 //Primary button 255 string buttonPrimaryForegroundColor = Model.Item.GetString("ButtonPrimaryForegroundColor", "currentColor"); 256 string buttonPrimaryBackgroundColor = Model.Item.GetString("ButtonPrimaryBackgroundColor", "transparent"); 257 string buttonPrimaryBorderColor = Model.Item.GetString("ButtonPrimaryBorderColor", "transparent"); 258 259 string buttonPrimaryHoverBackgroundColorAuto = "transparent"; 260 if (buttonPrimaryBackgroundColor != "transparent") 261 { 262 buttonPrimaryHoverBackgroundColorAuto = "hsl(" + GetColorVariation(buttonPrimaryBackgroundColor) + ")"; 263 } 264 string buttonPrimaryHoverForegroundColor = Model.Item.GetString("ButtonPrimaryHoverForegroundColor", buttonPrimaryForegroundColor); 265 string buttonPrimaryHoverBackgroundColor = Model.Item.GetString("ButtonPrimaryHoverBackgroundColor", buttonPrimaryHoverBackgroundColorAuto); 266 string buttonPrimaryHoverBorderColor = Model.Item.GetString("ButtonPrimaryHoverBorderColor", buttonPrimaryBorderColor); 267 268 //Secondary buton 269 string buttonSecondaryForegroundColor = Model.Item.GetString("ButtonSecondaryForegroundColor", "currentColor"); 270 string buttonSecondaryBackgroundColor = Model.Item.GetString("ButtonSecondaryBackgroundColor", "transparent"); 271 string buttonSecondaryBorderColor = Model.Item.GetString("ButtonSecondaryBorderColor", "transparent"); 272 273 string buttonSecondaryHoverBackgroundColorAuto = "transparent"; 274 if (buttonSecondaryBackgroundColor != "transparent") 275 { 276 buttonSecondaryHoverBackgroundColorAuto = "hsl(" + GetColorVariation(buttonSecondaryBackgroundColor) + ")"; 277 } 278 string buttonSecondaryHoverForegroundColor = Model.Item.GetString("ButtonSecondaryHoverForegroundColor", buttonSecondaryForegroundColor); 279 string buttonSecondaryHoverBackgroundColor = Model.Item.GetString("ButtonSecondaryHoverBackgroundColor", buttonSecondaryHoverBackgroundColorAuto); 280 string buttonSecondaryHoverBorderColor = Model.Item.GetString("ButtonSecondaryHoverBorderColor", buttonSecondaryBorderColor); 281 282 //Link buton 283 string buttonLinkColor = Model.Item.GetString("ButtonLinkColor", "currentColor"); 284 string buttonLinkHoverColorAuto = "currentColor"; 285 if (buttonLinkColor != "currentColor") 286 { 287 buttonLinkHoverColorAuto = "hsl(" + GetColorVariation(buttonLinkColor) + ")"; 288 } 289 string buttonLinkHoverColor = Model.Item.GetString("ButtonLinkHoverColor", buttonLinkHoverColorAuto); 290 291 string accessibilityOutlineColor = Model.Item.GetString("OutlineColor") != null ? Model.Item.GetString("OutlineColor") : ""; 292 293 if (!string.IsNullOrEmpty(themeClassName)) 294 { 295 var sb = new System.Text.StringBuilder(); 296 297 sb.AppendLine("." + themeClassName + "{"); 298 if (!string.IsNullOrEmpty(foregroundColor)) 299 { 300 sb.AppendLine($"--swift-foreground-color: {foregroundColor};"); 301 sb.AppendLine($"--swift-foreground-color-rgb: {HexToRGB(foregroundColor)};"); 302 } 303 if (!string.IsNullOrEmpty(backgroundColor)) 304 { 305 sb.AppendLine($"--swift-background-color: {backgroundColor};"); 306 sb.AppendLine($"--swift-background-color-rgb: {HexToRGB(backgroundColor)};"); 307 } 308 if (!string.IsNullOrEmpty(accentColor)) 309 { 310 sb.AppendLine($"--swift-accent-color: {accentColor};"); 311 sb.AppendLine($"--swift-accent-color-rgb: {HexToRGB(accentColor)};"); 312 } 313 if (!string.IsNullOrEmpty(borderColor)) 314 { 315 sb.AppendLine($"--swift-border-color: {borderColor};"); 316 sb.AppendLine($"--swift-border-color-rgb: {HexToRGB(borderColor)};"); 317 } 318 319 if (!string.IsNullOrEmpty(buttonPrimaryBackgroundColor)) 320 { 321 sb.AppendLine($"--swift-button-primary-background-color: {buttonPrimaryBackgroundColor};"); 322 sb.AppendLine($"--swift-button-primary-background-color-rgb: {HexToRGB(buttonPrimaryBackgroundColor)};"); 323 } 324 if (!string.IsNullOrEmpty(buttonPrimaryForegroundColor)) 325 { 326 sb.AppendLine($"--swift-button-primary-foreground-color: {buttonPrimaryForegroundColor};"); 327 sb.AppendLine($"--swift-button-primary-foreground-color-rgb: {HexToRGB(buttonPrimaryForegroundColor)};"); 328 } 329 if (!string.IsNullOrEmpty(buttonPrimaryBorderColor)) 330 { 331 sb.AppendLine($"--swift-button-primary-border-color: {buttonPrimaryBorderColor};"); 332 sb.AppendLine($"--swift-button-primary-border-color-rgb: {HexToRGB(buttonPrimaryBorderColor)};"); 333 } 334 335 if (!string.IsNullOrEmpty(buttonPrimaryHoverBackgroundColor)) 336 { 337 sb.AppendLine($"--swift-button-primary-hover-background-color: {buttonPrimaryHoverBackgroundColor};"); 338 sb.AppendLine($"--swift-button-primary-hover-background-color-rgb: {HexToRGB(buttonPrimaryHoverBackgroundColor)};"); 339 } 340 if (!string.IsNullOrEmpty(buttonPrimaryHoverForegroundColor)) 341 { 342 sb.AppendLine($"--swift-button-primary-hover-foreground-color: {buttonPrimaryHoverForegroundColor};"); 343 sb.AppendLine($"--swift-button-primary-hover-foreground-color-rgb: {HexToRGB(buttonPrimaryHoverForegroundColor)};"); 344 } 345 if (!string.IsNullOrEmpty(buttonPrimaryHoverBorderColor)) 346 { 347 sb.AppendLine($"--swift-button-primary-hover-border-color: {buttonPrimaryHoverBorderColor};"); 348 sb.AppendLine($"--swift-button-primary-hover-border-color-rgb: {HexToRGB(buttonPrimaryHoverBorderColor)};"); 349 } 350 351 if (!string.IsNullOrEmpty(buttonSecondaryBackgroundColor)) 352 { 353 sb.AppendLine($"--swift-button-secondary-background-color: {buttonSecondaryBackgroundColor};"); 354 sb.AppendLine($"--swift-button-secondary-background-color-rgb: {HexToRGB(buttonSecondaryBackgroundColor)};"); 355 } 356 if (!string.IsNullOrEmpty(buttonSecondaryForegroundColor)) 357 { 358 sb.AppendLine($"--swift-button-secondary-foreground-color: {buttonSecondaryForegroundColor};"); 359 sb.AppendLine($"--swift-button-secondary-foreground-color-rgb: {HexToRGB(buttonSecondaryForegroundColor)};"); 360 } 361 if (!string.IsNullOrEmpty(buttonSecondaryBorderColor)) 362 { 363 sb.AppendLine($"--swift-button-secondary-border-color: {buttonSecondaryBorderColor};"); 364 sb.AppendLine($"--swift-button-secondary-border-color-rgb: {HexToRGB(buttonSecondaryBorderColor)};"); 365 } 366 if (!string.IsNullOrEmpty(buttonSecondaryHoverBackgroundColor)) 367 { 368 sb.AppendLine($"--swift-button-secondary-hover-background-color: {buttonSecondaryHoverBackgroundColor};"); 369 sb.AppendLine($"--swift-button-secondary-hover-background-color-rgb: {HexToRGB(buttonSecondaryHoverBackgroundColor)};"); 370 } 371 if (!string.IsNullOrEmpty(buttonSecondaryHoverForegroundColor)) 372 { 373 sb.AppendLine($"--swift-button-secondary-hover-foreground-color: {buttonSecondaryHoverForegroundColor};"); 374 sb.AppendLine($"--swift-button-secondary-hover-foreground-color-rgb: {HexToRGB(buttonSecondaryHoverForegroundColor)};"); 375 } 376 if (!string.IsNullOrEmpty(buttonSecondaryHoverBorderColor)) 377 { 378 sb.AppendLine($"--swift-button-secondary-hover-border-color: {buttonSecondaryHoverBorderColor};"); 379 sb.AppendLine($"--swift-button-secondary-hover-border-color-rgb: {HexToRGB(buttonSecondaryHoverBorderColor)};"); 380 } 381 if (!string.IsNullOrEmpty(buttonLinkColor)) 382 { 383 sb.AppendLine($"--swift-button-link-color: {buttonLinkColor};"); 384 sb.AppendLine($"--swift-button-link-color-rgb: {HexToRGB(buttonLinkColor)};"); 385 } 386 if (!string.IsNullOrEmpty(buttonLinkHoverColor)) 387 { 388 sb.AppendLine($"--swift-button-link-hover-color: {buttonLinkHoverColor};"); 389 sb.AppendLine($"--swift-button-link-hover-color-rgb: {HexToRGB(buttonLinkHoverColor)};"); 390 } 391 if (!string.IsNullOrEmpty(accessibilityOutlineColor)) 392 { 393 sb.AppendLine($"--swift-a11y-outline-color: {accessibilityOutlineColor};"); 394 sb.AppendLine($"--swift-a11y-outline-color-rgb: {HexToRGB(accessibilityOutlineColor)};"); 395 } 396 sb.AppendLine("}"); 397 398 Dynamicweb.Core.Helpers.TextFileHelper.WriteTextFile(sb.ToString() + Environment.NewLine, Dynamicweb.Context.Current.Server.MapPath($"/Files/Templates/Designs/Swift/_parsed/Swift_css/Swift_theme_styles_{Dynamicweb.Content.Services.Pages.GetPage(Model.PageID).AreaId}.tmp"), true); 399 } 400 } 401 402 @if (themeClassName != "") 403 { 404 string iconPath = "/Files/Templates/Designs/Swift/Assets/icons/"; 405 406 <div class="g-col-12 g-col-lg-4"> 407 <div class="swift-checkered p-3"> 408 <div class="theme-option theme @themeClassName p-lg-3"> 409 <div class="mb-2 pb-1 border-bottom d-flex align-items-center"> 410 <span class="icon-3 me-2"> 411 @ReadFile(iconPath + "sun.svg") 412 </span> 413 <h4 class="m-0 p-0">@themeName</h4> 414 </div> 415 <div class="d-flex flex-column gap-1 mb-2"> 416 <p class="mb-0">This is the body text of the theme.</p> 417 <p class="mb-0" style="color: var(--swift-accent-color)">This is the accent color of the theme.</p> 418 </div> 419 <div> 420 <button class="btn btn-primary me-1">Primary</button> 421 <button class="btn btn-secondary">Secondary</button> 422 <button class="btn btn-link">Link</button> 423 </div> 424 </div> 425 </div> 426 </div> 427 <div class="g-col-12 g-col-lg-8 mb-4 mb-lg-0"> 428 <div class="grid fs-7"> 429 <div class="g-col-12 g-col-lg-3"> 430 <table class="table table-borderless table-sm w-100"> 431 <thead> 432 <tr> 433 <th colspan="2" class="fw-bold">@Translate("Base")</th> 434 </tr> 435 </thead> 436 <tr> 437 <td>@Translate("Foreground")</td> 438 <td>@GetColorSquare(foregroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@foregroundColor');">@foregroundColor</a></td> 439 </tr> 440 <tr> 441 <td>@Translate("Background")</td> 442 <td>@GetColorSquare(backgroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@backgroundColor');">@backgroundColor</a></td> 443 </tr> 444 <tr> 445 <td>@Translate("Accent")</td> 446 <td>@GetColorSquare(accentColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@accentColor');">@accentColor</a></td> 447 </tr> 448 <tr> 449 <td>@Translate("Border")</td> 450 <td>@GetColorSquare(borderColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@borderColor');">@borderColor</a></td> 451 </tr> 452 </table> 453 </div> 454 <div class="g-col-12 g-col-lg-3"> 455 <table class="table table-borderless table-sm w-100"> 456 <thead> 457 <tr> 458 <th colspan="2" class="fw-bold">@Translate("Primary button")</th> 459 </tr> 460 </thead> 461 <tr> 462 <td>@Translate("Foreground")</td> 463 <td>@GetColorSquare(buttonPrimaryForegroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonPrimaryForegroundColor');">@buttonPrimaryForegroundColor</a></td> 464 </tr> 465 <tr> 466 <td>@Translate("Background")</td> 467 <td>@GetColorSquare(buttonPrimaryBackgroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonPrimaryBackgroundColor');">@buttonPrimaryBackgroundColor</a></td> 468 </tr> 469 @if (!string.IsNullOrEmpty(buttonPrimaryBorderColor)) 470 { 471 <tr> 472 <td>@Translate("Border")</td> 473 <td>@GetColorSquare(buttonPrimaryBorderColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonPrimaryBorderColor');">@buttonPrimaryBorderColor</a></td> 474 </tr> 475 } 476 <thead> 477 <tr> 478 <th colspan="2" class="fw-bold">@Translate("Primary button hover")</th> 479 </tr> 480 </thead> 481 @if (!string.IsNullOrEmpty(buttonPrimaryHoverForegroundColor)) 482 { 483 <tr> 484 <td>@Translate("Foreground")</td> 485 <td>@GetColorSquare(buttonPrimaryHoverForegroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonPrimaryHoverForegroundColor');">@buttonPrimaryHoverForegroundColor</a></td> 486 </tr> 487 } 488 @if (!string.IsNullOrEmpty(buttonPrimaryHoverBackgroundColor)) 489 { 490 <tr> 491 <td>@Translate("Background")</td> 492 <td>@GetColorSquare(buttonPrimaryHoverBackgroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonPrimaryHoverBackgroundColor');">@buttonPrimaryHoverBackgroundColor</a></td> 493 </tr> 494 } 495 @if (!string.IsNullOrEmpty(buttonPrimaryHoverBorderColor)) 496 { 497 <tr> 498 <td>@Translate("Border")</td> 499 <td>@GetColorSquare(buttonPrimaryHoverBorderColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonPrimaryHoverBorderColor');">@buttonPrimaryHoverBorderColor</a></td> 500 </tr> 501 } 502 </table> 503 </div> 504 <div class="g-col-12 g-col-lg-3"> 505 <table class="table table-borderless table-sm w-100"> 506 <thead> 507 <tr> 508 <th colspan="2" class="fw-bold">@Translate("Secondary button")</th> 509 </tr> 510 </thead> 511 <tr> 512 <td>@Translate("Foreground")</td> 513 <td>@GetColorSquare(buttonSecondaryForegroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonSecondaryForegroundColor');">@buttonSecondaryForegroundColor</a></td> 514 </tr> 515 <tr> 516 <td>@Translate("Background")</td> 517 <td>@GetColorSquare(buttonSecondaryBackgroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonSecondaryBackgroundColor');">@buttonSecondaryBackgroundColor</a></td> 518 </tr> 519 @if (!string.IsNullOrEmpty(buttonSecondaryBorderColor)) 520 { 521 <tr> 522 <td>@Translate("Border")</td> 523 <td>@GetColorSquare(buttonSecondaryBorderColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonSecondaryBorderColor');">@buttonSecondaryBorderColor</a></td> 524 </tr> 525 } 526 <thead> 527 <tr> 528 <th colspan="2" class="fw-bold">@Translate("Secondary button hover")</th> 529 </tr> 530 </thead> 531 @if (!string.IsNullOrEmpty(buttonSecondaryHoverForegroundColor)) 532 { 533 <tr> 534 <td>@Translate("Foreground")</td> 535 <td>@GetColorSquare(buttonSecondaryHoverForegroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonSecondaryHoverForegroundColor');">@buttonSecondaryHoverForegroundColor</a></td> 536 </tr> 537 } 538 @if (!string.IsNullOrEmpty(buttonSecondaryHoverBackgroundColor)) 539 { 540 <tr> 541 <td>@Translate("Background")</td> 542 <td>@GetColorSquare(buttonSecondaryHoverBackgroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonSecondaryHoverBackgroundColor');">@buttonSecondaryHoverBackgroundColor</a></td> 543 </tr> 544 } 545 @if (!string.IsNullOrEmpty(buttonSecondaryHoverBorderColor)) 546 { 547 <tr> 548 <td>@Translate("Border")</td> 549 <td>@GetColorSquare(buttonSecondaryHoverBorderColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonSecondaryHoverBorderColor');">@buttonSecondaryHoverBorderColor</a></td> 550 </tr> 551 } 552 @if (!string.IsNullOrEmpty(accessibilityOutlineColor)) 553 { 554 <tr> 555 <td>@Translate("Focus outline")</td> 556 <td>@GetColorSquare(accessibilityOutlineColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@accessibilityOutlineColor');">@accessibilityOutlineColor</a></td> 557 </tr> 558 } 559 </table> 560 </div> 561 <div class="g-col-12 g-col-lg-3"> 562 <table class="table table-borderless table-sm w-100"> 563 <thead> 564 <tr> 565 <th colspan="2" class="fw-bold">@Translate("Link button")</th> 566 </tr> 567 </thead> 568 <tr> 569 <td>@Translate("Link color")</td> 570 <td>@GetColorSquare(buttonLinkColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonLinkColor');">@buttonLinkColor</a></td> 571 </tr> 572 <thead> 573 <tr> 574 <th colspan="2" class="fw-bold">@Translate("Link button hover")</th> 575 </tr> 576 </thead> 577 @if (!string.IsNullOrEmpty(buttonLinkHoverColor)) 578 { 579 <tr> 580 <td>@Translate("Link hover color")</td> 581 <td>@GetColorSquare(buttonLinkHoverColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonLinkHoverColor');">@buttonLinkHoverColor</a></td> 582 </tr> 583 } 584 585 @if (!string.IsNullOrEmpty(accessibilityOutlineColor)) 586 { 587 <tr> 588 <td>@Translate("Focus outline")</td> 589 <td>@GetColorSquare(accessibilityOutlineColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@accessibilityOutlineColor');">@accessibilityOutlineColor</a></td> 590 </tr> 591 } 592 </table> 593 </div> 594 <div class="g-col-12 g-col-lg-3"> 595 <table class="table table-borderless table-sm w-100"> 596 <tr> 597 <td class="fw-bold">@Translate("Implementation")</td> 598 </tr> 599 <tr> 600 <td> 601 @{ 602 string implementation = $"<div class=\"theme {themeClassName}\"></div>"; 603 } 604 <div class="text-muted"> 605 <code class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@themeClassName');"> 606 @Dynamicweb.Core.Encoders.HtmlEncoder.HtmlEncode(implementation) 607 </code> 608 </div> 609 </td> 610 </tr> 611 </table> 612 </div> 613 @{ 614 bool hasUsageData = Converter.ToBoolean(Dynamicweb.Context.Current.Request["auditUsages"]); 615 if (hasUsageData) 616 { 617 var themeUsage = GetThemeUsageById(themeClassName); 618 int allUsages = themeUsage?.AllUsages ?? 0; 619 string buttonAttributes = allUsages > 0 ? $"data-bs-toggle=\"modal\" data-bs-target=\"#themeUsage_{Model.ID}\"" : string.Empty; 620 string badgeStyle = allUsages > 0 ? "bg-success" : "bg-danger"; 621 622 <div class="g-col-12 g-col-lg-9 position-relative"> 623 <button type="button" class="btn btn-primary btn-sm position-absolute end-0" @buttonAttributes> 624 Usages 625 <span class="position-absolute top-0 start-100 translate-middle badge rounded-pill text-white @badgeStyle">@allUsages</span> 626 </button> 627 628 @if (allUsages > 0) 629 { 630 int websiteUsages = themeUsage?.WebsiteUsages.Count ?? 0; 631 int pageUsages = themeUsage?.PageUsages.Count ?? 0; 632 int pagePropertyUsages = themeUsage?.PagePropertyUsages.Count ?? 0; 633 int gridRowUsages = themeUsage?.GridRowUsages.Count ?? 0; 634 int paragraphUsages = themeUsage?.ParagraphUsages.Count ?? 0; 635 636 <!-- Modal --> 637 <div class="modal fade" id="themeUsage_@(Model.ID)" tabindex="-1" aria-labelledby="usagesModelLabel" aria-hidden="true"> 638 <div class="modal-dialog modal-xl modal-dialog-centered modal-dialog-scrollable"> 639 <div class="modal-content"> 640 <div class="modal-header"> 641 <h5 class="modal-title" id="usagesModelLabel">@allUsages Usages of '@(themeName)' (@(themeClassName))</h5> 642 <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> 643 </div> 644 <div class="modal-body"> 645 <div class="accordion" id="accordionWrapper"> 646 @if(websiteUsages > 0) 647 { 648 <div class="accordion-item"> 649 <h2 class="accordion-header" id="headingWebsites"> 650 <button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#collapseWebsites" aria-expanded="true" aria-controls="collapseWebsites"> 651 <span class="pe-2">Websites</span><span class="badge rounded-pill bg-secondary text-light">@websiteUsages</span> 652 </button> 653 </h2> 654 <div id="collapseWebsites" class="accordion-collapse collapse show" aria-labelledby="headingWebsites" data-bs-parent="#accordionWrapper"> 655 <div class="accordion-body"> 656 <ul> 657 @foreach (var usage in themeUsage.WebsiteUsages) 658 { 659 var website = Dynamicweb.Content.Services.Areas.GetArea(usage); 660 <li><span class="fw-bold">@website.Name</span>@($" (ID: {usage})")</li> 661 } 662 </ul> 663 </div> 664 </div> 665 </div> 666 } 667 @if (pageUsages > 0) 668 { 669 var pages = Dynamicweb.Content.Services.Pages.GetPages(themeUsage.PageUsages.ToArray()); 670 671 <div class="accordion-item"> 672 <h2 class="accordion-header" id="headingPages"> 673 <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapsePages" aria-expanded="false" aria-controls="collapsePages"> 674 <span class="pe-2">Pages</span><span class="badge rounded-pill bg-secondary text-light">@pageUsages</span> 675 </button> 676 </h2> 677 <div id="collapsePages" class="accordion-collapse collapse" aria-labelledby="headingPages" data-bs-parent="#accordionWrapper"> 678 <div class="accordion-body"> 679 <ul> 680 @foreach (var usage in themeUsage.PageUsages) 681 { 682 <li><span class="fw-bold">@pages.FirstOrDefault(p => p.ID == usage).GetDisplayName()</span>@($" (ID: {usage})")</li> 683 } 684 </ul> 685 </div> 686 </div> 687 </div> 688 } 689 @if (pagePropertyUsages > 0) 690 { 691 var pages = Dynamicweb.Content.Services.Pages.GetPages(themeUsage.PageUsages.ToArray()); 692 693 <div class="accordion-item"> 694 <h2 class="accordion-header" id="headingPageProperties"> 695 <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapsePageProperties" aria-expanded="false" aria-controls="collapsePageProperties"> 696 <span class="pe-2">Page Properties</span><span class="badge rounded-pill bg-secondary text-light">@pagePropertyUsages</span> 697 </button> 698 </h2> 699 <div id="collapsePageProperties" class="accordion-collapse collapse" aria-labelledby="headingPageProperties" data-bs-parent="#accordionWrapper"> 700 <div class="accordion-body"> 701 <ul> 702 @foreach (var usage in themeUsage.PagePropertyUsages) 703 { 704 <li><span class="fw-bold">@pages.FirstOrDefault(p => p.ID == usage).GetDisplayName()</span>@($" (ID: {usage})")</li> 705 } 706 </ul> 707 </div> 708 </div> 709 </div> 710 } 711 @if (gridRowUsages > 0) 712 { 713 var rows = Dynamicweb.Content.Services.Grids.GetGridRows().Where(r => themeUsage.GridRowUsages.Contains(r.ID)).ToList(); 714 715 <div class="accordion-item"> 716 <h2 class="accordion-header" id="headingRows"> 717 <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseRows" aria-expanded="false" aria-controls="collapseRows"> 718 <span class="pe-2">Rows</span><span class="badge rounded-pill bg-secondary text-light">@gridRowUsages</span> 719 </button> 720 </h2> 721 <div id="collapseRows" class="accordion-collapse collapse" aria-labelledby="headingRows" data-bs-parent="#accordionWrapper"> 722 <div class="accordion-body"> 723 <ul> 724 @foreach (var usage in themeUsage.GridRowUsages) 725 { 726 var row = rows.FirstOrDefault(r => r.ID == usage); 727 var page = Dynamicweb.Content.Services.Pages.GetPage(row.PageId); 728 <li>Page: <span class="fw-bold">@(page.GetDisplayName())</span>@($"( ID: {page.ID}) - Row: ")<span class="fw-bold">@(row.DefinitionId)</span>@($" (ID: {usage})")</li> 729 } 730 </ul> 731 </div> 732 </div> 733 </div> 734 } 735 @if (paragraphUsages > 0) 736 { 737 var paragraphs = Dynamicweb.Content.Services.Paragraphs.GetParagraphs().Where(p => themeUsage.ParagraphUsages.Contains(p.ID)).ToList(); 738 739 <div class="accordion-item"> 740 <h2 class="accordion-header" id="headingParagraphs"> 741 <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseParagraphs" aria-expanded="false" aria-controls="collapseParagraphs"> 742 <span class="pe-2">Paragraphs</span><span class="badge rounded-pill bg-secondary text-light">@paragraphUsages</span> 743 </button> 744 </h2> 745 <div id="collapseParagraphs" class="accordion-collapse collapse" aria-labelledby="headingParagraphs" data-bs-parent="#accordionWrapper"> 746 <div class="accordion-body"> 747 <ul> 748 @foreach (var usage in themeUsage.ParagraphUsages) 749 { 750 var paragraph = paragraphs.FirstOrDefault(p => p.ID == usage); 751 var page = Dynamicweb.Content.Services.Pages.GetPage(paragraph.PageID); 752 <li>Page: <span class="fw-bold">@(page.GetDisplayName())</span>@($"( ID: {page.ID}) - Paragraph: ")<span class="fw-bold">@paragraph.Header</span>@($" (ID: {usage})")</li> 753 } 754 </ul> 755 </div> 756 </div> 757 </div> 758 } 759 </div> 760 </div> 761 </div> 762 </div> 763 </div> 764 } 765 </div> 766 } 767 } 768 </div> 769 </div> 770 } 771 <div class="g-col-12"> 772 <hr /> 773 </div> 774
Error executing template "Designs/Swift/Paragraph/Swift_Theme.cshtml" System.Data.SqlClient.SqlException (0x80131904): STRING_AGG aggregation result exceeded the limit of 8000 bytes. Use LOB types to avoid result truncation. at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction) at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose) at System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady) at System.Data.SqlClient.SqlDataReader.TryConsumeMetaData() at System.Data.SqlClient.SqlDataReader.get_MetaData() at System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString, Boolean isInternal, Boolean forDescribeParameterEncryption, Boolean shouldCacheForAlwaysEncrypted) at System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async, Int32 timeout, Task& task, Boolean asyncWrite, Boolean inRetry, SqlDataReader ds, Boolean describeParameterEncryptionRequest) at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, TaskCompletionSource`1 completion, Int32 timeout, Task& task, Boolean& usedCache, Boolean asyncWrite, Boolean inRetry) at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method) at System.Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior behavior, String method) at Dynamicweb.Data.Database.CreateDataReader(IDbCommand command, CommandBehavior behavior) at Dynamicweb.Data.Database.CreateDataReader(String sql, IDbConnection connection, IDbTransaction transaction, CommandBehavior behavior, Int32 commandTimeout, Dictionary`2 sqlParams) at Dynamicweb.Data.Database.CreateDataReader(String sql, IDbConnection connection, IDbTransaction transaction, Int32 commandTimeout, Dictionary`2 sqlParams) at Dynamicweb.Data.Database.CreateDataReader(String sql) at CompiledRazorTemplates.Dynamic.RazorEngine_8e3f1b11eb0041ceb2ca487c2be837e6.UpdateThemeUsages(String sqlQuery, List`1 themeUsages) in E:\Dynamicweb.net\Solutions\Dynamicweb\dw2022.cloud.dynamicweb-cms.com\Files\Templates\Designs\Swift\Paragraph\Swift_Theme.cshtml:line 202 at CompiledRazorTemplates.Dynamic.RazorEngine_8e3f1b11eb0041ceb2ca487c2be837e6.GetAllThemeUsages() in E:\Dynamicweb.net\Solutions\Dynamicweb\dw2022.cloud.dynamicweb-cms.com\Files\Templates\Designs\Swift\Paragraph\Swift_Theme.cshtml:line 184 at CompiledRazorTemplates.Dynamic.RazorEngine_8e3f1b11eb0041ceb2ca487c2be837e6.GetThemeUsageById(String themeId) in E:\Dynamicweb.net\Solutions\Dynamicweb\dw2022.cloud.dynamicweb-cms.com\Files\Templates\Designs\Swift\Paragraph\Swift_Theme.cshtml:line 238 at CompiledRazorTemplates.Dynamic.RazorEngine_8e3f1b11eb0041ceb2ca487c2be837e6.Execute() in E:\Dynamicweb.net\Solutions\Dynamicweb\dw2022.cloud.dynamicweb-cms.com\Files\Templates\Designs\Swift\Paragraph\Swift_Theme.cshtml:line 617 at RazorEngine.Templating.TemplateBase.RazorEngine.Templating.ITemplate.Run(ExecuteContext context, TextWriter reader) at RazorEngine.Templating.RazorEngineService.RunCompile(ITemplateKey key, TextWriter writer, Type modelType, Object model, DynamicViewBag viewBag) at RazorEngine.Templating.RazorEngineServiceExtensions.<>c__DisplayClass16_0.<RunCompile>b__0(TextWriter writer) at RazorEngine.Templating.RazorEngineServiceExtensions.WithWriter(Action`1 withWriter) at Dynamicweb.Rendering.RazorTemplateRenderingProvider.Render(Template template) at Dynamicweb.Rendering.TemplateRenderingService.Render(Template template) at Dynamicweb.Rendering.Template.RenderRazorTemplate() ClientConnectionId:b42d1cec-597c-4eed-bdc2-e0762a41101a Error Number:9829,State:1,Class:16
1 @inherits Dynamicweb.Rendering.ViewModelTemplate<Dynamicweb.Frontend.ParagraphViewModel> 2 @using System.Globalization 3 @using System.Drawing 4 @using Dynamicweb.Core 5 6 @functions{ 7 // Get Hex Color from color picker and translate to RGB color 8 public static string HexToRGB(string hexString) 9 { 10 if (hexString.Equals("none") || string.IsNullOrEmpty(hexString)) 11 return hexString; 12 13 //replace # occurences 14 if (hexString.IndexOf('#') != -1) 15 hexString = hexString.Replace("#", ""); 16 try 17 { 18 int r, g, b = 0; 19 r = int.Parse(hexString.Substring(0, 2), NumberStyles.AllowHexSpecifier); 20 g = int.Parse(hexString.Substring(2, 2), NumberStyles.AllowHexSpecifier); 21 b = int.Parse(hexString.Substring(4, 2), NumberStyles.AllowHexSpecifier); 22 23 string rgb = r + "," + g + "," + b; 24 return rgb; 25 } 26 catch (System.Exception) 27 { 28 return hexString; 29 } 30 } 31 32 public static string GetColorSquare(string hex) 33 { 34 return $"<div class=\"swift-checkered d-inline-block me-1\" style=\"height:1.25rem;width:1.25rem;\"><div style=\"background-color: {hex};border:.0625rem solid grey\" class=\"w-100 h-100\"></div></div>"; 35 } 36 37 public class HSL 38 { 39 public double h { get; set; } 40 public double s { get; set; } 41 public double l { get; set; } 42 } 43 44 //Convert HEX to HSL 45 public static HSL HexToHsl(string hexString) 46 { 47 System.Drawing.Color color = System.Drawing.ColorTranslator.FromHtml(hexString); 48 49 float _R = (color.R / 255f); 50 float _G = (color.G / 255f); 51 float _B = (color.B / 255f); 52 53 float _Min = Math.Min(Math.Min(_R, _G), _B); 54 float _Max = Math.Max(Math.Max(_R, _G), _B); 55 float _Delta = _Max - _Min; 56 57 float S = 0; 58 float L = (float)((_Max + _Min) / 2.0f); 59 60 if (_Delta != 0) 61 { 62 if (L < 0.5f) 63 { 64 S = (float)(_Delta / (_Max + _Min)); 65 } 66 else 67 { 68 S = (float)(_Delta / (2.0f - _Max - _Min)); 69 } 70 } 71 72 HSL hsl = new HSL(); 73 hsl.h = Math.Round(color.GetHue(), 2); 74 hsl.s = Math.Round(S, 2) * 100; 75 hsl.l = Math.Round(L, 2) * 100; 76 77 return hsl; 78 } 79 80 //Find contrast color (white, black) 81 public static Color GetContrastColor(string hexString) 82 { 83 System.Drawing.Color bg = System.Drawing.ColorTranslator.FromHtml(hexString); 84 85 int nThreshold = 105; 86 int bgDelta = Convert.ToInt32((bg.R * 0.299) + (bg.G * 0.587) + 87 (bg.B * 0.114)); 88 89 Color foreColor = (255 - bgDelta < nThreshold) ? Color.Black : Color.White; 90 return foreColor; 91 } 92 93 public string GetColorVariation(string hexString) 94 { 95 var contrast = GetContrastColor(hexString); 96 HSL currentHslColor = HexToHsl(hexString); 97 HSL variantHslColor = currentHslColor; 98 99 if (contrast == Color.Black) 100 { 101 variantHslColor.l = 85; //The background is dark - Color should be light 102 } 103 else 104 { 105 variantHslColor.l = 40; //The background is light - Color should be less light 106 } 107 108 //Color is very light 109 if (currentHslColor.l > 85) 110 { 111 variantHslColor.l = 95; 112 } 113 114 string colorString = variantHslColor.h + ", " + variantHslColor.s + "%, " + variantHslColor.l + "%"; 115 return colorString; 116 } 117 118 private class ThemeDatabaseUsage 119 { 120 public string TableName { get; set; } 121 public string ColumnName { get; set; } 122 } 123 124 private class ThemeUsage 125 { 126 public string Id { get; set; } 127 public List<int> WebsiteUsages { get; set; } = new List<int>(); 128 public List<int> PageUsages { get; set; } = new List<int>(); 129 public List<int> PagePropertyUsages { get; set; } = new List<int>(); 130 public List<int> GridRowUsages { get; set; } = new List<int>(); 131 public List<int> ParagraphUsages { get; set; } = new List<int>(); 132 public int AllUsages { get; set; } = 0; 133 } 134 135 private List<ThemeDatabaseUsage> GetThemeColumnsFromSchema() 136 { 137 string cacheKey = "ThemesFromDatabase"; 138 if (Dynamicweb.Context.Current.Items.Contains(cacheKey)) 139 { 140 return (List<ThemeDatabaseUsage>)Dynamicweb.Context.Current.Items[cacheKey]; 141 } 142 var schema = Dynamicweb.Data.Database.CreateDataReader("SELECT table_name, column_name FROM information_schema.columns WHERE column_name LIKE '%Theme%'"); 143 144 var rawData = new List<ThemeDatabaseUsage>(); 145 while (schema.Read()) { 146 rawData.Add(new ThemeDatabaseUsage {TableName = schema["table_name"].ToString(), ColumnName = schema["column_name"].ToString() }); 147 } 148 Dynamicweb.Context.Current.Items[cacheKey] = rawData; 149 return rawData; 150 } 151 152 private List<ThemeUsage> GetAllThemeUsages() 153 { 154 string cacheKey = "ThemeUsages"; 155 if (Dynamicweb.Context.Current.Items.Contains(cacheKey)) 156 { 157 return (List<ThemeUsage>)Dynamicweb.Context.Current.Items[cacheKey]; 158 } 159 160 var rawData = GetThemeColumnsFromSchema(); 161 var themeUsages = new List<ThemeUsage>(); 162 163 var sqlQuery = ""; 164 foreach (var row in rawData) 165 { 166 if (!string.IsNullOrEmpty(sqlQuery)) { sqlQuery += " UNION ALL "; } 167 sqlQuery += $"SELECT '{row.TableName}' AS TableName, '{row.ColumnName}' AS ColumnName, {row.ColumnName} AS ColumnValue, Id, AreaId, Page.PageId, PageProperties.PageId as 'PagePropertiesId', GridRowId, ParagraphId" + 168 $" FROM [{row.TableName}]" + 169 $" LEFT JOIN Area ON AreaItemType = '{row.TableName.Replace("ItemType_","")}' AND AreaItemId = Id" + 170 $" LEFT JOIN Page ON PageItemType = '{row.TableName.Replace("ItemType_","")}' AND PageItemId = Id" + 171 $" LEFT JOIN Page as PageProperties ON AreaItemTypePageProperty = '{row.TableName.Replace("ItemType_","")}' AND PageProperties.PagePropertyItemId = Id" + 172 $" LEFT JOIN GridRow ON GridRowItemType = '{row.TableName.Replace("ItemType_","")}' AND GridRowItemId = Id" + 173 $" LEFT JOIN Paragraph ON ParagraphItemType = '{row.TableName.Replace("ItemType_","")}' AND ParagraphItemId = Id" + 174 $" WHERE {row.ColumnName} != '' AND {row.ColumnName} IS NOT NULL" + 175 $" AND (AreaId IS NULL OR AreaId = {Pageview.AreaID})" + 176 $" AND (Page.PageId IS NULL OR Page.PageAreaId = {Pageview.AreaID})" + 177 $" AND (PageProperties.PageId IS NULL OR PageProperties.PageAreaId = {Pageview.AreaID})" + 178 $" AND (GridRowId IS NULL OR GridRowPageId IN (SELECT value From string_split(@pageIds, ',')))" + 179 $" AND (ParagraphId IS NULL OR ParagraphPageId IN (SELECT value From string_split(@pageIds, ',')))"; 180 181 var maxMsSqlServerCharLimit = 60000; 182 if (sqlQuery.Length > maxMsSqlServerCharLimit) 183 { 184 UpdateThemeUsages(sqlQuery, themeUsages); 185 sqlQuery = ""; 186 } 187 } 188 189 if (!string.IsNullOrEmpty(sqlQuery)) 190 { 191 UpdateThemeUsages(sqlQuery, themeUsages); 192 } 193 UpdateAllUsages(themeUsages); 194 195 Dynamicweb.Context.Current.Items[cacheKey] = themeUsages; 196 return themeUsages; 197 } 198 199 private void UpdateThemeUsages(string sqlQuery, List<ThemeUsage> themeUsages) 200 { 201 sqlQuery = $"DECLARE @pageIds NVARCHAR(max) = (SELECT STRING_AGG(PageId,',') FROM Page WHERE PageAreaId = {Pageview.AreaID}) " + sqlQuery; 202 var rawData = Dynamicweb.Data.Database.CreateDataReader(sqlQuery); 203 while (rawData.Read()) 204 { 205 var themeId = rawData["ColumnValue"].ToString(); 206 var themeUsageExists = themeUsages.FirstOrDefault(t => t.Id == themeId) != null; 207 if (!themeUsageExists) 208 { 209 themeUsages.Add(new ThemeUsage { Id = themeId }); 210 } 211 212 var themeUsage = themeUsages.FirstOrDefault(t => t.Id == themeId); 213 if (themeUsage == null) continue; 214 215 if (Converter.ToInt32(rawData["AreaId"].ToString()) > 0) { themeUsage.WebsiteUsages.Add(Converter.ToInt32(rawData["AreaId"].ToString())); } 216 if (Converter.ToInt32(rawData["PageId"].ToString()) > 0) { themeUsage.PageUsages.Add(Converter.ToInt32(rawData["PageId"].ToString())); } 217 if (Converter.ToInt32(rawData["PagePropertiesId"].ToString()) > 0) { themeUsage.PagePropertyUsages.Add(Converter.ToInt32(rawData["PagePropertiesId"].ToString())); } 218 if (Converter.ToInt32(rawData["GridRowId"].ToString()) > 0) { themeUsage.GridRowUsages.Add(Converter.ToInt32(rawData["GridRowId"].ToString())); } 219 if (Converter.ToInt32(rawData["ParagraphId"].ToString()) > 0) { themeUsage.ParagraphUsages.Add(Converter.ToInt32(rawData["ParagraphId"].ToString())); } 220 } 221 } 222 223 private void UpdateAllUsages(List<ThemeUsage> themeUsages) 224 { 225 foreach (var themeUsage in themeUsages) 226 { 227 int websiteUsages = themeUsage?.WebsiteUsages.Count ?? 0; 228 int pageUsages = themeUsage?.PageUsages.Count ?? 0; 229 int pagePropertyUsages = themeUsage?.PagePropertyUsages.Count ?? 0; 230 int gridRowUsages = themeUsage?.GridRowUsages.Count ?? 0; 231 int paragraphUsages = themeUsage?.ParagraphUsages.Count ?? 0; 232 themeUsage.AllUsages = websiteUsages + pageUsages + pagePropertyUsages + gridRowUsages + paragraphUsages; 233 } 234 } 235 236 private ThemeUsage GetThemeUsageById(string themeId) 237 { 238 var themeUsages = GetAllThemeUsages(); 239 return themeUsages.FirstOrDefault(t => t.Id == themeId); 240 } 241 242 } 243 244 @{ 245 string themeName = !string.IsNullOrWhiteSpace(Model.Item.GetString("Name")) ? Model.Item.GetString("Name") : "Default"; 246 string themeClassName = !string.IsNullOrWhiteSpace(Model.Item.GetString("CSSClassName")) ? Model.Item.GetString("CSSClassName").Replace(" ", "").Trim().ToLower() : ""; 247 248 //Theme colors 249 string foregroundColor = Model.Item.GetString("ForegroundColor", "currentColor"); 250 string backgroundColor = Model.Item.GetString("BackgroundColor", "transparent"); 251 string accentColor = Model.Item.GetString("accentColor", "currentColor"); 252 string borderColor = Model.Item.GetString("BorderColor", "transparent"); 253 254 //Primary button 255 string buttonPrimaryForegroundColor = Model.Item.GetString("ButtonPrimaryForegroundColor", "currentColor"); 256 string buttonPrimaryBackgroundColor = Model.Item.GetString("ButtonPrimaryBackgroundColor", "transparent"); 257 string buttonPrimaryBorderColor = Model.Item.GetString("ButtonPrimaryBorderColor", "transparent"); 258 259 string buttonPrimaryHoverBackgroundColorAuto = "transparent"; 260 if (buttonPrimaryBackgroundColor != "transparent") 261 { 262 buttonPrimaryHoverBackgroundColorAuto = "hsl(" + GetColorVariation(buttonPrimaryBackgroundColor) + ")"; 263 } 264 string buttonPrimaryHoverForegroundColor = Model.Item.GetString("ButtonPrimaryHoverForegroundColor", buttonPrimaryForegroundColor); 265 string buttonPrimaryHoverBackgroundColor = Model.Item.GetString("ButtonPrimaryHoverBackgroundColor", buttonPrimaryHoverBackgroundColorAuto); 266 string buttonPrimaryHoverBorderColor = Model.Item.GetString("ButtonPrimaryHoverBorderColor", buttonPrimaryBorderColor); 267 268 //Secondary buton 269 string buttonSecondaryForegroundColor = Model.Item.GetString("ButtonSecondaryForegroundColor", "currentColor"); 270 string buttonSecondaryBackgroundColor = Model.Item.GetString("ButtonSecondaryBackgroundColor", "transparent"); 271 string buttonSecondaryBorderColor = Model.Item.GetString("ButtonSecondaryBorderColor", "transparent"); 272 273 string buttonSecondaryHoverBackgroundColorAuto = "transparent"; 274 if (buttonSecondaryBackgroundColor != "transparent") 275 { 276 buttonSecondaryHoverBackgroundColorAuto = "hsl(" + GetColorVariation(buttonSecondaryBackgroundColor) + ")"; 277 } 278 string buttonSecondaryHoverForegroundColor = Model.Item.GetString("ButtonSecondaryHoverForegroundColor", buttonSecondaryForegroundColor); 279 string buttonSecondaryHoverBackgroundColor = Model.Item.GetString("ButtonSecondaryHoverBackgroundColor", buttonSecondaryHoverBackgroundColorAuto); 280 string buttonSecondaryHoverBorderColor = Model.Item.GetString("ButtonSecondaryHoverBorderColor", buttonSecondaryBorderColor); 281 282 //Link buton 283 string buttonLinkColor = Model.Item.GetString("ButtonLinkColor", "currentColor"); 284 string buttonLinkHoverColorAuto = "currentColor"; 285 if (buttonLinkColor != "currentColor") 286 { 287 buttonLinkHoverColorAuto = "hsl(" + GetColorVariation(buttonLinkColor) + ")"; 288 } 289 string buttonLinkHoverColor = Model.Item.GetString("ButtonLinkHoverColor", buttonLinkHoverColorAuto); 290 291 string accessibilityOutlineColor = Model.Item.GetString("OutlineColor") != null ? Model.Item.GetString("OutlineColor") : ""; 292 293 if (!string.IsNullOrEmpty(themeClassName)) 294 { 295 var sb = new System.Text.StringBuilder(); 296 297 sb.AppendLine("." + themeClassName + "{"); 298 if (!string.IsNullOrEmpty(foregroundColor)) 299 { 300 sb.AppendLine($"--swift-foreground-color: {foregroundColor};"); 301 sb.AppendLine($"--swift-foreground-color-rgb: {HexToRGB(foregroundColor)};"); 302 } 303 if (!string.IsNullOrEmpty(backgroundColor)) 304 { 305 sb.AppendLine($"--swift-background-color: {backgroundColor};"); 306 sb.AppendLine($"--swift-background-color-rgb: {HexToRGB(backgroundColor)};"); 307 } 308 if (!string.IsNullOrEmpty(accentColor)) 309 { 310 sb.AppendLine($"--swift-accent-color: {accentColor};"); 311 sb.AppendLine($"--swift-accent-color-rgb: {HexToRGB(accentColor)};"); 312 } 313 if (!string.IsNullOrEmpty(borderColor)) 314 { 315 sb.AppendLine($"--swift-border-color: {borderColor};"); 316 sb.AppendLine($"--swift-border-color-rgb: {HexToRGB(borderColor)};"); 317 } 318 319 if (!string.IsNullOrEmpty(buttonPrimaryBackgroundColor)) 320 { 321 sb.AppendLine($"--swift-button-primary-background-color: {buttonPrimaryBackgroundColor};"); 322 sb.AppendLine($"--swift-button-primary-background-color-rgb: {HexToRGB(buttonPrimaryBackgroundColor)};"); 323 } 324 if (!string.IsNullOrEmpty(buttonPrimaryForegroundColor)) 325 { 326 sb.AppendLine($"--swift-button-primary-foreground-color: {buttonPrimaryForegroundColor};"); 327 sb.AppendLine($"--swift-button-primary-foreground-color-rgb: {HexToRGB(buttonPrimaryForegroundColor)};"); 328 } 329 if (!string.IsNullOrEmpty(buttonPrimaryBorderColor)) 330 { 331 sb.AppendLine($"--swift-button-primary-border-color: {buttonPrimaryBorderColor};"); 332 sb.AppendLine($"--swift-button-primary-border-color-rgb: {HexToRGB(buttonPrimaryBorderColor)};"); 333 } 334 335 if (!string.IsNullOrEmpty(buttonPrimaryHoverBackgroundColor)) 336 { 337 sb.AppendLine($"--swift-button-primary-hover-background-color: {buttonPrimaryHoverBackgroundColor};"); 338 sb.AppendLine($"--swift-button-primary-hover-background-color-rgb: {HexToRGB(buttonPrimaryHoverBackgroundColor)};"); 339 } 340 if (!string.IsNullOrEmpty(buttonPrimaryHoverForegroundColor)) 341 { 342 sb.AppendLine($"--swift-button-primary-hover-foreground-color: {buttonPrimaryHoverForegroundColor};"); 343 sb.AppendLine($"--swift-button-primary-hover-foreground-color-rgb: {HexToRGB(buttonPrimaryHoverForegroundColor)};"); 344 } 345 if (!string.IsNullOrEmpty(buttonPrimaryHoverBorderColor)) 346 { 347 sb.AppendLine($"--swift-button-primary-hover-border-color: {buttonPrimaryHoverBorderColor};"); 348 sb.AppendLine($"--swift-button-primary-hover-border-color-rgb: {HexToRGB(buttonPrimaryHoverBorderColor)};"); 349 } 350 351 if (!string.IsNullOrEmpty(buttonSecondaryBackgroundColor)) 352 { 353 sb.AppendLine($"--swift-button-secondary-background-color: {buttonSecondaryBackgroundColor};"); 354 sb.AppendLine($"--swift-button-secondary-background-color-rgb: {HexToRGB(buttonSecondaryBackgroundColor)};"); 355 } 356 if (!string.IsNullOrEmpty(buttonSecondaryForegroundColor)) 357 { 358 sb.AppendLine($"--swift-button-secondary-foreground-color: {buttonSecondaryForegroundColor};"); 359 sb.AppendLine($"--swift-button-secondary-foreground-color-rgb: {HexToRGB(buttonSecondaryForegroundColor)};"); 360 } 361 if (!string.IsNullOrEmpty(buttonSecondaryBorderColor)) 362 { 363 sb.AppendLine($"--swift-button-secondary-border-color: {buttonSecondaryBorderColor};"); 364 sb.AppendLine($"--swift-button-secondary-border-color-rgb: {HexToRGB(buttonSecondaryBorderColor)};"); 365 } 366 if (!string.IsNullOrEmpty(buttonSecondaryHoverBackgroundColor)) 367 { 368 sb.AppendLine($"--swift-button-secondary-hover-background-color: {buttonSecondaryHoverBackgroundColor};"); 369 sb.AppendLine($"--swift-button-secondary-hover-background-color-rgb: {HexToRGB(buttonSecondaryHoverBackgroundColor)};"); 370 } 371 if (!string.IsNullOrEmpty(buttonSecondaryHoverForegroundColor)) 372 { 373 sb.AppendLine($"--swift-button-secondary-hover-foreground-color: {buttonSecondaryHoverForegroundColor};"); 374 sb.AppendLine($"--swift-button-secondary-hover-foreground-color-rgb: {HexToRGB(buttonSecondaryHoverForegroundColor)};"); 375 } 376 if (!string.IsNullOrEmpty(buttonSecondaryHoverBorderColor)) 377 { 378 sb.AppendLine($"--swift-button-secondary-hover-border-color: {buttonSecondaryHoverBorderColor};"); 379 sb.AppendLine($"--swift-button-secondary-hover-border-color-rgb: {HexToRGB(buttonSecondaryHoverBorderColor)};"); 380 } 381 if (!string.IsNullOrEmpty(buttonLinkColor)) 382 { 383 sb.AppendLine($"--swift-button-link-color: {buttonLinkColor};"); 384 sb.AppendLine($"--swift-button-link-color-rgb: {HexToRGB(buttonLinkColor)};"); 385 } 386 if (!string.IsNullOrEmpty(buttonLinkHoverColor)) 387 { 388 sb.AppendLine($"--swift-button-link-hover-color: {buttonLinkHoverColor};"); 389 sb.AppendLine($"--swift-button-link-hover-color-rgb: {HexToRGB(buttonLinkHoverColor)};"); 390 } 391 if (!string.IsNullOrEmpty(accessibilityOutlineColor)) 392 { 393 sb.AppendLine($"--swift-a11y-outline-color: {accessibilityOutlineColor};"); 394 sb.AppendLine($"--swift-a11y-outline-color-rgb: {HexToRGB(accessibilityOutlineColor)};"); 395 } 396 sb.AppendLine("}"); 397 398 Dynamicweb.Core.Helpers.TextFileHelper.WriteTextFile(sb.ToString() + Environment.NewLine, Dynamicweb.Context.Current.Server.MapPath($"/Files/Templates/Designs/Swift/_parsed/Swift_css/Swift_theme_styles_{Dynamicweb.Content.Services.Pages.GetPage(Model.PageID).AreaId}.tmp"), true); 399 } 400 } 401 402 @if (themeClassName != "") 403 { 404 string iconPath = "/Files/Templates/Designs/Swift/Assets/icons/"; 405 406 <div class="g-col-12 g-col-lg-4"> 407 <div class="swift-checkered p-3"> 408 <div class="theme-option theme @themeClassName p-lg-3"> 409 <div class="mb-2 pb-1 border-bottom d-flex align-items-center"> 410 <span class="icon-3 me-2"> 411 @ReadFile(iconPath + "sun.svg") 412 </span> 413 <h4 class="m-0 p-0">@themeName</h4> 414 </div> 415 <div class="d-flex flex-column gap-1 mb-2"> 416 <p class="mb-0">This is the body text of the theme.</p> 417 <p class="mb-0" style="color: var(--swift-accent-color)">This is the accent color of the theme.</p> 418 </div> 419 <div> 420 <button class="btn btn-primary me-1">Primary</button> 421 <button class="btn btn-secondary">Secondary</button> 422 <button class="btn btn-link">Link</button> 423 </div> 424 </div> 425 </div> 426 </div> 427 <div class="g-col-12 g-col-lg-8 mb-4 mb-lg-0"> 428 <div class="grid fs-7"> 429 <div class="g-col-12 g-col-lg-3"> 430 <table class="table table-borderless table-sm w-100"> 431 <thead> 432 <tr> 433 <th colspan="2" class="fw-bold">@Translate("Base")</th> 434 </tr> 435 </thead> 436 <tr> 437 <td>@Translate("Foreground")</td> 438 <td>@GetColorSquare(foregroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@foregroundColor');">@foregroundColor</a></td> 439 </tr> 440 <tr> 441 <td>@Translate("Background")</td> 442 <td>@GetColorSquare(backgroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@backgroundColor');">@backgroundColor</a></td> 443 </tr> 444 <tr> 445 <td>@Translate("Accent")</td> 446 <td>@GetColorSquare(accentColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@accentColor');">@accentColor</a></td> 447 </tr> 448 <tr> 449 <td>@Translate("Border")</td> 450 <td>@GetColorSquare(borderColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@borderColor');">@borderColor</a></td> 451 </tr> 452 </table> 453 </div> 454 <div class="g-col-12 g-col-lg-3"> 455 <table class="table table-borderless table-sm w-100"> 456 <thead> 457 <tr> 458 <th colspan="2" class="fw-bold">@Translate("Primary button")</th> 459 </tr> 460 </thead> 461 <tr> 462 <td>@Translate("Foreground")</td> 463 <td>@GetColorSquare(buttonPrimaryForegroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonPrimaryForegroundColor');">@buttonPrimaryForegroundColor</a></td> 464 </tr> 465 <tr> 466 <td>@Translate("Background")</td> 467 <td>@GetColorSquare(buttonPrimaryBackgroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonPrimaryBackgroundColor');">@buttonPrimaryBackgroundColor</a></td> 468 </tr> 469 @if (!string.IsNullOrEmpty(buttonPrimaryBorderColor)) 470 { 471 <tr> 472 <td>@Translate("Border")</td> 473 <td>@GetColorSquare(buttonPrimaryBorderColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonPrimaryBorderColor');">@buttonPrimaryBorderColor</a></td> 474 </tr> 475 } 476 <thead> 477 <tr> 478 <th colspan="2" class="fw-bold">@Translate("Primary button hover")</th> 479 </tr> 480 </thead> 481 @if (!string.IsNullOrEmpty(buttonPrimaryHoverForegroundColor)) 482 { 483 <tr> 484 <td>@Translate("Foreground")</td> 485 <td>@GetColorSquare(buttonPrimaryHoverForegroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonPrimaryHoverForegroundColor');">@buttonPrimaryHoverForegroundColor</a></td> 486 </tr> 487 } 488 @if (!string.IsNullOrEmpty(buttonPrimaryHoverBackgroundColor)) 489 { 490 <tr> 491 <td>@Translate("Background")</td> 492 <td>@GetColorSquare(buttonPrimaryHoverBackgroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonPrimaryHoverBackgroundColor');">@buttonPrimaryHoverBackgroundColor</a></td> 493 </tr> 494 } 495 @if (!string.IsNullOrEmpty(buttonPrimaryHoverBorderColor)) 496 { 497 <tr> 498 <td>@Translate("Border")</td> 499 <td>@GetColorSquare(buttonPrimaryHoverBorderColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonPrimaryHoverBorderColor');">@buttonPrimaryHoverBorderColor</a></td> 500 </tr> 501 } 502 </table> 503 </div> 504 <div class="g-col-12 g-col-lg-3"> 505 <table class="table table-borderless table-sm w-100"> 506 <thead> 507 <tr> 508 <th colspan="2" class="fw-bold">@Translate("Secondary button")</th> 509 </tr> 510 </thead> 511 <tr> 512 <td>@Translate("Foreground")</td> 513 <td>@GetColorSquare(buttonSecondaryForegroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonSecondaryForegroundColor');">@buttonSecondaryForegroundColor</a></td> 514 </tr> 515 <tr> 516 <td>@Translate("Background")</td> 517 <td>@GetColorSquare(buttonSecondaryBackgroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonSecondaryBackgroundColor');">@buttonSecondaryBackgroundColor</a></td> 518 </tr> 519 @if (!string.IsNullOrEmpty(buttonSecondaryBorderColor)) 520 { 521 <tr> 522 <td>@Translate("Border")</td> 523 <td>@GetColorSquare(buttonSecondaryBorderColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonSecondaryBorderColor');">@buttonSecondaryBorderColor</a></td> 524 </tr> 525 } 526 <thead> 527 <tr> 528 <th colspan="2" class="fw-bold">@Translate("Secondary button hover")</th> 529 </tr> 530 </thead> 531 @if (!string.IsNullOrEmpty(buttonSecondaryHoverForegroundColor)) 532 { 533 <tr> 534 <td>@Translate("Foreground")</td> 535 <td>@GetColorSquare(buttonSecondaryHoverForegroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonSecondaryHoverForegroundColor');">@buttonSecondaryHoverForegroundColor</a></td> 536 </tr> 537 } 538 @if (!string.IsNullOrEmpty(buttonSecondaryHoverBackgroundColor)) 539 { 540 <tr> 541 <td>@Translate("Background")</td> 542 <td>@GetColorSquare(buttonSecondaryHoverBackgroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonSecondaryHoverBackgroundColor');">@buttonSecondaryHoverBackgroundColor</a></td> 543 </tr> 544 } 545 @if (!string.IsNullOrEmpty(buttonSecondaryHoverBorderColor)) 546 { 547 <tr> 548 <td>@Translate("Border")</td> 549 <td>@GetColorSquare(buttonSecondaryHoverBorderColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonSecondaryHoverBorderColor');">@buttonSecondaryHoverBorderColor</a></td> 550 </tr> 551 } 552 @if (!string.IsNullOrEmpty(accessibilityOutlineColor)) 553 { 554 <tr> 555 <td>@Translate("Focus outline")</td> 556 <td>@GetColorSquare(accessibilityOutlineColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@accessibilityOutlineColor');">@accessibilityOutlineColor</a></td> 557 </tr> 558 } 559 </table> 560 </div> 561 <div class="g-col-12 g-col-lg-3"> 562 <table class="table table-borderless table-sm w-100"> 563 <thead> 564 <tr> 565 <th colspan="2" class="fw-bold">@Translate("Link button")</th> 566 </tr> 567 </thead> 568 <tr> 569 <td>@Translate("Link color")</td> 570 <td>@GetColorSquare(buttonLinkColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonLinkColor');">@buttonLinkColor</a></td> 571 </tr> 572 <thead> 573 <tr> 574 <th colspan="2" class="fw-bold">@Translate("Link button hover")</th> 575 </tr> 576 </thead> 577 @if (!string.IsNullOrEmpty(buttonLinkHoverColor)) 578 { 579 <tr> 580 <td>@Translate("Link hover color")</td> 581 <td>@GetColorSquare(buttonLinkHoverColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonLinkHoverColor');">@buttonLinkHoverColor</a></td> 582 </tr> 583 } 584 585 @if (!string.IsNullOrEmpty(accessibilityOutlineColor)) 586 { 587 <tr> 588 <td>@Translate("Focus outline")</td> 589 <td>@GetColorSquare(accessibilityOutlineColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@accessibilityOutlineColor');">@accessibilityOutlineColor</a></td> 590 </tr> 591 } 592 </table> 593 </div> 594 <div class="g-col-12 g-col-lg-3"> 595 <table class="table table-borderless table-sm w-100"> 596 <tr> 597 <td class="fw-bold">@Translate("Implementation")</td> 598 </tr> 599 <tr> 600 <td> 601 @{ 602 string implementation = $"<div class=\"theme {themeClassName}\"></div>"; 603 } 604 <div class="text-muted"> 605 <code class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@themeClassName');"> 606 @Dynamicweb.Core.Encoders.HtmlEncoder.HtmlEncode(implementation) 607 </code> 608 </div> 609 </td> 610 </tr> 611 </table> 612 </div> 613 @{ 614 bool hasUsageData = Converter.ToBoolean(Dynamicweb.Context.Current.Request["auditUsages"]); 615 if (hasUsageData) 616 { 617 var themeUsage = GetThemeUsageById(themeClassName); 618 int allUsages = themeUsage?.AllUsages ?? 0; 619 string buttonAttributes = allUsages > 0 ? $"data-bs-toggle=\"modal\" data-bs-target=\"#themeUsage_{Model.ID}\"" : string.Empty; 620 string badgeStyle = allUsages > 0 ? "bg-success" : "bg-danger"; 621 622 <div class="g-col-12 g-col-lg-9 position-relative"> 623 <button type="button" class="btn btn-primary btn-sm position-absolute end-0" @buttonAttributes> 624 Usages 625 <span class="position-absolute top-0 start-100 translate-middle badge rounded-pill text-white @badgeStyle">@allUsages</span> 626 </button> 627 628 @if (allUsages > 0) 629 { 630 int websiteUsages = themeUsage?.WebsiteUsages.Count ?? 0; 631 int pageUsages = themeUsage?.PageUsages.Count ?? 0; 632 int pagePropertyUsages = themeUsage?.PagePropertyUsages.Count ?? 0; 633 int gridRowUsages = themeUsage?.GridRowUsages.Count ?? 0; 634 int paragraphUsages = themeUsage?.ParagraphUsages.Count ?? 0; 635 636 <!-- Modal --> 637 <div class="modal fade" id="themeUsage_@(Model.ID)" tabindex="-1" aria-labelledby="usagesModelLabel" aria-hidden="true"> 638 <div class="modal-dialog modal-xl modal-dialog-centered modal-dialog-scrollable"> 639 <div class="modal-content"> 640 <div class="modal-header"> 641 <h5 class="modal-title" id="usagesModelLabel">@allUsages Usages of '@(themeName)' (@(themeClassName))</h5> 642 <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> 643 </div> 644 <div class="modal-body"> 645 <div class="accordion" id="accordionWrapper"> 646 @if(websiteUsages > 0) 647 { 648 <div class="accordion-item"> 649 <h2 class="accordion-header" id="headingWebsites"> 650 <button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#collapseWebsites" aria-expanded="true" aria-controls="collapseWebsites"> 651 <span class="pe-2">Websites</span><span class="badge rounded-pill bg-secondary text-light">@websiteUsages</span> 652 </button> 653 </h2> 654 <div id="collapseWebsites" class="accordion-collapse collapse show" aria-labelledby="headingWebsites" data-bs-parent="#accordionWrapper"> 655 <div class="accordion-body"> 656 <ul> 657 @foreach (var usage in themeUsage.WebsiteUsages) 658 { 659 var website = Dynamicweb.Content.Services.Areas.GetArea(usage); 660 <li><span class="fw-bold">@website.Name</span>@($" (ID: {usage})")</li> 661 } 662 </ul> 663 </div> 664 </div> 665 </div> 666 } 667 @if (pageUsages > 0) 668 { 669 var pages = Dynamicweb.Content.Services.Pages.GetPages(themeUsage.PageUsages.ToArray()); 670 671 <div class="accordion-item"> 672 <h2 class="accordion-header" id="headingPages"> 673 <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapsePages" aria-expanded="false" aria-controls="collapsePages"> 674 <span class="pe-2">Pages</span><span class="badge rounded-pill bg-secondary text-light">@pageUsages</span> 675 </button> 676 </h2> 677 <div id="collapsePages" class="accordion-collapse collapse" aria-labelledby="headingPages" data-bs-parent="#accordionWrapper"> 678 <div class="accordion-body"> 679 <ul> 680 @foreach (var usage in themeUsage.PageUsages) 681 { 682 <li><span class="fw-bold">@pages.FirstOrDefault(p => p.ID == usage).GetDisplayName()</span>@($" (ID: {usage})")</li> 683 } 684 </ul> 685 </div> 686 </div> 687 </div> 688 } 689 @if (pagePropertyUsages > 0) 690 { 691 var pages = Dynamicweb.Content.Services.Pages.GetPages(themeUsage.PageUsages.ToArray()); 692 693 <div class="accordion-item"> 694 <h2 class="accordion-header" id="headingPageProperties"> 695 <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapsePageProperties" aria-expanded="false" aria-controls="collapsePageProperties"> 696 <span class="pe-2">Page Properties</span><span class="badge rounded-pill bg-secondary text-light">@pagePropertyUsages</span> 697 </button> 698 </h2> 699 <div id="collapsePageProperties" class="accordion-collapse collapse" aria-labelledby="headingPageProperties" data-bs-parent="#accordionWrapper"> 700 <div class="accordion-body"> 701 <ul> 702 @foreach (var usage in themeUsage.PagePropertyUsages) 703 { 704 <li><span class="fw-bold">@pages.FirstOrDefault(p => p.ID == usage).GetDisplayName()</span>@($" (ID: {usage})")</li> 705 } 706 </ul> 707 </div> 708 </div> 709 </div> 710 } 711 @if (gridRowUsages > 0) 712 { 713 var rows = Dynamicweb.Content.Services.Grids.GetGridRows().Where(r => themeUsage.GridRowUsages.Contains(r.ID)).ToList(); 714 715 <div class="accordion-item"> 716 <h2 class="accordion-header" id="headingRows"> 717 <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseRows" aria-expanded="false" aria-controls="collapseRows"> 718 <span class="pe-2">Rows</span><span class="badge rounded-pill bg-secondary text-light">@gridRowUsages</span> 719 </button> 720 </h2> 721 <div id="collapseRows" class="accordion-collapse collapse" aria-labelledby="headingRows" data-bs-parent="#accordionWrapper"> 722 <div class="accordion-body"> 723 <ul> 724 @foreach (var usage in themeUsage.GridRowUsages) 725 { 726 var row = rows.FirstOrDefault(r => r.ID == usage); 727 var page = Dynamicweb.Content.Services.Pages.GetPage(row.PageId); 728 <li>Page: <span class="fw-bold">@(page.GetDisplayName())</span>@($"( ID: {page.ID}) - Row: ")<span class="fw-bold">@(row.DefinitionId)</span>@($" (ID: {usage})")</li> 729 } 730 </ul> 731 </div> 732 </div> 733 </div> 734 } 735 @if (paragraphUsages > 0) 736 { 737 var paragraphs = Dynamicweb.Content.Services.Paragraphs.GetParagraphs().Where(p => themeUsage.ParagraphUsages.Contains(p.ID)).ToList(); 738 739 <div class="accordion-item"> 740 <h2 class="accordion-header" id="headingParagraphs"> 741 <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseParagraphs" aria-expanded="false" aria-controls="collapseParagraphs"> 742 <span class="pe-2">Paragraphs</span><span class="badge rounded-pill bg-secondary text-light">@paragraphUsages</span> 743 </button> 744 </h2> 745 <div id="collapseParagraphs" class="accordion-collapse collapse" aria-labelledby="headingParagraphs" data-bs-parent="#accordionWrapper"> 746 <div class="accordion-body"> 747 <ul> 748 @foreach (var usage in themeUsage.ParagraphUsages) 749 { 750 var paragraph = paragraphs.FirstOrDefault(p => p.ID == usage); 751 var page = Dynamicweb.Content.Services.Pages.GetPage(paragraph.PageID); 752 <li>Page: <span class="fw-bold">@(page.GetDisplayName())</span>@($"( ID: {page.ID}) - Paragraph: ")<span class="fw-bold">@paragraph.Header</span>@($" (ID: {usage})")</li> 753 } 754 </ul> 755 </div> 756 </div> 757 </div> 758 } 759 </div> 760 </div> 761 </div> 762 </div> 763 </div> 764 } 765 </div> 766 } 767 } 768 </div> 769 </div> 770 } 771 <div class="g-col-12"> 772 <hr /> 773 </div> 774
Error executing template "Designs/Swift/Paragraph/Swift_Theme.cshtml" System.Data.SqlClient.SqlException (0x80131904): STRING_AGG aggregation result exceeded the limit of 8000 bytes. Use LOB types to avoid result truncation. at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction) at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose) at System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady) at System.Data.SqlClient.SqlDataReader.TryConsumeMetaData() at System.Data.SqlClient.SqlDataReader.get_MetaData() at System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString, Boolean isInternal, Boolean forDescribeParameterEncryption, Boolean shouldCacheForAlwaysEncrypted) at System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async, Int32 timeout, Task& task, Boolean asyncWrite, Boolean inRetry, SqlDataReader ds, Boolean describeParameterEncryptionRequest) at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, TaskCompletionSource`1 completion, Int32 timeout, Task& task, Boolean& usedCache, Boolean asyncWrite, Boolean inRetry) at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method) at System.Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior behavior, String method) at Dynamicweb.Data.Database.CreateDataReader(IDbCommand command, CommandBehavior behavior) at Dynamicweb.Data.Database.CreateDataReader(String sql, IDbConnection connection, IDbTransaction transaction, CommandBehavior behavior, Int32 commandTimeout, Dictionary`2 sqlParams) at Dynamicweb.Data.Database.CreateDataReader(String sql, IDbConnection connection, IDbTransaction transaction, Int32 commandTimeout, Dictionary`2 sqlParams) at Dynamicweb.Data.Database.CreateDataReader(String sql) at CompiledRazorTemplates.Dynamic.RazorEngine_8e3f1b11eb0041ceb2ca487c2be837e6.UpdateThemeUsages(String sqlQuery, List`1 themeUsages) in E:\Dynamicweb.net\Solutions\Dynamicweb\dw2022.cloud.dynamicweb-cms.com\Files\Templates\Designs\Swift\Paragraph\Swift_Theme.cshtml:line 202 at CompiledRazorTemplates.Dynamic.RazorEngine_8e3f1b11eb0041ceb2ca487c2be837e6.GetAllThemeUsages() in E:\Dynamicweb.net\Solutions\Dynamicweb\dw2022.cloud.dynamicweb-cms.com\Files\Templates\Designs\Swift\Paragraph\Swift_Theme.cshtml:line 184 at CompiledRazorTemplates.Dynamic.RazorEngine_8e3f1b11eb0041ceb2ca487c2be837e6.GetThemeUsageById(String themeId) in E:\Dynamicweb.net\Solutions\Dynamicweb\dw2022.cloud.dynamicweb-cms.com\Files\Templates\Designs\Swift\Paragraph\Swift_Theme.cshtml:line 238 at CompiledRazorTemplates.Dynamic.RazorEngine_8e3f1b11eb0041ceb2ca487c2be837e6.Execute() in E:\Dynamicweb.net\Solutions\Dynamicweb\dw2022.cloud.dynamicweb-cms.com\Files\Templates\Designs\Swift\Paragraph\Swift_Theme.cshtml:line 617 at RazorEngine.Templating.TemplateBase.RazorEngine.Templating.ITemplate.Run(ExecuteContext context, TextWriter reader) at RazorEngine.Templating.RazorEngineService.RunCompile(ITemplateKey key, TextWriter writer, Type modelType, Object model, DynamicViewBag viewBag) at RazorEngine.Templating.RazorEngineServiceExtensions.<>c__DisplayClass16_0.<RunCompile>b__0(TextWriter writer) at RazorEngine.Templating.RazorEngineServiceExtensions.WithWriter(Action`1 withWriter) at Dynamicweb.Rendering.RazorTemplateRenderingProvider.Render(Template template) at Dynamicweb.Rendering.TemplateRenderingService.Render(Template template) at Dynamicweb.Rendering.Template.RenderRazorTemplate() ClientConnectionId:b42d1cec-597c-4eed-bdc2-e0762a41101a Error Number:9829,State:1,Class:16
1 @inherits Dynamicweb.Rendering.ViewModelTemplate<Dynamicweb.Frontend.ParagraphViewModel> 2 @using System.Globalization 3 @using System.Drawing 4 @using Dynamicweb.Core 5 6 @functions{ 7 // Get Hex Color from color picker and translate to RGB color 8 public static string HexToRGB(string hexString) 9 { 10 if (hexString.Equals("none") || string.IsNullOrEmpty(hexString)) 11 return hexString; 12 13 //replace # occurences 14 if (hexString.IndexOf('#') != -1) 15 hexString = hexString.Replace("#", ""); 16 try 17 { 18 int r, g, b = 0; 19 r = int.Parse(hexString.Substring(0, 2), NumberStyles.AllowHexSpecifier); 20 g = int.Parse(hexString.Substring(2, 2), NumberStyles.AllowHexSpecifier); 21 b = int.Parse(hexString.Substring(4, 2), NumberStyles.AllowHexSpecifier); 22 23 string rgb = r + "," + g + "," + b; 24 return rgb; 25 } 26 catch (System.Exception) 27 { 28 return hexString; 29 } 30 } 31 32 public static string GetColorSquare(string hex) 33 { 34 return $"<div class=\"swift-checkered d-inline-block me-1\" style=\"height:1.25rem;width:1.25rem;\"><div style=\"background-color: {hex};border:.0625rem solid grey\" class=\"w-100 h-100\"></div></div>"; 35 } 36 37 public class HSL 38 { 39 public double h { get; set; } 40 public double s { get; set; } 41 public double l { get; set; } 42 } 43 44 //Convert HEX to HSL 45 public static HSL HexToHsl(string hexString) 46 { 47 System.Drawing.Color color = System.Drawing.ColorTranslator.FromHtml(hexString); 48 49 float _R = (color.R / 255f); 50 float _G = (color.G / 255f); 51 float _B = (color.B / 255f); 52 53 float _Min = Math.Min(Math.Min(_R, _G), _B); 54 float _Max = Math.Max(Math.Max(_R, _G), _B); 55 float _Delta = _Max - _Min; 56 57 float S = 0; 58 float L = (float)((_Max + _Min) / 2.0f); 59 60 if (_Delta != 0) 61 { 62 if (L < 0.5f) 63 { 64 S = (float)(_Delta / (_Max + _Min)); 65 } 66 else 67 { 68 S = (float)(_Delta / (2.0f - _Max - _Min)); 69 } 70 } 71 72 HSL hsl = new HSL(); 73 hsl.h = Math.Round(color.GetHue(), 2); 74 hsl.s = Math.Round(S, 2) * 100; 75 hsl.l = Math.Round(L, 2) * 100; 76 77 return hsl; 78 } 79 80 //Find contrast color (white, black) 81 public static Color GetContrastColor(string hexString) 82 { 83 System.Drawing.Color bg = System.Drawing.ColorTranslator.FromHtml(hexString); 84 85 int nThreshold = 105; 86 int bgDelta = Convert.ToInt32((bg.R * 0.299) + (bg.G * 0.587) + 87 (bg.B * 0.114)); 88 89 Color foreColor = (255 - bgDelta < nThreshold) ? Color.Black : Color.White; 90 return foreColor; 91 } 92 93 public string GetColorVariation(string hexString) 94 { 95 var contrast = GetContrastColor(hexString); 96 HSL currentHslColor = HexToHsl(hexString); 97 HSL variantHslColor = currentHslColor; 98 99 if (contrast == Color.Black) 100 { 101 variantHslColor.l = 85; //The background is dark - Color should be light 102 } 103 else 104 { 105 variantHslColor.l = 40; //The background is light - Color should be less light 106 } 107 108 //Color is very light 109 if (currentHslColor.l > 85) 110 { 111 variantHslColor.l = 95; 112 } 113 114 string colorString = variantHslColor.h + ", " + variantHslColor.s + "%, " + variantHslColor.l + "%"; 115 return colorString; 116 } 117 118 private class ThemeDatabaseUsage 119 { 120 public string TableName { get; set; } 121 public string ColumnName { get; set; } 122 } 123 124 private class ThemeUsage 125 { 126 public string Id { get; set; } 127 public List<int> WebsiteUsages { get; set; } = new List<int>(); 128 public List<int> PageUsages { get; set; } = new List<int>(); 129 public List<int> PagePropertyUsages { get; set; } = new List<int>(); 130 public List<int> GridRowUsages { get; set; } = new List<int>(); 131 public List<int> ParagraphUsages { get; set; } = new List<int>(); 132 public int AllUsages { get; set; } = 0; 133 } 134 135 private List<ThemeDatabaseUsage> GetThemeColumnsFromSchema() 136 { 137 string cacheKey = "ThemesFromDatabase"; 138 if (Dynamicweb.Context.Current.Items.Contains(cacheKey)) 139 { 140 return (List<ThemeDatabaseUsage>)Dynamicweb.Context.Current.Items[cacheKey]; 141 } 142 var schema = Dynamicweb.Data.Database.CreateDataReader("SELECT table_name, column_name FROM information_schema.columns WHERE column_name LIKE '%Theme%'"); 143 144 var rawData = new List<ThemeDatabaseUsage>(); 145 while (schema.Read()) { 146 rawData.Add(new ThemeDatabaseUsage {TableName = schema["table_name"].ToString(), ColumnName = schema["column_name"].ToString() }); 147 } 148 Dynamicweb.Context.Current.Items[cacheKey] = rawData; 149 return rawData; 150 } 151 152 private List<ThemeUsage> GetAllThemeUsages() 153 { 154 string cacheKey = "ThemeUsages"; 155 if (Dynamicweb.Context.Current.Items.Contains(cacheKey)) 156 { 157 return (List<ThemeUsage>)Dynamicweb.Context.Current.Items[cacheKey]; 158 } 159 160 var rawData = GetThemeColumnsFromSchema(); 161 var themeUsages = new List<ThemeUsage>(); 162 163 var sqlQuery = ""; 164 foreach (var row in rawData) 165 { 166 if (!string.IsNullOrEmpty(sqlQuery)) { sqlQuery += " UNION ALL "; } 167 sqlQuery += $"SELECT '{row.TableName}' AS TableName, '{row.ColumnName}' AS ColumnName, {row.ColumnName} AS ColumnValue, Id, AreaId, Page.PageId, PageProperties.PageId as 'PagePropertiesId', GridRowId, ParagraphId" + 168 $" FROM [{row.TableName}]" + 169 $" LEFT JOIN Area ON AreaItemType = '{row.TableName.Replace("ItemType_","")}' AND AreaItemId = Id" + 170 $" LEFT JOIN Page ON PageItemType = '{row.TableName.Replace("ItemType_","")}' AND PageItemId = Id" + 171 $" LEFT JOIN Page as PageProperties ON AreaItemTypePageProperty = '{row.TableName.Replace("ItemType_","")}' AND PageProperties.PagePropertyItemId = Id" + 172 $" LEFT JOIN GridRow ON GridRowItemType = '{row.TableName.Replace("ItemType_","")}' AND GridRowItemId = Id" + 173 $" LEFT JOIN Paragraph ON ParagraphItemType = '{row.TableName.Replace("ItemType_","")}' AND ParagraphItemId = Id" + 174 $" WHERE {row.ColumnName} != '' AND {row.ColumnName} IS NOT NULL" + 175 $" AND (AreaId IS NULL OR AreaId = {Pageview.AreaID})" + 176 $" AND (Page.PageId IS NULL OR Page.PageAreaId = {Pageview.AreaID})" + 177 $" AND (PageProperties.PageId IS NULL OR PageProperties.PageAreaId = {Pageview.AreaID})" + 178 $" AND (GridRowId IS NULL OR GridRowPageId IN (SELECT value From string_split(@pageIds, ',')))" + 179 $" AND (ParagraphId IS NULL OR ParagraphPageId IN (SELECT value From string_split(@pageIds, ',')))"; 180 181 var maxMsSqlServerCharLimit = 60000; 182 if (sqlQuery.Length > maxMsSqlServerCharLimit) 183 { 184 UpdateThemeUsages(sqlQuery, themeUsages); 185 sqlQuery = ""; 186 } 187 } 188 189 if (!string.IsNullOrEmpty(sqlQuery)) 190 { 191 UpdateThemeUsages(sqlQuery, themeUsages); 192 } 193 UpdateAllUsages(themeUsages); 194 195 Dynamicweb.Context.Current.Items[cacheKey] = themeUsages; 196 return themeUsages; 197 } 198 199 private void UpdateThemeUsages(string sqlQuery, List<ThemeUsage> themeUsages) 200 { 201 sqlQuery = $"DECLARE @pageIds NVARCHAR(max) = (SELECT STRING_AGG(PageId,',') FROM Page WHERE PageAreaId = {Pageview.AreaID}) " + sqlQuery; 202 var rawData = Dynamicweb.Data.Database.CreateDataReader(sqlQuery); 203 while (rawData.Read()) 204 { 205 var themeId = rawData["ColumnValue"].ToString(); 206 var themeUsageExists = themeUsages.FirstOrDefault(t => t.Id == themeId) != null; 207 if (!themeUsageExists) 208 { 209 themeUsages.Add(new ThemeUsage { Id = themeId }); 210 } 211 212 var themeUsage = themeUsages.FirstOrDefault(t => t.Id == themeId); 213 if (themeUsage == null) continue; 214 215 if (Converter.ToInt32(rawData["AreaId"].ToString()) > 0) { themeUsage.WebsiteUsages.Add(Converter.ToInt32(rawData["AreaId"].ToString())); } 216 if (Converter.ToInt32(rawData["PageId"].ToString()) > 0) { themeUsage.PageUsages.Add(Converter.ToInt32(rawData["PageId"].ToString())); } 217 if (Converter.ToInt32(rawData["PagePropertiesId"].ToString()) > 0) { themeUsage.PagePropertyUsages.Add(Converter.ToInt32(rawData["PagePropertiesId"].ToString())); } 218 if (Converter.ToInt32(rawData["GridRowId"].ToString()) > 0) { themeUsage.GridRowUsages.Add(Converter.ToInt32(rawData["GridRowId"].ToString())); } 219 if (Converter.ToInt32(rawData["ParagraphId"].ToString()) > 0) { themeUsage.ParagraphUsages.Add(Converter.ToInt32(rawData["ParagraphId"].ToString())); } 220 } 221 } 222 223 private void UpdateAllUsages(List<ThemeUsage> themeUsages) 224 { 225 foreach (var themeUsage in themeUsages) 226 { 227 int websiteUsages = themeUsage?.WebsiteUsages.Count ?? 0; 228 int pageUsages = themeUsage?.PageUsages.Count ?? 0; 229 int pagePropertyUsages = themeUsage?.PagePropertyUsages.Count ?? 0; 230 int gridRowUsages = themeUsage?.GridRowUsages.Count ?? 0; 231 int paragraphUsages = themeUsage?.ParagraphUsages.Count ?? 0; 232 themeUsage.AllUsages = websiteUsages + pageUsages + pagePropertyUsages + gridRowUsages + paragraphUsages; 233 } 234 } 235 236 private ThemeUsage GetThemeUsageById(string themeId) 237 { 238 var themeUsages = GetAllThemeUsages(); 239 return themeUsages.FirstOrDefault(t => t.Id == themeId); 240 } 241 242 } 243 244 @{ 245 string themeName = !string.IsNullOrWhiteSpace(Model.Item.GetString("Name")) ? Model.Item.GetString("Name") : "Default"; 246 string themeClassName = !string.IsNullOrWhiteSpace(Model.Item.GetString("CSSClassName")) ? Model.Item.GetString("CSSClassName").Replace(" ", "").Trim().ToLower() : ""; 247 248 //Theme colors 249 string foregroundColor = Model.Item.GetString("ForegroundColor", "currentColor"); 250 string backgroundColor = Model.Item.GetString("BackgroundColor", "transparent"); 251 string accentColor = Model.Item.GetString("accentColor", "currentColor"); 252 string borderColor = Model.Item.GetString("BorderColor", "transparent"); 253 254 //Primary button 255 string buttonPrimaryForegroundColor = Model.Item.GetString("ButtonPrimaryForegroundColor", "currentColor"); 256 string buttonPrimaryBackgroundColor = Model.Item.GetString("ButtonPrimaryBackgroundColor", "transparent"); 257 string buttonPrimaryBorderColor = Model.Item.GetString("ButtonPrimaryBorderColor", "transparent"); 258 259 string buttonPrimaryHoverBackgroundColorAuto = "transparent"; 260 if (buttonPrimaryBackgroundColor != "transparent") 261 { 262 buttonPrimaryHoverBackgroundColorAuto = "hsl(" + GetColorVariation(buttonPrimaryBackgroundColor) + ")"; 263 } 264 string buttonPrimaryHoverForegroundColor = Model.Item.GetString("ButtonPrimaryHoverForegroundColor", buttonPrimaryForegroundColor); 265 string buttonPrimaryHoverBackgroundColor = Model.Item.GetString("ButtonPrimaryHoverBackgroundColor", buttonPrimaryHoverBackgroundColorAuto); 266 string buttonPrimaryHoverBorderColor = Model.Item.GetString("ButtonPrimaryHoverBorderColor", buttonPrimaryBorderColor); 267 268 //Secondary buton 269 string buttonSecondaryForegroundColor = Model.Item.GetString("ButtonSecondaryForegroundColor", "currentColor"); 270 string buttonSecondaryBackgroundColor = Model.Item.GetString("ButtonSecondaryBackgroundColor", "transparent"); 271 string buttonSecondaryBorderColor = Model.Item.GetString("ButtonSecondaryBorderColor", "transparent"); 272 273 string buttonSecondaryHoverBackgroundColorAuto = "transparent"; 274 if (buttonSecondaryBackgroundColor != "transparent") 275 { 276 buttonSecondaryHoverBackgroundColorAuto = "hsl(" + GetColorVariation(buttonSecondaryBackgroundColor) + ")"; 277 } 278 string buttonSecondaryHoverForegroundColor = Model.Item.GetString("ButtonSecondaryHoverForegroundColor", buttonSecondaryForegroundColor); 279 string buttonSecondaryHoverBackgroundColor = Model.Item.GetString("ButtonSecondaryHoverBackgroundColor", buttonSecondaryHoverBackgroundColorAuto); 280 string buttonSecondaryHoverBorderColor = Model.Item.GetString("ButtonSecondaryHoverBorderColor", buttonSecondaryBorderColor); 281 282 //Link buton 283 string buttonLinkColor = Model.Item.GetString("ButtonLinkColor", "currentColor"); 284 string buttonLinkHoverColorAuto = "currentColor"; 285 if (buttonLinkColor != "currentColor") 286 { 287 buttonLinkHoverColorAuto = "hsl(" + GetColorVariation(buttonLinkColor) + ")"; 288 } 289 string buttonLinkHoverColor = Model.Item.GetString("ButtonLinkHoverColor", buttonLinkHoverColorAuto); 290 291 string accessibilityOutlineColor = Model.Item.GetString("OutlineColor") != null ? Model.Item.GetString("OutlineColor") : ""; 292 293 if (!string.IsNullOrEmpty(themeClassName)) 294 { 295 var sb = new System.Text.StringBuilder(); 296 297 sb.AppendLine("." + themeClassName + "{"); 298 if (!string.IsNullOrEmpty(foregroundColor)) 299 { 300 sb.AppendLine($"--swift-foreground-color: {foregroundColor};"); 301 sb.AppendLine($"--swift-foreground-color-rgb: {HexToRGB(foregroundColor)};"); 302 } 303 if (!string.IsNullOrEmpty(backgroundColor)) 304 { 305 sb.AppendLine($"--swift-background-color: {backgroundColor};"); 306 sb.AppendLine($"--swift-background-color-rgb: {HexToRGB(backgroundColor)};"); 307 } 308 if (!string.IsNullOrEmpty(accentColor)) 309 { 310 sb.AppendLine($"--swift-accent-color: {accentColor};"); 311 sb.AppendLine($"--swift-accent-color-rgb: {HexToRGB(accentColor)};"); 312 } 313 if (!string.IsNullOrEmpty(borderColor)) 314 { 315 sb.AppendLine($"--swift-border-color: {borderColor};"); 316 sb.AppendLine($"--swift-border-color-rgb: {HexToRGB(borderColor)};"); 317 } 318 319 if (!string.IsNullOrEmpty(buttonPrimaryBackgroundColor)) 320 { 321 sb.AppendLine($"--swift-button-primary-background-color: {buttonPrimaryBackgroundColor};"); 322 sb.AppendLine($"--swift-button-primary-background-color-rgb: {HexToRGB(buttonPrimaryBackgroundColor)};"); 323 } 324 if (!string.IsNullOrEmpty(buttonPrimaryForegroundColor)) 325 { 326 sb.AppendLine($"--swift-button-primary-foreground-color: {buttonPrimaryForegroundColor};"); 327 sb.AppendLine($"--swift-button-primary-foreground-color-rgb: {HexToRGB(buttonPrimaryForegroundColor)};"); 328 } 329 if (!string.IsNullOrEmpty(buttonPrimaryBorderColor)) 330 { 331 sb.AppendLine($"--swift-button-primary-border-color: {buttonPrimaryBorderColor};"); 332 sb.AppendLine($"--swift-button-primary-border-color-rgb: {HexToRGB(buttonPrimaryBorderColor)};"); 333 } 334 335 if (!string.IsNullOrEmpty(buttonPrimaryHoverBackgroundColor)) 336 { 337 sb.AppendLine($"--swift-button-primary-hover-background-color: {buttonPrimaryHoverBackgroundColor};"); 338 sb.AppendLine($"--swift-button-primary-hover-background-color-rgb: {HexToRGB(buttonPrimaryHoverBackgroundColor)};"); 339 } 340 if (!string.IsNullOrEmpty(buttonPrimaryHoverForegroundColor)) 341 { 342 sb.AppendLine($"--swift-button-primary-hover-foreground-color: {buttonPrimaryHoverForegroundColor};"); 343 sb.AppendLine($"--swift-button-primary-hover-foreground-color-rgb: {HexToRGB(buttonPrimaryHoverForegroundColor)};"); 344 } 345 if (!string.IsNullOrEmpty(buttonPrimaryHoverBorderColor)) 346 { 347 sb.AppendLine($"--swift-button-primary-hover-border-color: {buttonPrimaryHoverBorderColor};"); 348 sb.AppendLine($"--swift-button-primary-hover-border-color-rgb: {HexToRGB(buttonPrimaryHoverBorderColor)};"); 349 } 350 351 if (!string.IsNullOrEmpty(buttonSecondaryBackgroundColor)) 352 { 353 sb.AppendLine($"--swift-button-secondary-background-color: {buttonSecondaryBackgroundColor};"); 354 sb.AppendLine($"--swift-button-secondary-background-color-rgb: {HexToRGB(buttonSecondaryBackgroundColor)};"); 355 } 356 if (!string.IsNullOrEmpty(buttonSecondaryForegroundColor)) 357 { 358 sb.AppendLine($"--swift-button-secondary-foreground-color: {buttonSecondaryForegroundColor};"); 359 sb.AppendLine($"--swift-button-secondary-foreground-color-rgb: {HexToRGB(buttonSecondaryForegroundColor)};"); 360 } 361 if (!string.IsNullOrEmpty(buttonSecondaryBorderColor)) 362 { 363 sb.AppendLine($"--swift-button-secondary-border-color: {buttonSecondaryBorderColor};"); 364 sb.AppendLine($"--swift-button-secondary-border-color-rgb: {HexToRGB(buttonSecondaryBorderColor)};"); 365 } 366 if (!string.IsNullOrEmpty(buttonSecondaryHoverBackgroundColor)) 367 { 368 sb.AppendLine($"--swift-button-secondary-hover-background-color: {buttonSecondaryHoverBackgroundColor};"); 369 sb.AppendLine($"--swift-button-secondary-hover-background-color-rgb: {HexToRGB(buttonSecondaryHoverBackgroundColor)};"); 370 } 371 if (!string.IsNullOrEmpty(buttonSecondaryHoverForegroundColor)) 372 { 373 sb.AppendLine($"--swift-button-secondary-hover-foreground-color: {buttonSecondaryHoverForegroundColor};"); 374 sb.AppendLine($"--swift-button-secondary-hover-foreground-color-rgb: {HexToRGB(buttonSecondaryHoverForegroundColor)};"); 375 } 376 if (!string.IsNullOrEmpty(buttonSecondaryHoverBorderColor)) 377 { 378 sb.AppendLine($"--swift-button-secondary-hover-border-color: {buttonSecondaryHoverBorderColor};"); 379 sb.AppendLine($"--swift-button-secondary-hover-border-color-rgb: {HexToRGB(buttonSecondaryHoverBorderColor)};"); 380 } 381 if (!string.IsNullOrEmpty(buttonLinkColor)) 382 { 383 sb.AppendLine($"--swift-button-link-color: {buttonLinkColor};"); 384 sb.AppendLine($"--swift-button-link-color-rgb: {HexToRGB(buttonLinkColor)};"); 385 } 386 if (!string.IsNullOrEmpty(buttonLinkHoverColor)) 387 { 388 sb.AppendLine($"--swift-button-link-hover-color: {buttonLinkHoverColor};"); 389 sb.AppendLine($"--swift-button-link-hover-color-rgb: {HexToRGB(buttonLinkHoverColor)};"); 390 } 391 if (!string.IsNullOrEmpty(accessibilityOutlineColor)) 392 { 393 sb.AppendLine($"--swift-a11y-outline-color: {accessibilityOutlineColor};"); 394 sb.AppendLine($"--swift-a11y-outline-color-rgb: {HexToRGB(accessibilityOutlineColor)};"); 395 } 396 sb.AppendLine("}"); 397 398 Dynamicweb.Core.Helpers.TextFileHelper.WriteTextFile(sb.ToString() + Environment.NewLine, Dynamicweb.Context.Current.Server.MapPath($"/Files/Templates/Designs/Swift/_parsed/Swift_css/Swift_theme_styles_{Dynamicweb.Content.Services.Pages.GetPage(Model.PageID).AreaId}.tmp"), true); 399 } 400 } 401 402 @if (themeClassName != "") 403 { 404 string iconPath = "/Files/Templates/Designs/Swift/Assets/icons/"; 405 406 <div class="g-col-12 g-col-lg-4"> 407 <div class="swift-checkered p-3"> 408 <div class="theme-option theme @themeClassName p-lg-3"> 409 <div class="mb-2 pb-1 border-bottom d-flex align-items-center"> 410 <span class="icon-3 me-2"> 411 @ReadFile(iconPath + "sun.svg") 412 </span> 413 <h4 class="m-0 p-0">@themeName</h4> 414 </div> 415 <div class="d-flex flex-column gap-1 mb-2"> 416 <p class="mb-0">This is the body text of the theme.</p> 417 <p class="mb-0" style="color: var(--swift-accent-color)">This is the accent color of the theme.</p> 418 </div> 419 <div> 420 <button class="btn btn-primary me-1">Primary</button> 421 <button class="btn btn-secondary">Secondary</button> 422 <button class="btn btn-link">Link</button> 423 </div> 424 </div> 425 </div> 426 </div> 427 <div class="g-col-12 g-col-lg-8 mb-4 mb-lg-0"> 428 <div class="grid fs-7"> 429 <div class="g-col-12 g-col-lg-3"> 430 <table class="table table-borderless table-sm w-100"> 431 <thead> 432 <tr> 433 <th colspan="2" class="fw-bold">@Translate("Base")</th> 434 </tr> 435 </thead> 436 <tr> 437 <td>@Translate("Foreground")</td> 438 <td>@GetColorSquare(foregroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@foregroundColor');">@foregroundColor</a></td> 439 </tr> 440 <tr> 441 <td>@Translate("Background")</td> 442 <td>@GetColorSquare(backgroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@backgroundColor');">@backgroundColor</a></td> 443 </tr> 444 <tr> 445 <td>@Translate("Accent")</td> 446 <td>@GetColorSquare(accentColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@accentColor');">@accentColor</a></td> 447 </tr> 448 <tr> 449 <td>@Translate("Border")</td> 450 <td>@GetColorSquare(borderColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@borderColor');">@borderColor</a></td> 451 </tr> 452 </table> 453 </div> 454 <div class="g-col-12 g-col-lg-3"> 455 <table class="table table-borderless table-sm w-100"> 456 <thead> 457 <tr> 458 <th colspan="2" class="fw-bold">@Translate("Primary button")</th> 459 </tr> 460 </thead> 461 <tr> 462 <td>@Translate("Foreground")</td> 463 <td>@GetColorSquare(buttonPrimaryForegroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonPrimaryForegroundColor');">@buttonPrimaryForegroundColor</a></td> 464 </tr> 465 <tr> 466 <td>@Translate("Background")</td> 467 <td>@GetColorSquare(buttonPrimaryBackgroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonPrimaryBackgroundColor');">@buttonPrimaryBackgroundColor</a></td> 468 </tr> 469 @if (!string.IsNullOrEmpty(buttonPrimaryBorderColor)) 470 { 471 <tr> 472 <td>@Translate("Border")</td> 473 <td>@GetColorSquare(buttonPrimaryBorderColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonPrimaryBorderColor');">@buttonPrimaryBorderColor</a></td> 474 </tr> 475 } 476 <thead> 477 <tr> 478 <th colspan="2" class="fw-bold">@Translate("Primary button hover")</th> 479 </tr> 480 </thead> 481 @if (!string.IsNullOrEmpty(buttonPrimaryHoverForegroundColor)) 482 { 483 <tr> 484 <td>@Translate("Foreground")</td> 485 <td>@GetColorSquare(buttonPrimaryHoverForegroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonPrimaryHoverForegroundColor');">@buttonPrimaryHoverForegroundColor</a></td> 486 </tr> 487 } 488 @if (!string.IsNullOrEmpty(buttonPrimaryHoverBackgroundColor)) 489 { 490 <tr> 491 <td>@Translate("Background")</td> 492 <td>@GetColorSquare(buttonPrimaryHoverBackgroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonPrimaryHoverBackgroundColor');">@buttonPrimaryHoverBackgroundColor</a></td> 493 </tr> 494 } 495 @if (!string.IsNullOrEmpty(buttonPrimaryHoverBorderColor)) 496 { 497 <tr> 498 <td>@Translate("Border")</td> 499 <td>@GetColorSquare(buttonPrimaryHoverBorderColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonPrimaryHoverBorderColor');">@buttonPrimaryHoverBorderColor</a></td> 500 </tr> 501 } 502 </table> 503 </div> 504 <div class="g-col-12 g-col-lg-3"> 505 <table class="table table-borderless table-sm w-100"> 506 <thead> 507 <tr> 508 <th colspan="2" class="fw-bold">@Translate("Secondary button")</th> 509 </tr> 510 </thead> 511 <tr> 512 <td>@Translate("Foreground")</td> 513 <td>@GetColorSquare(buttonSecondaryForegroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonSecondaryForegroundColor');">@buttonSecondaryForegroundColor</a></td> 514 </tr> 515 <tr> 516 <td>@Translate("Background")</td> 517 <td>@GetColorSquare(buttonSecondaryBackgroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonSecondaryBackgroundColor');">@buttonSecondaryBackgroundColor</a></td> 518 </tr> 519 @if (!string.IsNullOrEmpty(buttonSecondaryBorderColor)) 520 { 521 <tr> 522 <td>@Translate("Border")</td> 523 <td>@GetColorSquare(buttonSecondaryBorderColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonSecondaryBorderColor');">@buttonSecondaryBorderColor</a></td> 524 </tr> 525 } 526 <thead> 527 <tr> 528 <th colspan="2" class="fw-bold">@Translate("Secondary button hover")</th> 529 </tr> 530 </thead> 531 @if (!string.IsNullOrEmpty(buttonSecondaryHoverForegroundColor)) 532 { 533 <tr> 534 <td>@Translate("Foreground")</td> 535 <td>@GetColorSquare(buttonSecondaryHoverForegroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonSecondaryHoverForegroundColor');">@buttonSecondaryHoverForegroundColor</a></td> 536 </tr> 537 } 538 @if (!string.IsNullOrEmpty(buttonSecondaryHoverBackgroundColor)) 539 { 540 <tr> 541 <td>@Translate("Background")</td> 542 <td>@GetColorSquare(buttonSecondaryHoverBackgroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonSecondaryHoverBackgroundColor');">@buttonSecondaryHoverBackgroundColor</a></td> 543 </tr> 544 } 545 @if (!string.IsNullOrEmpty(buttonSecondaryHoverBorderColor)) 546 { 547 <tr> 548 <td>@Translate("Border")</td> 549 <td>@GetColorSquare(buttonSecondaryHoverBorderColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonSecondaryHoverBorderColor');">@buttonSecondaryHoverBorderColor</a></td> 550 </tr> 551 } 552 @if (!string.IsNullOrEmpty(accessibilityOutlineColor)) 553 { 554 <tr> 555 <td>@Translate("Focus outline")</td> 556 <td>@GetColorSquare(accessibilityOutlineColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@accessibilityOutlineColor');">@accessibilityOutlineColor</a></td> 557 </tr> 558 } 559 </table> 560 </div> 561 <div class="g-col-12 g-col-lg-3"> 562 <table class="table table-borderless table-sm w-100"> 563 <thead> 564 <tr> 565 <th colspan="2" class="fw-bold">@Translate("Link button")</th> 566 </tr> 567 </thead> 568 <tr> 569 <td>@Translate("Link color")</td> 570 <td>@GetColorSquare(buttonLinkColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonLinkColor');">@buttonLinkColor</a></td> 571 </tr> 572 <thead> 573 <tr> 574 <th colspan="2" class="fw-bold">@Translate("Link button hover")</th> 575 </tr> 576 </thead> 577 @if (!string.IsNullOrEmpty(buttonLinkHoverColor)) 578 { 579 <tr> 580 <td>@Translate("Link hover color")</td> 581 <td>@GetColorSquare(buttonLinkHoverColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonLinkHoverColor');">@buttonLinkHoverColor</a></td> 582 </tr> 583 } 584 585 @if (!string.IsNullOrEmpty(accessibilityOutlineColor)) 586 { 587 <tr> 588 <td>@Translate("Focus outline")</td> 589 <td>@GetColorSquare(accessibilityOutlineColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@accessibilityOutlineColor');">@accessibilityOutlineColor</a></td> 590 </tr> 591 } 592 </table> 593 </div> 594 <div class="g-col-12 g-col-lg-3"> 595 <table class="table table-borderless table-sm w-100"> 596 <tr> 597 <td class="fw-bold">@Translate("Implementation")</td> 598 </tr> 599 <tr> 600 <td> 601 @{ 602 string implementation = $"<div class=\"theme {themeClassName}\"></div>"; 603 } 604 <div class="text-muted"> 605 <code class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@themeClassName');"> 606 @Dynamicweb.Core.Encoders.HtmlEncoder.HtmlEncode(implementation) 607 </code> 608 </div> 609 </td> 610 </tr> 611 </table> 612 </div> 613 @{ 614 bool hasUsageData = Converter.ToBoolean(Dynamicweb.Context.Current.Request["auditUsages"]); 615 if (hasUsageData) 616 { 617 var themeUsage = GetThemeUsageById(themeClassName); 618 int allUsages = themeUsage?.AllUsages ?? 0; 619 string buttonAttributes = allUsages > 0 ? $"data-bs-toggle=\"modal\" data-bs-target=\"#themeUsage_{Model.ID}\"" : string.Empty; 620 string badgeStyle = allUsages > 0 ? "bg-success" : "bg-danger"; 621 622 <div class="g-col-12 g-col-lg-9 position-relative"> 623 <button type="button" class="btn btn-primary btn-sm position-absolute end-0" @buttonAttributes> 624 Usages 625 <span class="position-absolute top-0 start-100 translate-middle badge rounded-pill text-white @badgeStyle">@allUsages</span> 626 </button> 627 628 @if (allUsages > 0) 629 { 630 int websiteUsages = themeUsage?.WebsiteUsages.Count ?? 0; 631 int pageUsages = themeUsage?.PageUsages.Count ?? 0; 632 int pagePropertyUsages = themeUsage?.PagePropertyUsages.Count ?? 0; 633 int gridRowUsages = themeUsage?.GridRowUsages.Count ?? 0; 634 int paragraphUsages = themeUsage?.ParagraphUsages.Count ?? 0; 635 636 <!-- Modal --> 637 <div class="modal fade" id="themeUsage_@(Model.ID)" tabindex="-1" aria-labelledby="usagesModelLabel" aria-hidden="true"> 638 <div class="modal-dialog modal-xl modal-dialog-centered modal-dialog-scrollable"> 639 <div class="modal-content"> 640 <div class="modal-header"> 641 <h5 class="modal-title" id="usagesModelLabel">@allUsages Usages of '@(themeName)' (@(themeClassName))</h5> 642 <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> 643 </div> 644 <div class="modal-body"> 645 <div class="accordion" id="accordionWrapper"> 646 @if(websiteUsages > 0) 647 { 648 <div class="accordion-item"> 649 <h2 class="accordion-header" id="headingWebsites"> 650 <button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#collapseWebsites" aria-expanded="true" aria-controls="collapseWebsites"> 651 <span class="pe-2">Websites</span><span class="badge rounded-pill bg-secondary text-light">@websiteUsages</span> 652 </button> 653 </h2> 654 <div id="collapseWebsites" class="accordion-collapse collapse show" aria-labelledby="headingWebsites" data-bs-parent="#accordionWrapper"> 655 <div class="accordion-body"> 656 <ul> 657 @foreach (var usage in themeUsage.WebsiteUsages) 658 { 659 var website = Dynamicweb.Content.Services.Areas.GetArea(usage); 660 <li><span class="fw-bold">@website.Name</span>@($" (ID: {usage})")</li> 661 } 662 </ul> 663 </div> 664 </div> 665 </div> 666 } 667 @if (pageUsages > 0) 668 { 669 var pages = Dynamicweb.Content.Services.Pages.GetPages(themeUsage.PageUsages.ToArray()); 670 671 <div class="accordion-item"> 672 <h2 class="accordion-header" id="headingPages"> 673 <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapsePages" aria-expanded="false" aria-controls="collapsePages"> 674 <span class="pe-2">Pages</span><span class="badge rounded-pill bg-secondary text-light">@pageUsages</span> 675 </button> 676 </h2> 677 <div id="collapsePages" class="accordion-collapse collapse" aria-labelledby="headingPages" data-bs-parent="#accordionWrapper"> 678 <div class="accordion-body"> 679 <ul> 680 @foreach (var usage in themeUsage.PageUsages) 681 { 682 <li><span class="fw-bold">@pages.FirstOrDefault(p => p.ID == usage).GetDisplayName()</span>@($" (ID: {usage})")</li> 683 } 684 </ul> 685 </div> 686 </div> 687 </div> 688 } 689 @if (pagePropertyUsages > 0) 690 { 691 var pages = Dynamicweb.Content.Services.Pages.GetPages(themeUsage.PageUsages.ToArray()); 692 693 <div class="accordion-item"> 694 <h2 class="accordion-header" id="headingPageProperties"> 695 <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapsePageProperties" aria-expanded="false" aria-controls="collapsePageProperties"> 696 <span class="pe-2">Page Properties</span><span class="badge rounded-pill bg-secondary text-light">@pagePropertyUsages</span> 697 </button> 698 </h2> 699 <div id="collapsePageProperties" class="accordion-collapse collapse" aria-labelledby="headingPageProperties" data-bs-parent="#accordionWrapper"> 700 <div class="accordion-body"> 701 <ul> 702 @foreach (var usage in themeUsage.PagePropertyUsages) 703 { 704 <li><span class="fw-bold">@pages.FirstOrDefault(p => p.ID == usage).GetDisplayName()</span>@($" (ID: {usage})")</li> 705 } 706 </ul> 707 </div> 708 </div> 709 </div> 710 } 711 @if (gridRowUsages > 0) 712 { 713 var rows = Dynamicweb.Content.Services.Grids.GetGridRows().Where(r => themeUsage.GridRowUsages.Contains(r.ID)).ToList(); 714 715 <div class="accordion-item"> 716 <h2 class="accordion-header" id="headingRows"> 717 <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseRows" aria-expanded="false" aria-controls="collapseRows"> 718 <span class="pe-2">Rows</span><span class="badge rounded-pill bg-secondary text-light">@gridRowUsages</span> 719 </button> 720 </h2> 721 <div id="collapseRows" class="accordion-collapse collapse" aria-labelledby="headingRows" data-bs-parent="#accordionWrapper"> 722 <div class="accordion-body"> 723 <ul> 724 @foreach (var usage in themeUsage.GridRowUsages) 725 { 726 var row = rows.FirstOrDefault(r => r.ID == usage); 727 var page = Dynamicweb.Content.Services.Pages.GetPage(row.PageId); 728 <li>Page: <span class="fw-bold">@(page.GetDisplayName())</span>@($"( ID: {page.ID}) - Row: ")<span class="fw-bold">@(row.DefinitionId)</span>@($" (ID: {usage})")</li> 729 } 730 </ul> 731 </div> 732 </div> 733 </div> 734 } 735 @if (paragraphUsages > 0) 736 { 737 var paragraphs = Dynamicweb.Content.Services.Paragraphs.GetParagraphs().Where(p => themeUsage.ParagraphUsages.Contains(p.ID)).ToList(); 738 739 <div class="accordion-item"> 740 <h2 class="accordion-header" id="headingParagraphs"> 741 <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseParagraphs" aria-expanded="false" aria-controls="collapseParagraphs"> 742 <span class="pe-2">Paragraphs</span><span class="badge rounded-pill bg-secondary text-light">@paragraphUsages</span> 743 </button> 744 </h2> 745 <div id="collapseParagraphs" class="accordion-collapse collapse" aria-labelledby="headingParagraphs" data-bs-parent="#accordionWrapper"> 746 <div class="accordion-body"> 747 <ul> 748 @foreach (var usage in themeUsage.ParagraphUsages) 749 { 750 var paragraph = paragraphs.FirstOrDefault(p => p.ID == usage); 751 var page = Dynamicweb.Content.Services.Pages.GetPage(paragraph.PageID); 752 <li>Page: <span class="fw-bold">@(page.GetDisplayName())</span>@($"( ID: {page.ID}) - Paragraph: ")<span class="fw-bold">@paragraph.Header</span>@($" (ID: {usage})")</li> 753 } 754 </ul> 755 </div> 756 </div> 757 </div> 758 } 759 </div> 760 </div> 761 </div> 762 </div> 763 </div> 764 } 765 </div> 766 } 767 } 768 </div> 769 </div> 770 } 771 <div class="g-col-12"> 772 <hr /> 773 </div> 774
Error executing template "Designs/Swift/Paragraph/Swift_Theme.cshtml" System.Data.SqlClient.SqlException (0x80131904): STRING_AGG aggregation result exceeded the limit of 8000 bytes. Use LOB types to avoid result truncation. at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction) at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose) at System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady) at System.Data.SqlClient.SqlDataReader.TryConsumeMetaData() at System.Data.SqlClient.SqlDataReader.get_MetaData() at System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString, Boolean isInternal, Boolean forDescribeParameterEncryption, Boolean shouldCacheForAlwaysEncrypted) at System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async, Int32 timeout, Task& task, Boolean asyncWrite, Boolean inRetry, SqlDataReader ds, Boolean describeParameterEncryptionRequest) at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, TaskCompletionSource`1 completion, Int32 timeout, Task& task, Boolean& usedCache, Boolean asyncWrite, Boolean inRetry) at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method) at System.Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior behavior, String method) at Dynamicweb.Data.Database.CreateDataReader(IDbCommand command, CommandBehavior behavior) at Dynamicweb.Data.Database.CreateDataReader(String sql, IDbConnection connection, IDbTransaction transaction, CommandBehavior behavior, Int32 commandTimeout, Dictionary`2 sqlParams) at Dynamicweb.Data.Database.CreateDataReader(String sql, IDbConnection connection, IDbTransaction transaction, Int32 commandTimeout, Dictionary`2 sqlParams) at Dynamicweb.Data.Database.CreateDataReader(String sql) at CompiledRazorTemplates.Dynamic.RazorEngine_8e3f1b11eb0041ceb2ca487c2be837e6.UpdateThemeUsages(String sqlQuery, List`1 themeUsages) in E:\Dynamicweb.net\Solutions\Dynamicweb\dw2022.cloud.dynamicweb-cms.com\Files\Templates\Designs\Swift\Paragraph\Swift_Theme.cshtml:line 202 at CompiledRazorTemplates.Dynamic.RazorEngine_8e3f1b11eb0041ceb2ca487c2be837e6.GetAllThemeUsages() in E:\Dynamicweb.net\Solutions\Dynamicweb\dw2022.cloud.dynamicweb-cms.com\Files\Templates\Designs\Swift\Paragraph\Swift_Theme.cshtml:line 184 at CompiledRazorTemplates.Dynamic.RazorEngine_8e3f1b11eb0041ceb2ca487c2be837e6.GetThemeUsageById(String themeId) in E:\Dynamicweb.net\Solutions\Dynamicweb\dw2022.cloud.dynamicweb-cms.com\Files\Templates\Designs\Swift\Paragraph\Swift_Theme.cshtml:line 238 at CompiledRazorTemplates.Dynamic.RazorEngine_8e3f1b11eb0041ceb2ca487c2be837e6.Execute() in E:\Dynamicweb.net\Solutions\Dynamicweb\dw2022.cloud.dynamicweb-cms.com\Files\Templates\Designs\Swift\Paragraph\Swift_Theme.cshtml:line 617 at RazorEngine.Templating.TemplateBase.RazorEngine.Templating.ITemplate.Run(ExecuteContext context, TextWriter reader) at RazorEngine.Templating.RazorEngineService.RunCompile(ITemplateKey key, TextWriter writer, Type modelType, Object model, DynamicViewBag viewBag) at RazorEngine.Templating.RazorEngineServiceExtensions.<>c__DisplayClass16_0.<RunCompile>b__0(TextWriter writer) at RazorEngine.Templating.RazorEngineServiceExtensions.WithWriter(Action`1 withWriter) at Dynamicweb.Rendering.RazorTemplateRenderingProvider.Render(Template template) at Dynamicweb.Rendering.TemplateRenderingService.Render(Template template) at Dynamicweb.Rendering.Template.RenderRazorTemplate() ClientConnectionId:b42d1cec-597c-4eed-bdc2-e0762a41101a Error Number:9829,State:1,Class:16
1 @inherits Dynamicweb.Rendering.ViewModelTemplate<Dynamicweb.Frontend.ParagraphViewModel> 2 @using System.Globalization 3 @using System.Drawing 4 @using Dynamicweb.Core 5 6 @functions{ 7 // Get Hex Color from color picker and translate to RGB color 8 public static string HexToRGB(string hexString) 9 { 10 if (hexString.Equals("none") || string.IsNullOrEmpty(hexString)) 11 return hexString; 12 13 //replace # occurences 14 if (hexString.IndexOf('#') != -1) 15 hexString = hexString.Replace("#", ""); 16 try 17 { 18 int r, g, b = 0; 19 r = int.Parse(hexString.Substring(0, 2), NumberStyles.AllowHexSpecifier); 20 g = int.Parse(hexString.Substring(2, 2), NumberStyles.AllowHexSpecifier); 21 b = int.Parse(hexString.Substring(4, 2), NumberStyles.AllowHexSpecifier); 22 23 string rgb = r + "," + g + "," + b; 24 return rgb; 25 } 26 catch (System.Exception) 27 { 28 return hexString; 29 } 30 } 31 32 public static string GetColorSquare(string hex) 33 { 34 return $"<div class=\"swift-checkered d-inline-block me-1\" style=\"height:1.25rem;width:1.25rem;\"><div style=\"background-color: {hex};border:.0625rem solid grey\" class=\"w-100 h-100\"></div></div>"; 35 } 36 37 public class HSL 38 { 39 public double h { get; set; } 40 public double s { get; set; } 41 public double l { get; set; } 42 } 43 44 //Convert HEX to HSL 45 public static HSL HexToHsl(string hexString) 46 { 47 System.Drawing.Color color = System.Drawing.ColorTranslator.FromHtml(hexString); 48 49 float _R = (color.R / 255f); 50 float _G = (color.G / 255f); 51 float _B = (color.B / 255f); 52 53 float _Min = Math.Min(Math.Min(_R, _G), _B); 54 float _Max = Math.Max(Math.Max(_R, _G), _B); 55 float _Delta = _Max - _Min; 56 57 float S = 0; 58 float L = (float)((_Max + _Min) / 2.0f); 59 60 if (_Delta != 0) 61 { 62 if (L < 0.5f) 63 { 64 S = (float)(_Delta / (_Max + _Min)); 65 } 66 else 67 { 68 S = (float)(_Delta / (2.0f - _Max - _Min)); 69 } 70 } 71 72 HSL hsl = new HSL(); 73 hsl.h = Math.Round(color.GetHue(), 2); 74 hsl.s = Math.Round(S, 2) * 100; 75 hsl.l = Math.Round(L, 2) * 100; 76 77 return hsl; 78 } 79 80 //Find contrast color (white, black) 81 public static Color GetContrastColor(string hexString) 82 { 83 System.Drawing.Color bg = System.Drawing.ColorTranslator.FromHtml(hexString); 84 85 int nThreshold = 105; 86 int bgDelta = Convert.ToInt32((bg.R * 0.299) + (bg.G * 0.587) + 87 (bg.B * 0.114)); 88 89 Color foreColor = (255 - bgDelta < nThreshold) ? Color.Black : Color.White; 90 return foreColor; 91 } 92 93 public string GetColorVariation(string hexString) 94 { 95 var contrast = GetContrastColor(hexString); 96 HSL currentHslColor = HexToHsl(hexString); 97 HSL variantHslColor = currentHslColor; 98 99 if (contrast == Color.Black) 100 { 101 variantHslColor.l = 85; //The background is dark - Color should be light 102 } 103 else 104 { 105 variantHslColor.l = 40; //The background is light - Color should be less light 106 } 107 108 //Color is very light 109 if (currentHslColor.l > 85) 110 { 111 variantHslColor.l = 95; 112 } 113 114 string colorString = variantHslColor.h + ", " + variantHslColor.s + "%, " + variantHslColor.l + "%"; 115 return colorString; 116 } 117 118 private class ThemeDatabaseUsage 119 { 120 public string TableName { get; set; } 121 public string ColumnName { get; set; } 122 } 123 124 private class ThemeUsage 125 { 126 public string Id { get; set; } 127 public List<int> WebsiteUsages { get; set; } = new List<int>(); 128 public List<int> PageUsages { get; set; } = new List<int>(); 129 public List<int> PagePropertyUsages { get; set; } = new List<int>(); 130 public List<int> GridRowUsages { get; set; } = new List<int>(); 131 public List<int> ParagraphUsages { get; set; } = new List<int>(); 132 public int AllUsages { get; set; } = 0; 133 } 134 135 private List<ThemeDatabaseUsage> GetThemeColumnsFromSchema() 136 { 137 string cacheKey = "ThemesFromDatabase"; 138 if (Dynamicweb.Context.Current.Items.Contains(cacheKey)) 139 { 140 return (List<ThemeDatabaseUsage>)Dynamicweb.Context.Current.Items[cacheKey]; 141 } 142 var schema = Dynamicweb.Data.Database.CreateDataReader("SELECT table_name, column_name FROM information_schema.columns WHERE column_name LIKE '%Theme%'"); 143 144 var rawData = new List<ThemeDatabaseUsage>(); 145 while (schema.Read()) { 146 rawData.Add(new ThemeDatabaseUsage {TableName = schema["table_name"].ToString(), ColumnName = schema["column_name"].ToString() }); 147 } 148 Dynamicweb.Context.Current.Items[cacheKey] = rawData; 149 return rawData; 150 } 151 152 private List<ThemeUsage> GetAllThemeUsages() 153 { 154 string cacheKey = "ThemeUsages"; 155 if (Dynamicweb.Context.Current.Items.Contains(cacheKey)) 156 { 157 return (List<ThemeUsage>)Dynamicweb.Context.Current.Items[cacheKey]; 158 } 159 160 var rawData = GetThemeColumnsFromSchema(); 161 var themeUsages = new List<ThemeUsage>(); 162 163 var sqlQuery = ""; 164 foreach (var row in rawData) 165 { 166 if (!string.IsNullOrEmpty(sqlQuery)) { sqlQuery += " UNION ALL "; } 167 sqlQuery += $"SELECT '{row.TableName}' AS TableName, '{row.ColumnName}' AS ColumnName, {row.ColumnName} AS ColumnValue, Id, AreaId, Page.PageId, PageProperties.PageId as 'PagePropertiesId', GridRowId, ParagraphId" + 168 $" FROM [{row.TableName}]" + 169 $" LEFT JOIN Area ON AreaItemType = '{row.TableName.Replace("ItemType_","")}' AND AreaItemId = Id" + 170 $" LEFT JOIN Page ON PageItemType = '{row.TableName.Replace("ItemType_","")}' AND PageItemId = Id" + 171 $" LEFT JOIN Page as PageProperties ON AreaItemTypePageProperty = '{row.TableName.Replace("ItemType_","")}' AND PageProperties.PagePropertyItemId = Id" + 172 $" LEFT JOIN GridRow ON GridRowItemType = '{row.TableName.Replace("ItemType_","")}' AND GridRowItemId = Id" + 173 $" LEFT JOIN Paragraph ON ParagraphItemType = '{row.TableName.Replace("ItemType_","")}' AND ParagraphItemId = Id" + 174 $" WHERE {row.ColumnName} != '' AND {row.ColumnName} IS NOT NULL" + 175 $" AND (AreaId IS NULL OR AreaId = {Pageview.AreaID})" + 176 $" AND (Page.PageId IS NULL OR Page.PageAreaId = {Pageview.AreaID})" + 177 $" AND (PageProperties.PageId IS NULL OR PageProperties.PageAreaId = {Pageview.AreaID})" + 178 $" AND (GridRowId IS NULL OR GridRowPageId IN (SELECT value From string_split(@pageIds, ',')))" + 179 $" AND (ParagraphId IS NULL OR ParagraphPageId IN (SELECT value From string_split(@pageIds, ',')))"; 180 181 var maxMsSqlServerCharLimit = 60000; 182 if (sqlQuery.Length > maxMsSqlServerCharLimit) 183 { 184 UpdateThemeUsages(sqlQuery, themeUsages); 185 sqlQuery = ""; 186 } 187 } 188 189 if (!string.IsNullOrEmpty(sqlQuery)) 190 { 191 UpdateThemeUsages(sqlQuery, themeUsages); 192 } 193 UpdateAllUsages(themeUsages); 194 195 Dynamicweb.Context.Current.Items[cacheKey] = themeUsages; 196 return themeUsages; 197 } 198 199 private void UpdateThemeUsages(string sqlQuery, List<ThemeUsage> themeUsages) 200 { 201 sqlQuery = $"DECLARE @pageIds NVARCHAR(max) = (SELECT STRING_AGG(PageId,',') FROM Page WHERE PageAreaId = {Pageview.AreaID}) " + sqlQuery; 202 var rawData = Dynamicweb.Data.Database.CreateDataReader(sqlQuery); 203 while (rawData.Read()) 204 { 205 var themeId = rawData["ColumnValue"].ToString(); 206 var themeUsageExists = themeUsages.FirstOrDefault(t => t.Id == themeId) != null; 207 if (!themeUsageExists) 208 { 209 themeUsages.Add(new ThemeUsage { Id = themeId }); 210 } 211 212 var themeUsage = themeUsages.FirstOrDefault(t => t.Id == themeId); 213 if (themeUsage == null) continue; 214 215 if (Converter.ToInt32(rawData["AreaId"].ToString()) > 0) { themeUsage.WebsiteUsages.Add(Converter.ToInt32(rawData["AreaId"].ToString())); } 216 if (Converter.ToInt32(rawData["PageId"].ToString()) > 0) { themeUsage.PageUsages.Add(Converter.ToInt32(rawData["PageId"].ToString())); } 217 if (Converter.ToInt32(rawData["PagePropertiesId"].ToString()) > 0) { themeUsage.PagePropertyUsages.Add(Converter.ToInt32(rawData["PagePropertiesId"].ToString())); } 218 if (Converter.ToInt32(rawData["GridRowId"].ToString()) > 0) { themeUsage.GridRowUsages.Add(Converter.ToInt32(rawData["GridRowId"].ToString())); } 219 if (Converter.ToInt32(rawData["ParagraphId"].ToString()) > 0) { themeUsage.ParagraphUsages.Add(Converter.ToInt32(rawData["ParagraphId"].ToString())); } 220 } 221 } 222 223 private void UpdateAllUsages(List<ThemeUsage> themeUsages) 224 { 225 foreach (var themeUsage in themeUsages) 226 { 227 int websiteUsages = themeUsage?.WebsiteUsages.Count ?? 0; 228 int pageUsages = themeUsage?.PageUsages.Count ?? 0; 229 int pagePropertyUsages = themeUsage?.PagePropertyUsages.Count ?? 0; 230 int gridRowUsages = themeUsage?.GridRowUsages.Count ?? 0; 231 int paragraphUsages = themeUsage?.ParagraphUsages.Count ?? 0; 232 themeUsage.AllUsages = websiteUsages + pageUsages + pagePropertyUsages + gridRowUsages + paragraphUsages; 233 } 234 } 235 236 private ThemeUsage GetThemeUsageById(string themeId) 237 { 238 var themeUsages = GetAllThemeUsages(); 239 return themeUsages.FirstOrDefault(t => t.Id == themeId); 240 } 241 242 } 243 244 @{ 245 string themeName = !string.IsNullOrWhiteSpace(Model.Item.GetString("Name")) ? Model.Item.GetString("Name") : "Default"; 246 string themeClassName = !string.IsNullOrWhiteSpace(Model.Item.GetString("CSSClassName")) ? Model.Item.GetString("CSSClassName").Replace(" ", "").Trim().ToLower() : ""; 247 248 //Theme colors 249 string foregroundColor = Model.Item.GetString("ForegroundColor", "currentColor"); 250 string backgroundColor = Model.Item.GetString("BackgroundColor", "transparent"); 251 string accentColor = Model.Item.GetString("accentColor", "currentColor"); 252 string borderColor = Model.Item.GetString("BorderColor", "transparent"); 253 254 //Primary button 255 string buttonPrimaryForegroundColor = Model.Item.GetString("ButtonPrimaryForegroundColor", "currentColor"); 256 string buttonPrimaryBackgroundColor = Model.Item.GetString("ButtonPrimaryBackgroundColor", "transparent"); 257 string buttonPrimaryBorderColor = Model.Item.GetString("ButtonPrimaryBorderColor", "transparent"); 258 259 string buttonPrimaryHoverBackgroundColorAuto = "transparent"; 260 if (buttonPrimaryBackgroundColor != "transparent") 261 { 262 buttonPrimaryHoverBackgroundColorAuto = "hsl(" + GetColorVariation(buttonPrimaryBackgroundColor) + ")"; 263 } 264 string buttonPrimaryHoverForegroundColor = Model.Item.GetString("ButtonPrimaryHoverForegroundColor", buttonPrimaryForegroundColor); 265 string buttonPrimaryHoverBackgroundColor = Model.Item.GetString("ButtonPrimaryHoverBackgroundColor", buttonPrimaryHoverBackgroundColorAuto); 266 string buttonPrimaryHoverBorderColor = Model.Item.GetString("ButtonPrimaryHoverBorderColor", buttonPrimaryBorderColor); 267 268 //Secondary buton 269 string buttonSecondaryForegroundColor = Model.Item.GetString("ButtonSecondaryForegroundColor", "currentColor"); 270 string buttonSecondaryBackgroundColor = Model.Item.GetString("ButtonSecondaryBackgroundColor", "transparent"); 271 string buttonSecondaryBorderColor = Model.Item.GetString("ButtonSecondaryBorderColor", "transparent"); 272 273 string buttonSecondaryHoverBackgroundColorAuto = "transparent"; 274 if (buttonSecondaryBackgroundColor != "transparent") 275 { 276 buttonSecondaryHoverBackgroundColorAuto = "hsl(" + GetColorVariation(buttonSecondaryBackgroundColor) + ")"; 277 } 278 string buttonSecondaryHoverForegroundColor = Model.Item.GetString("ButtonSecondaryHoverForegroundColor", buttonSecondaryForegroundColor); 279 string buttonSecondaryHoverBackgroundColor = Model.Item.GetString("ButtonSecondaryHoverBackgroundColor", buttonSecondaryHoverBackgroundColorAuto); 280 string buttonSecondaryHoverBorderColor = Model.Item.GetString("ButtonSecondaryHoverBorderColor", buttonSecondaryBorderColor); 281 282 //Link buton 283 string buttonLinkColor = Model.Item.GetString("ButtonLinkColor", "currentColor"); 284 string buttonLinkHoverColorAuto = "currentColor"; 285 if (buttonLinkColor != "currentColor") 286 { 287 buttonLinkHoverColorAuto = "hsl(" + GetColorVariation(buttonLinkColor) + ")"; 288 } 289 string buttonLinkHoverColor = Model.Item.GetString("ButtonLinkHoverColor", buttonLinkHoverColorAuto); 290 291 string accessibilityOutlineColor = Model.Item.GetString("OutlineColor") != null ? Model.Item.GetString("OutlineColor") : ""; 292 293 if (!string.IsNullOrEmpty(themeClassName)) 294 { 295 var sb = new System.Text.StringBuilder(); 296 297 sb.AppendLine("." + themeClassName + "{"); 298 if (!string.IsNullOrEmpty(foregroundColor)) 299 { 300 sb.AppendLine($"--swift-foreground-color: {foregroundColor};"); 301 sb.AppendLine($"--swift-foreground-color-rgb: {HexToRGB(foregroundColor)};"); 302 } 303 if (!string.IsNullOrEmpty(backgroundColor)) 304 { 305 sb.AppendLine($"--swift-background-color: {backgroundColor};"); 306 sb.AppendLine($"--swift-background-color-rgb: {HexToRGB(backgroundColor)};"); 307 } 308 if (!string.IsNullOrEmpty(accentColor)) 309 { 310 sb.AppendLine($"--swift-accent-color: {accentColor};"); 311 sb.AppendLine($"--swift-accent-color-rgb: {HexToRGB(accentColor)};"); 312 } 313 if (!string.IsNullOrEmpty(borderColor)) 314 { 315 sb.AppendLine($"--swift-border-color: {borderColor};"); 316 sb.AppendLine($"--swift-border-color-rgb: {HexToRGB(borderColor)};"); 317 } 318 319 if (!string.IsNullOrEmpty(buttonPrimaryBackgroundColor)) 320 { 321 sb.AppendLine($"--swift-button-primary-background-color: {buttonPrimaryBackgroundColor};"); 322 sb.AppendLine($"--swift-button-primary-background-color-rgb: {HexToRGB(buttonPrimaryBackgroundColor)};"); 323 } 324 if (!string.IsNullOrEmpty(buttonPrimaryForegroundColor)) 325 { 326 sb.AppendLine($"--swift-button-primary-foreground-color: {buttonPrimaryForegroundColor};"); 327 sb.AppendLine($"--swift-button-primary-foreground-color-rgb: {HexToRGB(buttonPrimaryForegroundColor)};"); 328 } 329 if (!string.IsNullOrEmpty(buttonPrimaryBorderColor)) 330 { 331 sb.AppendLine($"--swift-button-primary-border-color: {buttonPrimaryBorderColor};"); 332 sb.AppendLine($"--swift-button-primary-border-color-rgb: {HexToRGB(buttonPrimaryBorderColor)};"); 333 } 334 335 if (!string.IsNullOrEmpty(buttonPrimaryHoverBackgroundColor)) 336 { 337 sb.AppendLine($"--swift-button-primary-hover-background-color: {buttonPrimaryHoverBackgroundColor};"); 338 sb.AppendLine($"--swift-button-primary-hover-background-color-rgb: {HexToRGB(buttonPrimaryHoverBackgroundColor)};"); 339 } 340 if (!string.IsNullOrEmpty(buttonPrimaryHoverForegroundColor)) 341 { 342 sb.AppendLine($"--swift-button-primary-hover-foreground-color: {buttonPrimaryHoverForegroundColor};"); 343 sb.AppendLine($"--swift-button-primary-hover-foreground-color-rgb: {HexToRGB(buttonPrimaryHoverForegroundColor)};"); 344 } 345 if (!string.IsNullOrEmpty(buttonPrimaryHoverBorderColor)) 346 { 347 sb.AppendLine($"--swift-button-primary-hover-border-color: {buttonPrimaryHoverBorderColor};"); 348 sb.AppendLine($"--swift-button-primary-hover-border-color-rgb: {HexToRGB(buttonPrimaryHoverBorderColor)};"); 349 } 350 351 if (!string.IsNullOrEmpty(buttonSecondaryBackgroundColor)) 352 { 353 sb.AppendLine($"--swift-button-secondary-background-color: {buttonSecondaryBackgroundColor};"); 354 sb.AppendLine($"--swift-button-secondary-background-color-rgb: {HexToRGB(buttonSecondaryBackgroundColor)};"); 355 } 356 if (!string.IsNullOrEmpty(buttonSecondaryForegroundColor)) 357 { 358 sb.AppendLine($"--swift-button-secondary-foreground-color: {buttonSecondaryForegroundColor};"); 359 sb.AppendLine($"--swift-button-secondary-foreground-color-rgb: {HexToRGB(buttonSecondaryForegroundColor)};"); 360 } 361 if (!string.IsNullOrEmpty(buttonSecondaryBorderColor)) 362 { 363 sb.AppendLine($"--swift-button-secondary-border-color: {buttonSecondaryBorderColor};"); 364 sb.AppendLine($"--swift-button-secondary-border-color-rgb: {HexToRGB(buttonSecondaryBorderColor)};"); 365 } 366 if (!string.IsNullOrEmpty(buttonSecondaryHoverBackgroundColor)) 367 { 368 sb.AppendLine($"--swift-button-secondary-hover-background-color: {buttonSecondaryHoverBackgroundColor};"); 369 sb.AppendLine($"--swift-button-secondary-hover-background-color-rgb: {HexToRGB(buttonSecondaryHoverBackgroundColor)};"); 370 } 371 if (!string.IsNullOrEmpty(buttonSecondaryHoverForegroundColor)) 372 { 373 sb.AppendLine($"--swift-button-secondary-hover-foreground-color: {buttonSecondaryHoverForegroundColor};"); 374 sb.AppendLine($"--swift-button-secondary-hover-foreground-color-rgb: {HexToRGB(buttonSecondaryHoverForegroundColor)};"); 375 } 376 if (!string.IsNullOrEmpty(buttonSecondaryHoverBorderColor)) 377 { 378 sb.AppendLine($"--swift-button-secondary-hover-border-color: {buttonSecondaryHoverBorderColor};"); 379 sb.AppendLine($"--swift-button-secondary-hover-border-color-rgb: {HexToRGB(buttonSecondaryHoverBorderColor)};"); 380 } 381 if (!string.IsNullOrEmpty(buttonLinkColor)) 382 { 383 sb.AppendLine($"--swift-button-link-color: {buttonLinkColor};"); 384 sb.AppendLine($"--swift-button-link-color-rgb: {HexToRGB(buttonLinkColor)};"); 385 } 386 if (!string.IsNullOrEmpty(buttonLinkHoverColor)) 387 { 388 sb.AppendLine($"--swift-button-link-hover-color: {buttonLinkHoverColor};"); 389 sb.AppendLine($"--swift-button-link-hover-color-rgb: {HexToRGB(buttonLinkHoverColor)};"); 390 } 391 if (!string.IsNullOrEmpty(accessibilityOutlineColor)) 392 { 393 sb.AppendLine($"--swift-a11y-outline-color: {accessibilityOutlineColor};"); 394 sb.AppendLine($"--swift-a11y-outline-color-rgb: {HexToRGB(accessibilityOutlineColor)};"); 395 } 396 sb.AppendLine("}"); 397 398 Dynamicweb.Core.Helpers.TextFileHelper.WriteTextFile(sb.ToString() + Environment.NewLine, Dynamicweb.Context.Current.Server.MapPath($"/Files/Templates/Designs/Swift/_parsed/Swift_css/Swift_theme_styles_{Dynamicweb.Content.Services.Pages.GetPage(Model.PageID).AreaId}.tmp"), true); 399 } 400 } 401 402 @if (themeClassName != "") 403 { 404 string iconPath = "/Files/Templates/Designs/Swift/Assets/icons/"; 405 406 <div class="g-col-12 g-col-lg-4"> 407 <div class="swift-checkered p-3"> 408 <div class="theme-option theme @themeClassName p-lg-3"> 409 <div class="mb-2 pb-1 border-bottom d-flex align-items-center"> 410 <span class="icon-3 me-2"> 411 @ReadFile(iconPath + "sun.svg") 412 </span> 413 <h4 class="m-0 p-0">@themeName</h4> 414 </div> 415 <div class="d-flex flex-column gap-1 mb-2"> 416 <p class="mb-0">This is the body text of the theme.</p> 417 <p class="mb-0" style="color: var(--swift-accent-color)">This is the accent color of the theme.</p> 418 </div> 419 <div> 420 <button class="btn btn-primary me-1">Primary</button> 421 <button class="btn btn-secondary">Secondary</button> 422 <button class="btn btn-link">Link</button> 423 </div> 424 </div> 425 </div> 426 </div> 427 <div class="g-col-12 g-col-lg-8 mb-4 mb-lg-0"> 428 <div class="grid fs-7"> 429 <div class="g-col-12 g-col-lg-3"> 430 <table class="table table-borderless table-sm w-100"> 431 <thead> 432 <tr> 433 <th colspan="2" class="fw-bold">@Translate("Base")</th> 434 </tr> 435 </thead> 436 <tr> 437 <td>@Translate("Foreground")</td> 438 <td>@GetColorSquare(foregroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@foregroundColor');">@foregroundColor</a></td> 439 </tr> 440 <tr> 441 <td>@Translate("Background")</td> 442 <td>@GetColorSquare(backgroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@backgroundColor');">@backgroundColor</a></td> 443 </tr> 444 <tr> 445 <td>@Translate("Accent")</td> 446 <td>@GetColorSquare(accentColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@accentColor');">@accentColor</a></td> 447 </tr> 448 <tr> 449 <td>@Translate("Border")</td> 450 <td>@GetColorSquare(borderColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@borderColor');">@borderColor</a></td> 451 </tr> 452 </table> 453 </div> 454 <div class="g-col-12 g-col-lg-3"> 455 <table class="table table-borderless table-sm w-100"> 456 <thead> 457 <tr> 458 <th colspan="2" class="fw-bold">@Translate("Primary button")</th> 459 </tr> 460 </thead> 461 <tr> 462 <td>@Translate("Foreground")</td> 463 <td>@GetColorSquare(buttonPrimaryForegroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonPrimaryForegroundColor');">@buttonPrimaryForegroundColor</a></td> 464 </tr> 465 <tr> 466 <td>@Translate("Background")</td> 467 <td>@GetColorSquare(buttonPrimaryBackgroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonPrimaryBackgroundColor');">@buttonPrimaryBackgroundColor</a></td> 468 </tr> 469 @if (!string.IsNullOrEmpty(buttonPrimaryBorderColor)) 470 { 471 <tr> 472 <td>@Translate("Border")</td> 473 <td>@GetColorSquare(buttonPrimaryBorderColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonPrimaryBorderColor');">@buttonPrimaryBorderColor</a></td> 474 </tr> 475 } 476 <thead> 477 <tr> 478 <th colspan="2" class="fw-bold">@Translate("Primary button hover")</th> 479 </tr> 480 </thead> 481 @if (!string.IsNullOrEmpty(buttonPrimaryHoverForegroundColor)) 482 { 483 <tr> 484 <td>@Translate("Foreground")</td> 485 <td>@GetColorSquare(buttonPrimaryHoverForegroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonPrimaryHoverForegroundColor');">@buttonPrimaryHoverForegroundColor</a></td> 486 </tr> 487 } 488 @if (!string.IsNullOrEmpty(buttonPrimaryHoverBackgroundColor)) 489 { 490 <tr> 491 <td>@Translate("Background")</td> 492 <td>@GetColorSquare(buttonPrimaryHoverBackgroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonPrimaryHoverBackgroundColor');">@buttonPrimaryHoverBackgroundColor</a></td> 493 </tr> 494 } 495 @if (!string.IsNullOrEmpty(buttonPrimaryHoverBorderColor)) 496 { 497 <tr> 498 <td>@Translate("Border")</td> 499 <td>@GetColorSquare(buttonPrimaryHoverBorderColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonPrimaryHoverBorderColor');">@buttonPrimaryHoverBorderColor</a></td> 500 </tr> 501 } 502 </table> 503 </div> 504 <div class="g-col-12 g-col-lg-3"> 505 <table class="table table-borderless table-sm w-100"> 506 <thead> 507 <tr> 508 <th colspan="2" class="fw-bold">@Translate("Secondary button")</th> 509 </tr> 510 </thead> 511 <tr> 512 <td>@Translate("Foreground")</td> 513 <td>@GetColorSquare(buttonSecondaryForegroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonSecondaryForegroundColor');">@buttonSecondaryForegroundColor</a></td> 514 </tr> 515 <tr> 516 <td>@Translate("Background")</td> 517 <td>@GetColorSquare(buttonSecondaryBackgroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonSecondaryBackgroundColor');">@buttonSecondaryBackgroundColor</a></td> 518 </tr> 519 @if (!string.IsNullOrEmpty(buttonSecondaryBorderColor)) 520 { 521 <tr> 522 <td>@Translate("Border")</td> 523 <td>@GetColorSquare(buttonSecondaryBorderColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonSecondaryBorderColor');">@buttonSecondaryBorderColor</a></td> 524 </tr> 525 } 526 <thead> 527 <tr> 528 <th colspan="2" class="fw-bold">@Translate("Secondary button hover")</th> 529 </tr> 530 </thead> 531 @if (!string.IsNullOrEmpty(buttonSecondaryHoverForegroundColor)) 532 { 533 <tr> 534 <td>@Translate("Foreground")</td> 535 <td>@GetColorSquare(buttonSecondaryHoverForegroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonSecondaryHoverForegroundColor');">@buttonSecondaryHoverForegroundColor</a></td> 536 </tr> 537 } 538 @if (!string.IsNullOrEmpty(buttonSecondaryHoverBackgroundColor)) 539 { 540 <tr> 541 <td>@Translate("Background")</td> 542 <td>@GetColorSquare(buttonSecondaryHoverBackgroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonSecondaryHoverBackgroundColor');">@buttonSecondaryHoverBackgroundColor</a></td> 543 </tr> 544 } 545 @if (!string.IsNullOrEmpty(buttonSecondaryHoverBorderColor)) 546 { 547 <tr> 548 <td>@Translate("Border")</td> 549 <td>@GetColorSquare(buttonSecondaryHoverBorderColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonSecondaryHoverBorderColor');">@buttonSecondaryHoverBorderColor</a></td> 550 </tr> 551 } 552 @if (!string.IsNullOrEmpty(accessibilityOutlineColor)) 553 { 554 <tr> 555 <td>@Translate("Focus outline")</td> 556 <td>@GetColorSquare(accessibilityOutlineColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@accessibilityOutlineColor');">@accessibilityOutlineColor</a></td> 557 </tr> 558 } 559 </table> 560 </div> 561 <div class="g-col-12 g-col-lg-3"> 562 <table class="table table-borderless table-sm w-100"> 563 <thead> 564 <tr> 565 <th colspan="2" class="fw-bold">@Translate("Link button")</th> 566 </tr> 567 </thead> 568 <tr> 569 <td>@Translate("Link color")</td> 570 <td>@GetColorSquare(buttonLinkColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonLinkColor');">@buttonLinkColor</a></td> 571 </tr> 572 <thead> 573 <tr> 574 <th colspan="2" class="fw-bold">@Translate("Link button hover")</th> 575 </tr> 576 </thead> 577 @if (!string.IsNullOrEmpty(buttonLinkHoverColor)) 578 { 579 <tr> 580 <td>@Translate("Link hover color")</td> 581 <td>@GetColorSquare(buttonLinkHoverColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonLinkHoverColor');">@buttonLinkHoverColor</a></td> 582 </tr> 583 } 584 585 @if (!string.IsNullOrEmpty(accessibilityOutlineColor)) 586 { 587 <tr> 588 <td>@Translate("Focus outline")</td> 589 <td>@GetColorSquare(accessibilityOutlineColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@accessibilityOutlineColor');">@accessibilityOutlineColor</a></td> 590 </tr> 591 } 592 </table> 593 </div> 594 <div class="g-col-12 g-col-lg-3"> 595 <table class="table table-borderless table-sm w-100"> 596 <tr> 597 <td class="fw-bold">@Translate("Implementation")</td> 598 </tr> 599 <tr> 600 <td> 601 @{ 602 string implementation = $"<div class=\"theme {themeClassName}\"></div>"; 603 } 604 <div class="text-muted"> 605 <code class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@themeClassName');"> 606 @Dynamicweb.Core.Encoders.HtmlEncoder.HtmlEncode(implementation) 607 </code> 608 </div> 609 </td> 610 </tr> 611 </table> 612 </div> 613 @{ 614 bool hasUsageData = Converter.ToBoolean(Dynamicweb.Context.Current.Request["auditUsages"]); 615 if (hasUsageData) 616 { 617 var themeUsage = GetThemeUsageById(themeClassName); 618 int allUsages = themeUsage?.AllUsages ?? 0; 619 string buttonAttributes = allUsages > 0 ? $"data-bs-toggle=\"modal\" data-bs-target=\"#themeUsage_{Model.ID}\"" : string.Empty; 620 string badgeStyle = allUsages > 0 ? "bg-success" : "bg-danger"; 621 622 <div class="g-col-12 g-col-lg-9 position-relative"> 623 <button type="button" class="btn btn-primary btn-sm position-absolute end-0" @buttonAttributes> 624 Usages 625 <span class="position-absolute top-0 start-100 translate-middle badge rounded-pill text-white @badgeStyle">@allUsages</span> 626 </button> 627 628 @if (allUsages > 0) 629 { 630 int websiteUsages = themeUsage?.WebsiteUsages.Count ?? 0; 631 int pageUsages = themeUsage?.PageUsages.Count ?? 0; 632 int pagePropertyUsages = themeUsage?.PagePropertyUsages.Count ?? 0; 633 int gridRowUsages = themeUsage?.GridRowUsages.Count ?? 0; 634 int paragraphUsages = themeUsage?.ParagraphUsages.Count ?? 0; 635 636 <!-- Modal --> 637 <div class="modal fade" id="themeUsage_@(Model.ID)" tabindex="-1" aria-labelledby="usagesModelLabel" aria-hidden="true"> 638 <div class="modal-dialog modal-xl modal-dialog-centered modal-dialog-scrollable"> 639 <div class="modal-content"> 640 <div class="modal-header"> 641 <h5 class="modal-title" id="usagesModelLabel">@allUsages Usages of '@(themeName)' (@(themeClassName))</h5> 642 <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> 643 </div> 644 <div class="modal-body"> 645 <div class="accordion" id="accordionWrapper"> 646 @if(websiteUsages > 0) 647 { 648 <div class="accordion-item"> 649 <h2 class="accordion-header" id="headingWebsites"> 650 <button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#collapseWebsites" aria-expanded="true" aria-controls="collapseWebsites"> 651 <span class="pe-2">Websites</span><span class="badge rounded-pill bg-secondary text-light">@websiteUsages</span> 652 </button> 653 </h2> 654 <div id="collapseWebsites" class="accordion-collapse collapse show" aria-labelledby="headingWebsites" data-bs-parent="#accordionWrapper"> 655 <div class="accordion-body"> 656 <ul> 657 @foreach (var usage in themeUsage.WebsiteUsages) 658 { 659 var website = Dynamicweb.Content.Services.Areas.GetArea(usage); 660 <li><span class="fw-bold">@website.Name</span>@($" (ID: {usage})")</li> 661 } 662 </ul> 663 </div> 664 </div> 665 </div> 666 } 667 @if (pageUsages > 0) 668 { 669 var pages = Dynamicweb.Content.Services.Pages.GetPages(themeUsage.PageUsages.ToArray()); 670 671 <div class="accordion-item"> 672 <h2 class="accordion-header" id="headingPages"> 673 <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapsePages" aria-expanded="false" aria-controls="collapsePages"> 674 <span class="pe-2">Pages</span><span class="badge rounded-pill bg-secondary text-light">@pageUsages</span> 675 </button> 676 </h2> 677 <div id="collapsePages" class="accordion-collapse collapse" aria-labelledby="headingPages" data-bs-parent="#accordionWrapper"> 678 <div class="accordion-body"> 679 <ul> 680 @foreach (var usage in themeUsage.PageUsages) 681 { 682 <li><span class="fw-bold">@pages.FirstOrDefault(p => p.ID == usage).GetDisplayName()</span>@($" (ID: {usage})")</li> 683 } 684 </ul> 685 </div> 686 </div> 687 </div> 688 } 689 @if (pagePropertyUsages > 0) 690 { 691 var pages = Dynamicweb.Content.Services.Pages.GetPages(themeUsage.PageUsages.ToArray()); 692 693 <div class="accordion-item"> 694 <h2 class="accordion-header" id="headingPageProperties"> 695 <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapsePageProperties" aria-expanded="false" aria-controls="collapsePageProperties"> 696 <span class="pe-2">Page Properties</span><span class="badge rounded-pill bg-secondary text-light">@pagePropertyUsages</span> 697 </button> 698 </h2> 699 <div id="collapsePageProperties" class="accordion-collapse collapse" aria-labelledby="headingPageProperties" data-bs-parent="#accordionWrapper"> 700 <div class="accordion-body"> 701 <ul> 702 @foreach (var usage in themeUsage.PagePropertyUsages) 703 { 704 <li><span class="fw-bold">@pages.FirstOrDefault(p => p.ID == usage).GetDisplayName()</span>@($" (ID: {usage})")</li> 705 } 706 </ul> 707 </div> 708 </div> 709 </div> 710 } 711 @if (gridRowUsages > 0) 712 { 713 var rows = Dynamicweb.Content.Services.Grids.GetGridRows().Where(r => themeUsage.GridRowUsages.Contains(r.ID)).ToList(); 714 715 <div class="accordion-item"> 716 <h2 class="accordion-header" id="headingRows"> 717 <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseRows" aria-expanded="false" aria-controls="collapseRows"> 718 <span class="pe-2">Rows</span><span class="badge rounded-pill bg-secondary text-light">@gridRowUsages</span> 719 </button> 720 </h2> 721 <div id="collapseRows" class="accordion-collapse collapse" aria-labelledby="headingRows" data-bs-parent="#accordionWrapper"> 722 <div class="accordion-body"> 723 <ul> 724 @foreach (var usage in themeUsage.GridRowUsages) 725 { 726 var row = rows.FirstOrDefault(r => r.ID == usage); 727 var page = Dynamicweb.Content.Services.Pages.GetPage(row.PageId); 728 <li>Page: <span class="fw-bold">@(page.GetDisplayName())</span>@($"( ID: {page.ID}) - Row: ")<span class="fw-bold">@(row.DefinitionId)</span>@($" (ID: {usage})")</li> 729 } 730 </ul> 731 </div> 732 </div> 733 </div> 734 } 735 @if (paragraphUsages > 0) 736 { 737 var paragraphs = Dynamicweb.Content.Services.Paragraphs.GetParagraphs().Where(p => themeUsage.ParagraphUsages.Contains(p.ID)).ToList(); 738 739 <div class="accordion-item"> 740 <h2 class="accordion-header" id="headingParagraphs"> 741 <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseParagraphs" aria-expanded="false" aria-controls="collapseParagraphs"> 742 <span class="pe-2">Paragraphs</span><span class="badge rounded-pill bg-secondary text-light">@paragraphUsages</span> 743 </button> 744 </h2> 745 <div id="collapseParagraphs" class="accordion-collapse collapse" aria-labelledby="headingParagraphs" data-bs-parent="#accordionWrapper"> 746 <div class="accordion-body"> 747 <ul> 748 @foreach (var usage in themeUsage.ParagraphUsages) 749 { 750 var paragraph = paragraphs.FirstOrDefault(p => p.ID == usage); 751 var page = Dynamicweb.Content.Services.Pages.GetPage(paragraph.PageID); 752 <li>Page: <span class="fw-bold">@(page.GetDisplayName())</span>@($"( ID: {page.ID}) - Paragraph: ")<span class="fw-bold">@paragraph.Header</span>@($" (ID: {usage})")</li> 753 } 754 </ul> 755 </div> 756 </div> 757 </div> 758 } 759 </div> 760 </div> 761 </div> 762 </div> 763 </div> 764 } 765 </div> 766 } 767 } 768 </div> 769 </div> 770 } 771 <div class="g-col-12"> 772 <hr /> 773 </div> 774
Error executing template "Designs/Swift/Paragraph/Swift_Theme.cshtml" System.Data.SqlClient.SqlException (0x80131904): STRING_AGG aggregation result exceeded the limit of 8000 bytes. Use LOB types to avoid result truncation. at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction) at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose) at System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady) at System.Data.SqlClient.SqlDataReader.TryConsumeMetaData() at System.Data.SqlClient.SqlDataReader.get_MetaData() at System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString, Boolean isInternal, Boolean forDescribeParameterEncryption, Boolean shouldCacheForAlwaysEncrypted) at System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async, Int32 timeout, Task& task, Boolean asyncWrite, Boolean inRetry, SqlDataReader ds, Boolean describeParameterEncryptionRequest) at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, TaskCompletionSource`1 completion, Int32 timeout, Task& task, Boolean& usedCache, Boolean asyncWrite, Boolean inRetry) at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method) at System.Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior behavior, String method) at Dynamicweb.Data.Database.CreateDataReader(IDbCommand command, CommandBehavior behavior) at Dynamicweb.Data.Database.CreateDataReader(String sql, IDbConnection connection, IDbTransaction transaction, CommandBehavior behavior, Int32 commandTimeout, Dictionary`2 sqlParams) at Dynamicweb.Data.Database.CreateDataReader(String sql, IDbConnection connection, IDbTransaction transaction, Int32 commandTimeout, Dictionary`2 sqlParams) at Dynamicweb.Data.Database.CreateDataReader(String sql) at CompiledRazorTemplates.Dynamic.RazorEngine_8e3f1b11eb0041ceb2ca487c2be837e6.UpdateThemeUsages(String sqlQuery, List`1 themeUsages) in E:\Dynamicweb.net\Solutions\Dynamicweb\dw2022.cloud.dynamicweb-cms.com\Files\Templates\Designs\Swift\Paragraph\Swift_Theme.cshtml:line 202 at CompiledRazorTemplates.Dynamic.RazorEngine_8e3f1b11eb0041ceb2ca487c2be837e6.GetAllThemeUsages() in E:\Dynamicweb.net\Solutions\Dynamicweb\dw2022.cloud.dynamicweb-cms.com\Files\Templates\Designs\Swift\Paragraph\Swift_Theme.cshtml:line 184 at CompiledRazorTemplates.Dynamic.RazorEngine_8e3f1b11eb0041ceb2ca487c2be837e6.GetThemeUsageById(String themeId) in E:\Dynamicweb.net\Solutions\Dynamicweb\dw2022.cloud.dynamicweb-cms.com\Files\Templates\Designs\Swift\Paragraph\Swift_Theme.cshtml:line 238 at CompiledRazorTemplates.Dynamic.RazorEngine_8e3f1b11eb0041ceb2ca487c2be837e6.Execute() in E:\Dynamicweb.net\Solutions\Dynamicweb\dw2022.cloud.dynamicweb-cms.com\Files\Templates\Designs\Swift\Paragraph\Swift_Theme.cshtml:line 617 at RazorEngine.Templating.TemplateBase.RazorEngine.Templating.ITemplate.Run(ExecuteContext context, TextWriter reader) at RazorEngine.Templating.RazorEngineService.RunCompile(ITemplateKey key, TextWriter writer, Type modelType, Object model, DynamicViewBag viewBag) at RazorEngine.Templating.RazorEngineServiceExtensions.<>c__DisplayClass16_0.<RunCompile>b__0(TextWriter writer) at RazorEngine.Templating.RazorEngineServiceExtensions.WithWriter(Action`1 withWriter) at Dynamicweb.Rendering.RazorTemplateRenderingProvider.Render(Template template) at Dynamicweb.Rendering.TemplateRenderingService.Render(Template template) at Dynamicweb.Rendering.Template.RenderRazorTemplate() ClientConnectionId:b42d1cec-597c-4eed-bdc2-e0762a41101a Error Number:9829,State:1,Class:16
1 @inherits Dynamicweb.Rendering.ViewModelTemplate<Dynamicweb.Frontend.ParagraphViewModel> 2 @using System.Globalization 3 @using System.Drawing 4 @using Dynamicweb.Core 5 6 @functions{ 7 // Get Hex Color from color picker and translate to RGB color 8 public static string HexToRGB(string hexString) 9 { 10 if (hexString.Equals("none") || string.IsNullOrEmpty(hexString)) 11 return hexString; 12 13 //replace # occurences 14 if (hexString.IndexOf('#') != -1) 15 hexString = hexString.Replace("#", ""); 16 try 17 { 18 int r, g, b = 0; 19 r = int.Parse(hexString.Substring(0, 2), NumberStyles.AllowHexSpecifier); 20 g = int.Parse(hexString.Substring(2, 2), NumberStyles.AllowHexSpecifier); 21 b = int.Parse(hexString.Substring(4, 2), NumberStyles.AllowHexSpecifier); 22 23 string rgb = r + "," + g + "," + b; 24 return rgb; 25 } 26 catch (System.Exception) 27 { 28 return hexString; 29 } 30 } 31 32 public static string GetColorSquare(string hex) 33 { 34 return $"<div class=\"swift-checkered d-inline-block me-1\" style=\"height:1.25rem;width:1.25rem;\"><div style=\"background-color: {hex};border:.0625rem solid grey\" class=\"w-100 h-100\"></div></div>"; 35 } 36 37 public class HSL 38 { 39 public double h { get; set; } 40 public double s { get; set; } 41 public double l { get; set; } 42 } 43 44 //Convert HEX to HSL 45 public static HSL HexToHsl(string hexString) 46 { 47 System.Drawing.Color color = System.Drawing.ColorTranslator.FromHtml(hexString); 48 49 float _R = (color.R / 255f); 50 float _G = (color.G / 255f); 51 float _B = (color.B / 255f); 52 53 float _Min = Math.Min(Math.Min(_R, _G), _B); 54 float _Max = Math.Max(Math.Max(_R, _G), _B); 55 float _Delta = _Max - _Min; 56 57 float S = 0; 58 float L = (float)((_Max + _Min) / 2.0f); 59 60 if (_Delta != 0) 61 { 62 if (L < 0.5f) 63 { 64 S = (float)(_Delta / (_Max + _Min)); 65 } 66 else 67 { 68 S = (float)(_Delta / (2.0f - _Max - _Min)); 69 } 70 } 71 72 HSL hsl = new HSL(); 73 hsl.h = Math.Round(color.GetHue(), 2); 74 hsl.s = Math.Round(S, 2) * 100; 75 hsl.l = Math.Round(L, 2) * 100; 76 77 return hsl; 78 } 79 80 //Find contrast color (white, black) 81 public static Color GetContrastColor(string hexString) 82 { 83 System.Drawing.Color bg = System.Drawing.ColorTranslator.FromHtml(hexString); 84 85 int nThreshold = 105; 86 int bgDelta = Convert.ToInt32((bg.R * 0.299) + (bg.G * 0.587) + 87 (bg.B * 0.114)); 88 89 Color foreColor = (255 - bgDelta < nThreshold) ? Color.Black : Color.White; 90 return foreColor; 91 } 92 93 public string GetColorVariation(string hexString) 94 { 95 var contrast = GetContrastColor(hexString); 96 HSL currentHslColor = HexToHsl(hexString); 97 HSL variantHslColor = currentHslColor; 98 99 if (contrast == Color.Black) 100 { 101 variantHslColor.l = 85; //The background is dark - Color should be light 102 } 103 else 104 { 105 variantHslColor.l = 40; //The background is light - Color should be less light 106 } 107 108 //Color is very light 109 if (currentHslColor.l > 85) 110 { 111 variantHslColor.l = 95; 112 } 113 114 string colorString = variantHslColor.h + ", " + variantHslColor.s + "%, " + variantHslColor.l + "%"; 115 return colorString; 116 } 117 118 private class ThemeDatabaseUsage 119 { 120 public string TableName { get; set; } 121 public string ColumnName { get; set; } 122 } 123 124 private class ThemeUsage 125 { 126 public string Id { get; set; } 127 public List<int> WebsiteUsages { get; set; } = new List<int>(); 128 public List<int> PageUsages { get; set; } = new List<int>(); 129 public List<int> PagePropertyUsages { get; set; } = new List<int>(); 130 public List<int> GridRowUsages { get; set; } = new List<int>(); 131 public List<int> ParagraphUsages { get; set; } = new List<int>(); 132 public int AllUsages { get; set; } = 0; 133 } 134 135 private List<ThemeDatabaseUsage> GetThemeColumnsFromSchema() 136 { 137 string cacheKey = "ThemesFromDatabase"; 138 if (Dynamicweb.Context.Current.Items.Contains(cacheKey)) 139 { 140 return (List<ThemeDatabaseUsage>)Dynamicweb.Context.Current.Items[cacheKey]; 141 } 142 var schema = Dynamicweb.Data.Database.CreateDataReader("SELECT table_name, column_name FROM information_schema.columns WHERE column_name LIKE '%Theme%'"); 143 144 var rawData = new List<ThemeDatabaseUsage>(); 145 while (schema.Read()) { 146 rawData.Add(new ThemeDatabaseUsage {TableName = schema["table_name"].ToString(), ColumnName = schema["column_name"].ToString() }); 147 } 148 Dynamicweb.Context.Current.Items[cacheKey] = rawData; 149 return rawData; 150 } 151 152 private List<ThemeUsage> GetAllThemeUsages() 153 { 154 string cacheKey = "ThemeUsages"; 155 if (Dynamicweb.Context.Current.Items.Contains(cacheKey)) 156 { 157 return (List<ThemeUsage>)Dynamicweb.Context.Current.Items[cacheKey]; 158 } 159 160 var rawData = GetThemeColumnsFromSchema(); 161 var themeUsages = new List<ThemeUsage>(); 162 163 var sqlQuery = ""; 164 foreach (var row in rawData) 165 { 166 if (!string.IsNullOrEmpty(sqlQuery)) { sqlQuery += " UNION ALL "; } 167 sqlQuery += $"SELECT '{row.TableName}' AS TableName, '{row.ColumnName}' AS ColumnName, {row.ColumnName} AS ColumnValue, Id, AreaId, Page.PageId, PageProperties.PageId as 'PagePropertiesId', GridRowId, ParagraphId" + 168 $" FROM [{row.TableName}]" + 169 $" LEFT JOIN Area ON AreaItemType = '{row.TableName.Replace("ItemType_","")}' AND AreaItemId = Id" + 170 $" LEFT JOIN Page ON PageItemType = '{row.TableName.Replace("ItemType_","")}' AND PageItemId = Id" + 171 $" LEFT JOIN Page as PageProperties ON AreaItemTypePageProperty = '{row.TableName.Replace("ItemType_","")}' AND PageProperties.PagePropertyItemId = Id" + 172 $" LEFT JOIN GridRow ON GridRowItemType = '{row.TableName.Replace("ItemType_","")}' AND GridRowItemId = Id" + 173 $" LEFT JOIN Paragraph ON ParagraphItemType = '{row.TableName.Replace("ItemType_","")}' AND ParagraphItemId = Id" + 174 $" WHERE {row.ColumnName} != '' AND {row.ColumnName} IS NOT NULL" + 175 $" AND (AreaId IS NULL OR AreaId = {Pageview.AreaID})" + 176 $" AND (Page.PageId IS NULL OR Page.PageAreaId = {Pageview.AreaID})" + 177 $" AND (PageProperties.PageId IS NULL OR PageProperties.PageAreaId = {Pageview.AreaID})" + 178 $" AND (GridRowId IS NULL OR GridRowPageId IN (SELECT value From string_split(@pageIds, ',')))" + 179 $" AND (ParagraphId IS NULL OR ParagraphPageId IN (SELECT value From string_split(@pageIds, ',')))"; 180 181 var maxMsSqlServerCharLimit = 60000; 182 if (sqlQuery.Length > maxMsSqlServerCharLimit) 183 { 184 UpdateThemeUsages(sqlQuery, themeUsages); 185 sqlQuery = ""; 186 } 187 } 188 189 if (!string.IsNullOrEmpty(sqlQuery)) 190 { 191 UpdateThemeUsages(sqlQuery, themeUsages); 192 } 193 UpdateAllUsages(themeUsages); 194 195 Dynamicweb.Context.Current.Items[cacheKey] = themeUsages; 196 return themeUsages; 197 } 198 199 private void UpdateThemeUsages(string sqlQuery, List<ThemeUsage> themeUsages) 200 { 201 sqlQuery = $"DECLARE @pageIds NVARCHAR(max) = (SELECT STRING_AGG(PageId,',') FROM Page WHERE PageAreaId = {Pageview.AreaID}) " + sqlQuery; 202 var rawData = Dynamicweb.Data.Database.CreateDataReader(sqlQuery); 203 while (rawData.Read()) 204 { 205 var themeId = rawData["ColumnValue"].ToString(); 206 var themeUsageExists = themeUsages.FirstOrDefault(t => t.Id == themeId) != null; 207 if (!themeUsageExists) 208 { 209 themeUsages.Add(new ThemeUsage { Id = themeId }); 210 } 211 212 var themeUsage = themeUsages.FirstOrDefault(t => t.Id == themeId); 213 if (themeUsage == null) continue; 214 215 if (Converter.ToInt32(rawData["AreaId"].ToString()) > 0) { themeUsage.WebsiteUsages.Add(Converter.ToInt32(rawData["AreaId"].ToString())); } 216 if (Converter.ToInt32(rawData["PageId"].ToString()) > 0) { themeUsage.PageUsages.Add(Converter.ToInt32(rawData["PageId"].ToString())); } 217 if (Converter.ToInt32(rawData["PagePropertiesId"].ToString()) > 0) { themeUsage.PagePropertyUsages.Add(Converter.ToInt32(rawData["PagePropertiesId"].ToString())); } 218 if (Converter.ToInt32(rawData["GridRowId"].ToString()) > 0) { themeUsage.GridRowUsages.Add(Converter.ToInt32(rawData["GridRowId"].ToString())); } 219 if (Converter.ToInt32(rawData["ParagraphId"].ToString()) > 0) { themeUsage.ParagraphUsages.Add(Converter.ToInt32(rawData["ParagraphId"].ToString())); } 220 } 221 } 222 223 private void UpdateAllUsages(List<ThemeUsage> themeUsages) 224 { 225 foreach (var themeUsage in themeUsages) 226 { 227 int websiteUsages = themeUsage?.WebsiteUsages.Count ?? 0; 228 int pageUsages = themeUsage?.PageUsages.Count ?? 0; 229 int pagePropertyUsages = themeUsage?.PagePropertyUsages.Count ?? 0; 230 int gridRowUsages = themeUsage?.GridRowUsages.Count ?? 0; 231 int paragraphUsages = themeUsage?.ParagraphUsages.Count ?? 0; 232 themeUsage.AllUsages = websiteUsages + pageUsages + pagePropertyUsages + gridRowUsages + paragraphUsages; 233 } 234 } 235 236 private ThemeUsage GetThemeUsageById(string themeId) 237 { 238 var themeUsages = GetAllThemeUsages(); 239 return themeUsages.FirstOrDefault(t => t.Id == themeId); 240 } 241 242 } 243 244 @{ 245 string themeName = !string.IsNullOrWhiteSpace(Model.Item.GetString("Name")) ? Model.Item.GetString("Name") : "Default"; 246 string themeClassName = !string.IsNullOrWhiteSpace(Model.Item.GetString("CSSClassName")) ? Model.Item.GetString("CSSClassName").Replace(" ", "").Trim().ToLower() : ""; 247 248 //Theme colors 249 string foregroundColor = Model.Item.GetString("ForegroundColor", "currentColor"); 250 string backgroundColor = Model.Item.GetString("BackgroundColor", "transparent"); 251 string accentColor = Model.Item.GetString("accentColor", "currentColor"); 252 string borderColor = Model.Item.GetString("BorderColor", "transparent"); 253 254 //Primary button 255 string buttonPrimaryForegroundColor = Model.Item.GetString("ButtonPrimaryForegroundColor", "currentColor"); 256 string buttonPrimaryBackgroundColor = Model.Item.GetString("ButtonPrimaryBackgroundColor", "transparent"); 257 string buttonPrimaryBorderColor = Model.Item.GetString("ButtonPrimaryBorderColor", "transparent"); 258 259 string buttonPrimaryHoverBackgroundColorAuto = "transparent"; 260 if (buttonPrimaryBackgroundColor != "transparent") 261 { 262 buttonPrimaryHoverBackgroundColorAuto = "hsl(" + GetColorVariation(buttonPrimaryBackgroundColor) + ")"; 263 } 264 string buttonPrimaryHoverForegroundColor = Model.Item.GetString("ButtonPrimaryHoverForegroundColor", buttonPrimaryForegroundColor); 265 string buttonPrimaryHoverBackgroundColor = Model.Item.GetString("ButtonPrimaryHoverBackgroundColor", buttonPrimaryHoverBackgroundColorAuto); 266 string buttonPrimaryHoverBorderColor = Model.Item.GetString("ButtonPrimaryHoverBorderColor", buttonPrimaryBorderColor); 267 268 //Secondary buton 269 string buttonSecondaryForegroundColor = Model.Item.GetString("ButtonSecondaryForegroundColor", "currentColor"); 270 string buttonSecondaryBackgroundColor = Model.Item.GetString("ButtonSecondaryBackgroundColor", "transparent"); 271 string buttonSecondaryBorderColor = Model.Item.GetString("ButtonSecondaryBorderColor", "transparent"); 272 273 string buttonSecondaryHoverBackgroundColorAuto = "transparent"; 274 if (buttonSecondaryBackgroundColor != "transparent") 275 { 276 buttonSecondaryHoverBackgroundColorAuto = "hsl(" + GetColorVariation(buttonSecondaryBackgroundColor) + ")"; 277 } 278 string buttonSecondaryHoverForegroundColor = Model.Item.GetString("ButtonSecondaryHoverForegroundColor", buttonSecondaryForegroundColor); 279 string buttonSecondaryHoverBackgroundColor = Model.Item.GetString("ButtonSecondaryHoverBackgroundColor", buttonSecondaryHoverBackgroundColorAuto); 280 string buttonSecondaryHoverBorderColor = Model.Item.GetString("ButtonSecondaryHoverBorderColor", buttonSecondaryBorderColor); 281 282 //Link buton 283 string buttonLinkColor = Model.Item.GetString("ButtonLinkColor", "currentColor"); 284 string buttonLinkHoverColorAuto = "currentColor"; 285 if (buttonLinkColor != "currentColor") 286 { 287 buttonLinkHoverColorAuto = "hsl(" + GetColorVariation(buttonLinkColor) + ")"; 288 } 289 string buttonLinkHoverColor = Model.Item.GetString("ButtonLinkHoverColor", buttonLinkHoverColorAuto); 290 291 string accessibilityOutlineColor = Model.Item.GetString("OutlineColor") != null ? Model.Item.GetString("OutlineColor") : ""; 292 293 if (!string.IsNullOrEmpty(themeClassName)) 294 { 295 var sb = new System.Text.StringBuilder(); 296 297 sb.AppendLine("." + themeClassName + "{"); 298 if (!string.IsNullOrEmpty(foregroundColor)) 299 { 300 sb.AppendLine($"--swift-foreground-color: {foregroundColor};"); 301 sb.AppendLine($"--swift-foreground-color-rgb: {HexToRGB(foregroundColor)};"); 302 } 303 if (!string.IsNullOrEmpty(backgroundColor)) 304 { 305 sb.AppendLine($"--swift-background-color: {backgroundColor};"); 306 sb.AppendLine($"--swift-background-color-rgb: {HexToRGB(backgroundColor)};"); 307 } 308 if (!string.IsNullOrEmpty(accentColor)) 309 { 310 sb.AppendLine($"--swift-accent-color: {accentColor};"); 311 sb.AppendLine($"--swift-accent-color-rgb: {HexToRGB(accentColor)};"); 312 } 313 if (!string.IsNullOrEmpty(borderColor)) 314 { 315 sb.AppendLine($"--swift-border-color: {borderColor};"); 316 sb.AppendLine($"--swift-border-color-rgb: {HexToRGB(borderColor)};"); 317 } 318 319 if (!string.IsNullOrEmpty(buttonPrimaryBackgroundColor)) 320 { 321 sb.AppendLine($"--swift-button-primary-background-color: {buttonPrimaryBackgroundColor};"); 322 sb.AppendLine($"--swift-button-primary-background-color-rgb: {HexToRGB(buttonPrimaryBackgroundColor)};"); 323 } 324 if (!string.IsNullOrEmpty(buttonPrimaryForegroundColor)) 325 { 326 sb.AppendLine($"--swift-button-primary-foreground-color: {buttonPrimaryForegroundColor};"); 327 sb.AppendLine($"--swift-button-primary-foreground-color-rgb: {HexToRGB(buttonPrimaryForegroundColor)};"); 328 } 329 if (!string.IsNullOrEmpty(buttonPrimaryBorderColor)) 330 { 331 sb.AppendLine($"--swift-button-primary-border-color: {buttonPrimaryBorderColor};"); 332 sb.AppendLine($"--swift-button-primary-border-color-rgb: {HexToRGB(buttonPrimaryBorderColor)};"); 333 } 334 335 if (!string.IsNullOrEmpty(buttonPrimaryHoverBackgroundColor)) 336 { 337 sb.AppendLine($"--swift-button-primary-hover-background-color: {buttonPrimaryHoverBackgroundColor};"); 338 sb.AppendLine($"--swift-button-primary-hover-background-color-rgb: {HexToRGB(buttonPrimaryHoverBackgroundColor)};"); 339 } 340 if (!string.IsNullOrEmpty(buttonPrimaryHoverForegroundColor)) 341 { 342 sb.AppendLine($"--swift-button-primary-hover-foreground-color: {buttonPrimaryHoverForegroundColor};"); 343 sb.AppendLine($"--swift-button-primary-hover-foreground-color-rgb: {HexToRGB(buttonPrimaryHoverForegroundColor)};"); 344 } 345 if (!string.IsNullOrEmpty(buttonPrimaryHoverBorderColor)) 346 { 347 sb.AppendLine($"--swift-button-primary-hover-border-color: {buttonPrimaryHoverBorderColor};"); 348 sb.AppendLine($"--swift-button-primary-hover-border-color-rgb: {HexToRGB(buttonPrimaryHoverBorderColor)};"); 349 } 350 351 if (!string.IsNullOrEmpty(buttonSecondaryBackgroundColor)) 352 { 353 sb.AppendLine($"--swift-button-secondary-background-color: {buttonSecondaryBackgroundColor};"); 354 sb.AppendLine($"--swift-button-secondary-background-color-rgb: {HexToRGB(buttonSecondaryBackgroundColor)};"); 355 } 356 if (!string.IsNullOrEmpty(buttonSecondaryForegroundColor)) 357 { 358 sb.AppendLine($"--swift-button-secondary-foreground-color: {buttonSecondaryForegroundColor};"); 359 sb.AppendLine($"--swift-button-secondary-foreground-color-rgb: {HexToRGB(buttonSecondaryForegroundColor)};"); 360 } 361 if (!string.IsNullOrEmpty(buttonSecondaryBorderColor)) 362 { 363 sb.AppendLine($"--swift-button-secondary-border-color: {buttonSecondaryBorderColor};"); 364 sb.AppendLine($"--swift-button-secondary-border-color-rgb: {HexToRGB(buttonSecondaryBorderColor)};"); 365 } 366 if (!string.IsNullOrEmpty(buttonSecondaryHoverBackgroundColor)) 367 { 368 sb.AppendLine($"--swift-button-secondary-hover-background-color: {buttonSecondaryHoverBackgroundColor};"); 369 sb.AppendLine($"--swift-button-secondary-hover-background-color-rgb: {HexToRGB(buttonSecondaryHoverBackgroundColor)};"); 370 } 371 if (!string.IsNullOrEmpty(buttonSecondaryHoverForegroundColor)) 372 { 373 sb.AppendLine($"--swift-button-secondary-hover-foreground-color: {buttonSecondaryHoverForegroundColor};"); 374 sb.AppendLine($"--swift-button-secondary-hover-foreground-color-rgb: {HexToRGB(buttonSecondaryHoverForegroundColor)};"); 375 } 376 if (!string.IsNullOrEmpty(buttonSecondaryHoverBorderColor)) 377 { 378 sb.AppendLine($"--swift-button-secondary-hover-border-color: {buttonSecondaryHoverBorderColor};"); 379 sb.AppendLine($"--swift-button-secondary-hover-border-color-rgb: {HexToRGB(buttonSecondaryHoverBorderColor)};"); 380 } 381 if (!string.IsNullOrEmpty(buttonLinkColor)) 382 { 383 sb.AppendLine($"--swift-button-link-color: {buttonLinkColor};"); 384 sb.AppendLine($"--swift-button-link-color-rgb: {HexToRGB(buttonLinkColor)};"); 385 } 386 if (!string.IsNullOrEmpty(buttonLinkHoverColor)) 387 { 388 sb.AppendLine($"--swift-button-link-hover-color: {buttonLinkHoverColor};"); 389 sb.AppendLine($"--swift-button-link-hover-color-rgb: {HexToRGB(buttonLinkHoverColor)};"); 390 } 391 if (!string.IsNullOrEmpty(accessibilityOutlineColor)) 392 { 393 sb.AppendLine($"--swift-a11y-outline-color: {accessibilityOutlineColor};"); 394 sb.AppendLine($"--swift-a11y-outline-color-rgb: {HexToRGB(accessibilityOutlineColor)};"); 395 } 396 sb.AppendLine("}"); 397 398 Dynamicweb.Core.Helpers.TextFileHelper.WriteTextFile(sb.ToString() + Environment.NewLine, Dynamicweb.Context.Current.Server.MapPath($"/Files/Templates/Designs/Swift/_parsed/Swift_css/Swift_theme_styles_{Dynamicweb.Content.Services.Pages.GetPage(Model.PageID).AreaId}.tmp"), true); 399 } 400 } 401 402 @if (themeClassName != "") 403 { 404 string iconPath = "/Files/Templates/Designs/Swift/Assets/icons/"; 405 406 <div class="g-col-12 g-col-lg-4"> 407 <div class="swift-checkered p-3"> 408 <div class="theme-option theme @themeClassName p-lg-3"> 409 <div class="mb-2 pb-1 border-bottom d-flex align-items-center"> 410 <span class="icon-3 me-2"> 411 @ReadFile(iconPath + "sun.svg") 412 </span> 413 <h4 class="m-0 p-0">@themeName</h4> 414 </div> 415 <div class="d-flex flex-column gap-1 mb-2"> 416 <p class="mb-0">This is the body text of the theme.</p> 417 <p class="mb-0" style="color: var(--swift-accent-color)">This is the accent color of the theme.</p> 418 </div> 419 <div> 420 <button class="btn btn-primary me-1">Primary</button> 421 <button class="btn btn-secondary">Secondary</button> 422 <button class="btn btn-link">Link</button> 423 </div> 424 </div> 425 </div> 426 </div> 427 <div class="g-col-12 g-col-lg-8 mb-4 mb-lg-0"> 428 <div class="grid fs-7"> 429 <div class="g-col-12 g-col-lg-3"> 430 <table class="table table-borderless table-sm w-100"> 431 <thead> 432 <tr> 433 <th colspan="2" class="fw-bold">@Translate("Base")</th> 434 </tr> 435 </thead> 436 <tr> 437 <td>@Translate("Foreground")</td> 438 <td>@GetColorSquare(foregroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@foregroundColor');">@foregroundColor</a></td> 439 </tr> 440 <tr> 441 <td>@Translate("Background")</td> 442 <td>@GetColorSquare(backgroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@backgroundColor');">@backgroundColor</a></td> 443 </tr> 444 <tr> 445 <td>@Translate("Accent")</td> 446 <td>@GetColorSquare(accentColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@accentColor');">@accentColor</a></td> 447 </tr> 448 <tr> 449 <td>@Translate("Border")</td> 450 <td>@GetColorSquare(borderColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@borderColor');">@borderColor</a></td> 451 </tr> 452 </table> 453 </div> 454 <div class="g-col-12 g-col-lg-3"> 455 <table class="table table-borderless table-sm w-100"> 456 <thead> 457 <tr> 458 <th colspan="2" class="fw-bold">@Translate("Primary button")</th> 459 </tr> 460 </thead> 461 <tr> 462 <td>@Translate("Foreground")</td> 463 <td>@GetColorSquare(buttonPrimaryForegroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonPrimaryForegroundColor');">@buttonPrimaryForegroundColor</a></td> 464 </tr> 465 <tr> 466 <td>@Translate("Background")</td> 467 <td>@GetColorSquare(buttonPrimaryBackgroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonPrimaryBackgroundColor');">@buttonPrimaryBackgroundColor</a></td> 468 </tr> 469 @if (!string.IsNullOrEmpty(buttonPrimaryBorderColor)) 470 { 471 <tr> 472 <td>@Translate("Border")</td> 473 <td>@GetColorSquare(buttonPrimaryBorderColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonPrimaryBorderColor');">@buttonPrimaryBorderColor</a></td> 474 </tr> 475 } 476 <thead> 477 <tr> 478 <th colspan="2" class="fw-bold">@Translate("Primary button hover")</th> 479 </tr> 480 </thead> 481 @if (!string.IsNullOrEmpty(buttonPrimaryHoverForegroundColor)) 482 { 483 <tr> 484 <td>@Translate("Foreground")</td> 485 <td>@GetColorSquare(buttonPrimaryHoverForegroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonPrimaryHoverForegroundColor');">@buttonPrimaryHoverForegroundColor</a></td> 486 </tr> 487 } 488 @if (!string.IsNullOrEmpty(buttonPrimaryHoverBackgroundColor)) 489 { 490 <tr> 491 <td>@Translate("Background")</td> 492 <td>@GetColorSquare(buttonPrimaryHoverBackgroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonPrimaryHoverBackgroundColor');">@buttonPrimaryHoverBackgroundColor</a></td> 493 </tr> 494 } 495 @if (!string.IsNullOrEmpty(buttonPrimaryHoverBorderColor)) 496 { 497 <tr> 498 <td>@Translate("Border")</td> 499 <td>@GetColorSquare(buttonPrimaryHoverBorderColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonPrimaryHoverBorderColor');">@buttonPrimaryHoverBorderColor</a></td> 500 </tr> 501 } 502 </table> 503 </div> 504 <div class="g-col-12 g-col-lg-3"> 505 <table class="table table-borderless table-sm w-100"> 506 <thead> 507 <tr> 508 <th colspan="2" class="fw-bold">@Translate("Secondary button")</th> 509 </tr> 510 </thead> 511 <tr> 512 <td>@Translate("Foreground")</td> 513 <td>@GetColorSquare(buttonSecondaryForegroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonSecondaryForegroundColor');">@buttonSecondaryForegroundColor</a></td> 514 </tr> 515 <tr> 516 <td>@Translate("Background")</td> 517 <td>@GetColorSquare(buttonSecondaryBackgroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonSecondaryBackgroundColor');">@buttonSecondaryBackgroundColor</a></td> 518 </tr> 519 @if (!string.IsNullOrEmpty(buttonSecondaryBorderColor)) 520 { 521 <tr> 522 <td>@Translate("Border")</td> 523 <td>@GetColorSquare(buttonSecondaryBorderColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonSecondaryBorderColor');">@buttonSecondaryBorderColor</a></td> 524 </tr> 525 } 526 <thead> 527 <tr> 528 <th colspan="2" class="fw-bold">@Translate("Secondary button hover")</th> 529 </tr> 530 </thead> 531 @if (!string.IsNullOrEmpty(buttonSecondaryHoverForegroundColor)) 532 { 533 <tr> 534 <td>@Translate("Foreground")</td> 535 <td>@GetColorSquare(buttonSecondaryHoverForegroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonSecondaryHoverForegroundColor');">@buttonSecondaryHoverForegroundColor</a></td> 536 </tr> 537 } 538 @if (!string.IsNullOrEmpty(buttonSecondaryHoverBackgroundColor)) 539 { 540 <tr> 541 <td>@Translate("Background")</td> 542 <td>@GetColorSquare(buttonSecondaryHoverBackgroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonSecondaryHoverBackgroundColor');">@buttonSecondaryHoverBackgroundColor</a></td> 543 </tr> 544 } 545 @if (!string.IsNullOrEmpty(buttonSecondaryHoverBorderColor)) 546 { 547 <tr> 548 <td>@Translate("Border")</td> 549 <td>@GetColorSquare(buttonSecondaryHoverBorderColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonSecondaryHoverBorderColor');">@buttonSecondaryHoverBorderColor</a></td> 550 </tr> 551 } 552 @if (!string.IsNullOrEmpty(accessibilityOutlineColor)) 553 { 554 <tr> 555 <td>@Translate("Focus outline")</td> 556 <td>@GetColorSquare(accessibilityOutlineColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@accessibilityOutlineColor');">@accessibilityOutlineColor</a></td> 557 </tr> 558 } 559 </table> 560 </div> 561 <div class="g-col-12 g-col-lg-3"> 562 <table class="table table-borderless table-sm w-100"> 563 <thead> 564 <tr> 565 <th colspan="2" class="fw-bold">@Translate("Link button")</th> 566 </tr> 567 </thead> 568 <tr> 569 <td>@Translate("Link color")</td> 570 <td>@GetColorSquare(buttonLinkColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonLinkColor');">@buttonLinkColor</a></td> 571 </tr> 572 <thead> 573 <tr> 574 <th colspan="2" class="fw-bold">@Translate("Link button hover")</th> 575 </tr> 576 </thead> 577 @if (!string.IsNullOrEmpty(buttonLinkHoverColor)) 578 { 579 <tr> 580 <td>@Translate("Link hover color")</td> 581 <td>@GetColorSquare(buttonLinkHoverColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonLinkHoverColor');">@buttonLinkHoverColor</a></td> 582 </tr> 583 } 584 585 @if (!string.IsNullOrEmpty(accessibilityOutlineColor)) 586 { 587 <tr> 588 <td>@Translate("Focus outline")</td> 589 <td>@GetColorSquare(accessibilityOutlineColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@accessibilityOutlineColor');">@accessibilityOutlineColor</a></td> 590 </tr> 591 } 592 </table> 593 </div> 594 <div class="g-col-12 g-col-lg-3"> 595 <table class="table table-borderless table-sm w-100"> 596 <tr> 597 <td class="fw-bold">@Translate("Implementation")</td> 598 </tr> 599 <tr> 600 <td> 601 @{ 602 string implementation = $"<div class=\"theme {themeClassName}\"></div>"; 603 } 604 <div class="text-muted"> 605 <code class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@themeClassName');"> 606 @Dynamicweb.Core.Encoders.HtmlEncoder.HtmlEncode(implementation) 607 </code> 608 </div> 609 </td> 610 </tr> 611 </table> 612 </div> 613 @{ 614 bool hasUsageData = Converter.ToBoolean(Dynamicweb.Context.Current.Request["auditUsages"]); 615 if (hasUsageData) 616 { 617 var themeUsage = GetThemeUsageById(themeClassName); 618 int allUsages = themeUsage?.AllUsages ?? 0; 619 string buttonAttributes = allUsages > 0 ? $"data-bs-toggle=\"modal\" data-bs-target=\"#themeUsage_{Model.ID}\"" : string.Empty; 620 string badgeStyle = allUsages > 0 ? "bg-success" : "bg-danger"; 621 622 <div class="g-col-12 g-col-lg-9 position-relative"> 623 <button type="button" class="btn btn-primary btn-sm position-absolute end-0" @buttonAttributes> 624 Usages 625 <span class="position-absolute top-0 start-100 translate-middle badge rounded-pill text-white @badgeStyle">@allUsages</span> 626 </button> 627 628 @if (allUsages > 0) 629 { 630 int websiteUsages = themeUsage?.WebsiteUsages.Count ?? 0; 631 int pageUsages = themeUsage?.PageUsages.Count ?? 0; 632 int pagePropertyUsages = themeUsage?.PagePropertyUsages.Count ?? 0; 633 int gridRowUsages = themeUsage?.GridRowUsages.Count ?? 0; 634 int paragraphUsages = themeUsage?.ParagraphUsages.Count ?? 0; 635 636 <!-- Modal --> 637 <div class="modal fade" id="themeUsage_@(Model.ID)" tabindex="-1" aria-labelledby="usagesModelLabel" aria-hidden="true"> 638 <div class="modal-dialog modal-xl modal-dialog-centered modal-dialog-scrollable"> 639 <div class="modal-content"> 640 <div class="modal-header"> 641 <h5 class="modal-title" id="usagesModelLabel">@allUsages Usages of '@(themeName)' (@(themeClassName))</h5> 642 <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> 643 </div> 644 <div class="modal-body"> 645 <div class="accordion" id="accordionWrapper"> 646 @if(websiteUsages > 0) 647 { 648 <div class="accordion-item"> 649 <h2 class="accordion-header" id="headingWebsites"> 650 <button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#collapseWebsites" aria-expanded="true" aria-controls="collapseWebsites"> 651 <span class="pe-2">Websites</span><span class="badge rounded-pill bg-secondary text-light">@websiteUsages</span> 652 </button> 653 </h2> 654 <div id="collapseWebsites" class="accordion-collapse collapse show" aria-labelledby="headingWebsites" data-bs-parent="#accordionWrapper"> 655 <div class="accordion-body"> 656 <ul> 657 @foreach (var usage in themeUsage.WebsiteUsages) 658 { 659 var website = Dynamicweb.Content.Services.Areas.GetArea(usage); 660 <li><span class="fw-bold">@website.Name</span>@($" (ID: {usage})")</li> 661 } 662 </ul> 663 </div> 664 </div> 665 </div> 666 } 667 @if (pageUsages > 0) 668 { 669 var pages = Dynamicweb.Content.Services.Pages.GetPages(themeUsage.PageUsages.ToArray()); 670 671 <div class="accordion-item"> 672 <h2 class="accordion-header" id="headingPages"> 673 <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapsePages" aria-expanded="false" aria-controls="collapsePages"> 674 <span class="pe-2">Pages</span><span class="badge rounded-pill bg-secondary text-light">@pageUsages</span> 675 </button> 676 </h2> 677 <div id="collapsePages" class="accordion-collapse collapse" aria-labelledby="headingPages" data-bs-parent="#accordionWrapper"> 678 <div class="accordion-body"> 679 <ul> 680 @foreach (var usage in themeUsage.PageUsages) 681 { 682 <li><span class="fw-bold">@pages.FirstOrDefault(p => p.ID == usage).GetDisplayName()</span>@($" (ID: {usage})")</li> 683 } 684 </ul> 685 </div> 686 </div> 687 </div> 688 } 689 @if (pagePropertyUsages > 0) 690 { 691 var pages = Dynamicweb.Content.Services.Pages.GetPages(themeUsage.PageUsages.ToArray()); 692 693 <div class="accordion-item"> 694 <h2 class="accordion-header" id="headingPageProperties"> 695 <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapsePageProperties" aria-expanded="false" aria-controls="collapsePageProperties"> 696 <span class="pe-2">Page Properties</span><span class="badge rounded-pill bg-secondary text-light">@pagePropertyUsages</span> 697 </button> 698 </h2> 699 <div id="collapsePageProperties" class="accordion-collapse collapse" aria-labelledby="headingPageProperties" data-bs-parent="#accordionWrapper"> 700 <div class="accordion-body"> 701 <ul> 702 @foreach (var usage in themeUsage.PagePropertyUsages) 703 { 704 <li><span class="fw-bold">@pages.FirstOrDefault(p => p.ID == usage).GetDisplayName()</span>@($" (ID: {usage})")</li> 705 } 706 </ul> 707 </div> 708 </div> 709 </div> 710 } 711 @if (gridRowUsages > 0) 712 { 713 var rows = Dynamicweb.Content.Services.Grids.GetGridRows().Where(r => themeUsage.GridRowUsages.Contains(r.ID)).ToList(); 714 715 <div class="accordion-item"> 716 <h2 class="accordion-header" id="headingRows"> 717 <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseRows" aria-expanded="false" aria-controls="collapseRows"> 718 <span class="pe-2">Rows</span><span class="badge rounded-pill bg-secondary text-light">@gridRowUsages</span> 719 </button> 720 </h2> 721 <div id="collapseRows" class="accordion-collapse collapse" aria-labelledby="headingRows" data-bs-parent="#accordionWrapper"> 722 <div class="accordion-body"> 723 <ul> 724 @foreach (var usage in themeUsage.GridRowUsages) 725 { 726 var row = rows.FirstOrDefault(r => r.ID == usage); 727 var page = Dynamicweb.Content.Services.Pages.GetPage(row.PageId); 728 <li>Page: <span class="fw-bold">@(page.GetDisplayName())</span>@($"( ID: {page.ID}) - Row: ")<span class="fw-bold">@(row.DefinitionId)</span>@($" (ID: {usage})")</li> 729 } 730 </ul> 731 </div> 732 </div> 733 </div> 734 } 735 @if (paragraphUsages > 0) 736 { 737 var paragraphs = Dynamicweb.Content.Services.Paragraphs.GetParagraphs().Where(p => themeUsage.ParagraphUsages.Contains(p.ID)).ToList(); 738 739 <div class="accordion-item"> 740 <h2 class="accordion-header" id="headingParagraphs"> 741 <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseParagraphs" aria-expanded="false" aria-controls="collapseParagraphs"> 742 <span class="pe-2">Paragraphs</span><span class="badge rounded-pill bg-secondary text-light">@paragraphUsages</span> 743 </button> 744 </h2> 745 <div id="collapseParagraphs" class="accordion-collapse collapse" aria-labelledby="headingParagraphs" data-bs-parent="#accordionWrapper"> 746 <div class="accordion-body"> 747 <ul> 748 @foreach (var usage in themeUsage.ParagraphUsages) 749 { 750 var paragraph = paragraphs.FirstOrDefault(p => p.ID == usage); 751 var page = Dynamicweb.Content.Services.Pages.GetPage(paragraph.PageID); 752 <li>Page: <span class="fw-bold">@(page.GetDisplayName())</span>@($"( ID: {page.ID}) - Paragraph: ")<span class="fw-bold">@paragraph.Header</span>@($" (ID: {usage})")</li> 753 } 754 </ul> 755 </div> 756 </div> 757 </div> 758 } 759 </div> 760 </div> 761 </div> 762 </div> 763 </div> 764 } 765 </div> 766 } 767 } 768 </div> 769 </div> 770 } 771 <div class="g-col-12"> 772 <hr /> 773 </div> 774
Error executing template "Designs/Swift/Paragraph/Swift_Theme.cshtml" System.Data.SqlClient.SqlException (0x80131904): STRING_AGG aggregation result exceeded the limit of 8000 bytes. Use LOB types to avoid result truncation. at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction) at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose) at System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady) at System.Data.SqlClient.SqlDataReader.TryConsumeMetaData() at System.Data.SqlClient.SqlDataReader.get_MetaData() at System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString, Boolean isInternal, Boolean forDescribeParameterEncryption, Boolean shouldCacheForAlwaysEncrypted) at System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async, Int32 timeout, Task& task, Boolean asyncWrite, Boolean inRetry, SqlDataReader ds, Boolean describeParameterEncryptionRequest) at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, TaskCompletionSource`1 completion, Int32 timeout, Task& task, Boolean& usedCache, Boolean asyncWrite, Boolean inRetry) at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method) at System.Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior behavior, String method) at Dynamicweb.Data.Database.CreateDataReader(IDbCommand command, CommandBehavior behavior) at Dynamicweb.Data.Database.CreateDataReader(String sql, IDbConnection connection, IDbTransaction transaction, CommandBehavior behavior, Int32 commandTimeout, Dictionary`2 sqlParams) at Dynamicweb.Data.Database.CreateDataReader(String sql, IDbConnection connection, IDbTransaction transaction, Int32 commandTimeout, Dictionary`2 sqlParams) at Dynamicweb.Data.Database.CreateDataReader(String sql) at CompiledRazorTemplates.Dynamic.RazorEngine_8e3f1b11eb0041ceb2ca487c2be837e6.UpdateThemeUsages(String sqlQuery, List`1 themeUsages) in E:\Dynamicweb.net\Solutions\Dynamicweb\dw2022.cloud.dynamicweb-cms.com\Files\Templates\Designs\Swift\Paragraph\Swift_Theme.cshtml:line 202 at CompiledRazorTemplates.Dynamic.RazorEngine_8e3f1b11eb0041ceb2ca487c2be837e6.GetAllThemeUsages() in E:\Dynamicweb.net\Solutions\Dynamicweb\dw2022.cloud.dynamicweb-cms.com\Files\Templates\Designs\Swift\Paragraph\Swift_Theme.cshtml:line 184 at CompiledRazorTemplates.Dynamic.RazorEngine_8e3f1b11eb0041ceb2ca487c2be837e6.GetThemeUsageById(String themeId) in E:\Dynamicweb.net\Solutions\Dynamicweb\dw2022.cloud.dynamicweb-cms.com\Files\Templates\Designs\Swift\Paragraph\Swift_Theme.cshtml:line 238 at CompiledRazorTemplates.Dynamic.RazorEngine_8e3f1b11eb0041ceb2ca487c2be837e6.Execute() in E:\Dynamicweb.net\Solutions\Dynamicweb\dw2022.cloud.dynamicweb-cms.com\Files\Templates\Designs\Swift\Paragraph\Swift_Theme.cshtml:line 617 at RazorEngine.Templating.TemplateBase.RazorEngine.Templating.ITemplate.Run(ExecuteContext context, TextWriter reader) at RazorEngine.Templating.RazorEngineService.RunCompile(ITemplateKey key, TextWriter writer, Type modelType, Object model, DynamicViewBag viewBag) at RazorEngine.Templating.RazorEngineServiceExtensions.<>c__DisplayClass16_0.<RunCompile>b__0(TextWriter writer) at RazorEngine.Templating.RazorEngineServiceExtensions.WithWriter(Action`1 withWriter) at Dynamicweb.Rendering.RazorTemplateRenderingProvider.Render(Template template) at Dynamicweb.Rendering.TemplateRenderingService.Render(Template template) at Dynamicweb.Rendering.Template.RenderRazorTemplate() ClientConnectionId:b42d1cec-597c-4eed-bdc2-e0762a41101a Error Number:9829,State:1,Class:16
1 @inherits Dynamicweb.Rendering.ViewModelTemplate<Dynamicweb.Frontend.ParagraphViewModel> 2 @using System.Globalization 3 @using System.Drawing 4 @using Dynamicweb.Core 5 6 @functions{ 7 // Get Hex Color from color picker and translate to RGB color 8 public static string HexToRGB(string hexString) 9 { 10 if (hexString.Equals("none") || string.IsNullOrEmpty(hexString)) 11 return hexString; 12 13 //replace # occurences 14 if (hexString.IndexOf('#') != -1) 15 hexString = hexString.Replace("#", ""); 16 try 17 { 18 int r, g, b = 0; 19 r = int.Parse(hexString.Substring(0, 2), NumberStyles.AllowHexSpecifier); 20 g = int.Parse(hexString.Substring(2, 2), NumberStyles.AllowHexSpecifier); 21 b = int.Parse(hexString.Substring(4, 2), NumberStyles.AllowHexSpecifier); 22 23 string rgb = r + "," + g + "," + b; 24 return rgb; 25 } 26 catch (System.Exception) 27 { 28 return hexString; 29 } 30 } 31 32 public static string GetColorSquare(string hex) 33 { 34 return $"<div class=\"swift-checkered d-inline-block me-1\" style=\"height:1.25rem;width:1.25rem;\"><div style=\"background-color: {hex};border:.0625rem solid grey\" class=\"w-100 h-100\"></div></div>"; 35 } 36 37 public class HSL 38 { 39 public double h { get; set; } 40 public double s { get; set; } 41 public double l { get; set; } 42 } 43 44 //Convert HEX to HSL 45 public static HSL HexToHsl(string hexString) 46 { 47 System.Drawing.Color color = System.Drawing.ColorTranslator.FromHtml(hexString); 48 49 float _R = (color.R / 255f); 50 float _G = (color.G / 255f); 51 float _B = (color.B / 255f); 52 53 float _Min = Math.Min(Math.Min(_R, _G), _B); 54 float _Max = Math.Max(Math.Max(_R, _G), _B); 55 float _Delta = _Max - _Min; 56 57 float S = 0; 58 float L = (float)((_Max + _Min) / 2.0f); 59 60 if (_Delta != 0) 61 { 62 if (L < 0.5f) 63 { 64 S = (float)(_Delta / (_Max + _Min)); 65 } 66 else 67 { 68 S = (float)(_Delta / (2.0f - _Max - _Min)); 69 } 70 } 71 72 HSL hsl = new HSL(); 73 hsl.h = Math.Round(color.GetHue(), 2); 74 hsl.s = Math.Round(S, 2) * 100; 75 hsl.l = Math.Round(L, 2) * 100; 76 77 return hsl; 78 } 79 80 //Find contrast color (white, black) 81 public static Color GetContrastColor(string hexString) 82 { 83 System.Drawing.Color bg = System.Drawing.ColorTranslator.FromHtml(hexString); 84 85 int nThreshold = 105; 86 int bgDelta = Convert.ToInt32((bg.R * 0.299) + (bg.G * 0.587) + 87 (bg.B * 0.114)); 88 89 Color foreColor = (255 - bgDelta < nThreshold) ? Color.Black : Color.White; 90 return foreColor; 91 } 92 93 public string GetColorVariation(string hexString) 94 { 95 var contrast = GetContrastColor(hexString); 96 HSL currentHslColor = HexToHsl(hexString); 97 HSL variantHslColor = currentHslColor; 98 99 if (contrast == Color.Black) 100 { 101 variantHslColor.l = 85; //The background is dark - Color should be light 102 } 103 else 104 { 105 variantHslColor.l = 40; //The background is light - Color should be less light 106 } 107 108 //Color is very light 109 if (currentHslColor.l > 85) 110 { 111 variantHslColor.l = 95; 112 } 113 114 string colorString = variantHslColor.h + ", " + variantHslColor.s + "%, " + variantHslColor.l + "%"; 115 return colorString; 116 } 117 118 private class ThemeDatabaseUsage 119 { 120 public string TableName { get; set; } 121 public string ColumnName { get; set; } 122 } 123 124 private class ThemeUsage 125 { 126 public string Id { get; set; } 127 public List<int> WebsiteUsages { get; set; } = new List<int>(); 128 public List<int> PageUsages { get; set; } = new List<int>(); 129 public List<int> PagePropertyUsages { get; set; } = new List<int>(); 130 public List<int> GridRowUsages { get; set; } = new List<int>(); 131 public List<int> ParagraphUsages { get; set; } = new List<int>(); 132 public int AllUsages { get; set; } = 0; 133 } 134 135 private List<ThemeDatabaseUsage> GetThemeColumnsFromSchema() 136 { 137 string cacheKey = "ThemesFromDatabase"; 138 if (Dynamicweb.Context.Current.Items.Contains(cacheKey)) 139 { 140 return (List<ThemeDatabaseUsage>)Dynamicweb.Context.Current.Items[cacheKey]; 141 } 142 var schema = Dynamicweb.Data.Database.CreateDataReader("SELECT table_name, column_name FROM information_schema.columns WHERE column_name LIKE '%Theme%'"); 143 144 var rawData = new List<ThemeDatabaseUsage>(); 145 while (schema.Read()) { 146 rawData.Add(new ThemeDatabaseUsage {TableName = schema["table_name"].ToString(), ColumnName = schema["column_name"].ToString() }); 147 } 148 Dynamicweb.Context.Current.Items[cacheKey] = rawData; 149 return rawData; 150 } 151 152 private List<ThemeUsage> GetAllThemeUsages() 153 { 154 string cacheKey = "ThemeUsages"; 155 if (Dynamicweb.Context.Current.Items.Contains(cacheKey)) 156 { 157 return (List<ThemeUsage>)Dynamicweb.Context.Current.Items[cacheKey]; 158 } 159 160 var rawData = GetThemeColumnsFromSchema(); 161 var themeUsages = new List<ThemeUsage>(); 162 163 var sqlQuery = ""; 164 foreach (var row in rawData) 165 { 166 if (!string.IsNullOrEmpty(sqlQuery)) { sqlQuery += " UNION ALL "; } 167 sqlQuery += $"SELECT '{row.TableName}' AS TableName, '{row.ColumnName}' AS ColumnName, {row.ColumnName} AS ColumnValue, Id, AreaId, Page.PageId, PageProperties.PageId as 'PagePropertiesId', GridRowId, ParagraphId" + 168 $" FROM [{row.TableName}]" + 169 $" LEFT JOIN Area ON AreaItemType = '{row.TableName.Replace("ItemType_","")}' AND AreaItemId = Id" + 170 $" LEFT JOIN Page ON PageItemType = '{row.TableName.Replace("ItemType_","")}' AND PageItemId = Id" + 171 $" LEFT JOIN Page as PageProperties ON AreaItemTypePageProperty = '{row.TableName.Replace("ItemType_","")}' AND PageProperties.PagePropertyItemId = Id" + 172 $" LEFT JOIN GridRow ON GridRowItemType = '{row.TableName.Replace("ItemType_","")}' AND GridRowItemId = Id" + 173 $" LEFT JOIN Paragraph ON ParagraphItemType = '{row.TableName.Replace("ItemType_","")}' AND ParagraphItemId = Id" + 174 $" WHERE {row.ColumnName} != '' AND {row.ColumnName} IS NOT NULL" + 175 $" AND (AreaId IS NULL OR AreaId = {Pageview.AreaID})" + 176 $" AND (Page.PageId IS NULL OR Page.PageAreaId = {Pageview.AreaID})" + 177 $" AND (PageProperties.PageId IS NULL OR PageProperties.PageAreaId = {Pageview.AreaID})" + 178 $" AND (GridRowId IS NULL OR GridRowPageId IN (SELECT value From string_split(@pageIds, ',')))" + 179 $" AND (ParagraphId IS NULL OR ParagraphPageId IN (SELECT value From string_split(@pageIds, ',')))"; 180 181 var maxMsSqlServerCharLimit = 60000; 182 if (sqlQuery.Length > maxMsSqlServerCharLimit) 183 { 184 UpdateThemeUsages(sqlQuery, themeUsages); 185 sqlQuery = ""; 186 } 187 } 188 189 if (!string.IsNullOrEmpty(sqlQuery)) 190 { 191 UpdateThemeUsages(sqlQuery, themeUsages); 192 } 193 UpdateAllUsages(themeUsages); 194 195 Dynamicweb.Context.Current.Items[cacheKey] = themeUsages; 196 return themeUsages; 197 } 198 199 private void UpdateThemeUsages(string sqlQuery, List<ThemeUsage> themeUsages) 200 { 201 sqlQuery = $"DECLARE @pageIds NVARCHAR(max) = (SELECT STRING_AGG(PageId,',') FROM Page WHERE PageAreaId = {Pageview.AreaID}) " + sqlQuery; 202 var rawData = Dynamicweb.Data.Database.CreateDataReader(sqlQuery); 203 while (rawData.Read()) 204 { 205 var themeId = rawData["ColumnValue"].ToString(); 206 var themeUsageExists = themeUsages.FirstOrDefault(t => t.Id == themeId) != null; 207 if (!themeUsageExists) 208 { 209 themeUsages.Add(new ThemeUsage { Id = themeId }); 210 } 211 212 var themeUsage = themeUsages.FirstOrDefault(t => t.Id == themeId); 213 if (themeUsage == null) continue; 214 215 if (Converter.ToInt32(rawData["AreaId"].ToString()) > 0) { themeUsage.WebsiteUsages.Add(Converter.ToInt32(rawData["AreaId"].ToString())); } 216 if (Converter.ToInt32(rawData["PageId"].ToString()) > 0) { themeUsage.PageUsages.Add(Converter.ToInt32(rawData["PageId"].ToString())); } 217 if (Converter.ToInt32(rawData["PagePropertiesId"].ToString()) > 0) { themeUsage.PagePropertyUsages.Add(Converter.ToInt32(rawData["PagePropertiesId"].ToString())); } 218 if (Converter.ToInt32(rawData["GridRowId"].ToString()) > 0) { themeUsage.GridRowUsages.Add(Converter.ToInt32(rawData["GridRowId"].ToString())); } 219 if (Converter.ToInt32(rawData["ParagraphId"].ToString()) > 0) { themeUsage.ParagraphUsages.Add(Converter.ToInt32(rawData["ParagraphId"].ToString())); } 220 } 221 } 222 223 private void UpdateAllUsages(List<ThemeUsage> themeUsages) 224 { 225 foreach (var themeUsage in themeUsages) 226 { 227 int websiteUsages = themeUsage?.WebsiteUsages.Count ?? 0; 228 int pageUsages = themeUsage?.PageUsages.Count ?? 0; 229 int pagePropertyUsages = themeUsage?.PagePropertyUsages.Count ?? 0; 230 int gridRowUsages = themeUsage?.GridRowUsages.Count ?? 0; 231 int paragraphUsages = themeUsage?.ParagraphUsages.Count ?? 0; 232 themeUsage.AllUsages = websiteUsages + pageUsages + pagePropertyUsages + gridRowUsages + paragraphUsages; 233 } 234 } 235 236 private ThemeUsage GetThemeUsageById(string themeId) 237 { 238 var themeUsages = GetAllThemeUsages(); 239 return themeUsages.FirstOrDefault(t => t.Id == themeId); 240 } 241 242 } 243 244 @{ 245 string themeName = !string.IsNullOrWhiteSpace(Model.Item.GetString("Name")) ? Model.Item.GetString("Name") : "Default"; 246 string themeClassName = !string.IsNullOrWhiteSpace(Model.Item.GetString("CSSClassName")) ? Model.Item.GetString("CSSClassName").Replace(" ", "").Trim().ToLower() : ""; 247 248 //Theme colors 249 string foregroundColor = Model.Item.GetString("ForegroundColor", "currentColor"); 250 string backgroundColor = Model.Item.GetString("BackgroundColor", "transparent"); 251 string accentColor = Model.Item.GetString("accentColor", "currentColor"); 252 string borderColor = Model.Item.GetString("BorderColor", "transparent"); 253 254 //Primary button 255 string buttonPrimaryForegroundColor = Model.Item.GetString("ButtonPrimaryForegroundColor", "currentColor"); 256 string buttonPrimaryBackgroundColor = Model.Item.GetString("ButtonPrimaryBackgroundColor", "transparent"); 257 string buttonPrimaryBorderColor = Model.Item.GetString("ButtonPrimaryBorderColor", "transparent"); 258 259 string buttonPrimaryHoverBackgroundColorAuto = "transparent"; 260 if (buttonPrimaryBackgroundColor != "transparent") 261 { 262 buttonPrimaryHoverBackgroundColorAuto = "hsl(" + GetColorVariation(buttonPrimaryBackgroundColor) + ")"; 263 } 264 string buttonPrimaryHoverForegroundColor = Model.Item.GetString("ButtonPrimaryHoverForegroundColor", buttonPrimaryForegroundColor); 265 string buttonPrimaryHoverBackgroundColor = Model.Item.GetString("ButtonPrimaryHoverBackgroundColor", buttonPrimaryHoverBackgroundColorAuto); 266 string buttonPrimaryHoverBorderColor = Model.Item.GetString("ButtonPrimaryHoverBorderColor", buttonPrimaryBorderColor); 267 268 //Secondary buton 269 string buttonSecondaryForegroundColor = Model.Item.GetString("ButtonSecondaryForegroundColor", "currentColor"); 270 string buttonSecondaryBackgroundColor = Model.Item.GetString("ButtonSecondaryBackgroundColor", "transparent"); 271 string buttonSecondaryBorderColor = Model.Item.GetString("ButtonSecondaryBorderColor", "transparent"); 272 273 string buttonSecondaryHoverBackgroundColorAuto = "transparent"; 274 if (buttonSecondaryBackgroundColor != "transparent") 275 { 276 buttonSecondaryHoverBackgroundColorAuto = "hsl(" + GetColorVariation(buttonSecondaryBackgroundColor) + ")"; 277 } 278 string buttonSecondaryHoverForegroundColor = Model.Item.GetString("ButtonSecondaryHoverForegroundColor", buttonSecondaryForegroundColor); 279 string buttonSecondaryHoverBackgroundColor = Model.Item.GetString("ButtonSecondaryHoverBackgroundColor", buttonSecondaryHoverBackgroundColorAuto); 280 string buttonSecondaryHoverBorderColor = Model.Item.GetString("ButtonSecondaryHoverBorderColor", buttonSecondaryBorderColor); 281 282 //Link buton 283 string buttonLinkColor = Model.Item.GetString("ButtonLinkColor", "currentColor"); 284 string buttonLinkHoverColorAuto = "currentColor"; 285 if (buttonLinkColor != "currentColor") 286 { 287 buttonLinkHoverColorAuto = "hsl(" + GetColorVariation(buttonLinkColor) + ")"; 288 } 289 string buttonLinkHoverColor = Model.Item.GetString("ButtonLinkHoverColor", buttonLinkHoverColorAuto); 290 291 string accessibilityOutlineColor = Model.Item.GetString("OutlineColor") != null ? Model.Item.GetString("OutlineColor") : ""; 292 293 if (!string.IsNullOrEmpty(themeClassName)) 294 { 295 var sb = new System.Text.StringBuilder(); 296 297 sb.AppendLine("." + themeClassName + "{"); 298 if (!string.IsNullOrEmpty(foregroundColor)) 299 { 300 sb.AppendLine($"--swift-foreground-color: {foregroundColor};"); 301 sb.AppendLine($"--swift-foreground-color-rgb: {HexToRGB(foregroundColor)};"); 302 } 303 if (!string.IsNullOrEmpty(backgroundColor)) 304 { 305 sb.AppendLine($"--swift-background-color: {backgroundColor};"); 306 sb.AppendLine($"--swift-background-color-rgb: {HexToRGB(backgroundColor)};"); 307 } 308 if (!string.IsNullOrEmpty(accentColor)) 309 { 310 sb.AppendLine($"--swift-accent-color: {accentColor};"); 311 sb.AppendLine($"--swift-accent-color-rgb: {HexToRGB(accentColor)};"); 312 } 313 if (!string.IsNullOrEmpty(borderColor)) 314 { 315 sb.AppendLine($"--swift-border-color: {borderColor};"); 316 sb.AppendLine($"--swift-border-color-rgb: {HexToRGB(borderColor)};"); 317 } 318 319 if (!string.IsNullOrEmpty(buttonPrimaryBackgroundColor)) 320 { 321 sb.AppendLine($"--swift-button-primary-background-color: {buttonPrimaryBackgroundColor};"); 322 sb.AppendLine($"--swift-button-primary-background-color-rgb: {HexToRGB(buttonPrimaryBackgroundColor)};"); 323 } 324 if (!string.IsNullOrEmpty(buttonPrimaryForegroundColor)) 325 { 326 sb.AppendLine($"--swift-button-primary-foreground-color: {buttonPrimaryForegroundColor};"); 327 sb.AppendLine($"--swift-button-primary-foreground-color-rgb: {HexToRGB(buttonPrimaryForegroundColor)};"); 328 } 329 if (!string.IsNullOrEmpty(buttonPrimaryBorderColor)) 330 { 331 sb.AppendLine($"--swift-button-primary-border-color: {buttonPrimaryBorderColor};"); 332 sb.AppendLine($"--swift-button-primary-border-color-rgb: {HexToRGB(buttonPrimaryBorderColor)};"); 333 } 334 335 if (!string.IsNullOrEmpty(buttonPrimaryHoverBackgroundColor)) 336 { 337 sb.AppendLine($"--swift-button-primary-hover-background-color: {buttonPrimaryHoverBackgroundColor};"); 338 sb.AppendLine($"--swift-button-primary-hover-background-color-rgb: {HexToRGB(buttonPrimaryHoverBackgroundColor)};"); 339 } 340 if (!string.IsNullOrEmpty(buttonPrimaryHoverForegroundColor)) 341 { 342 sb.AppendLine($"--swift-button-primary-hover-foreground-color: {buttonPrimaryHoverForegroundColor};"); 343 sb.AppendLine($"--swift-button-primary-hover-foreground-color-rgb: {HexToRGB(buttonPrimaryHoverForegroundColor)};"); 344 } 345 if (!string.IsNullOrEmpty(buttonPrimaryHoverBorderColor)) 346 { 347 sb.AppendLine($"--swift-button-primary-hover-border-color: {buttonPrimaryHoverBorderColor};"); 348 sb.AppendLine($"--swift-button-primary-hover-border-color-rgb: {HexToRGB(buttonPrimaryHoverBorderColor)};"); 349 } 350 351 if (!string.IsNullOrEmpty(buttonSecondaryBackgroundColor)) 352 { 353 sb.AppendLine($"--swift-button-secondary-background-color: {buttonSecondaryBackgroundColor};"); 354 sb.AppendLine($"--swift-button-secondary-background-color-rgb: {HexToRGB(buttonSecondaryBackgroundColor)};"); 355 } 356 if (!string.IsNullOrEmpty(buttonSecondaryForegroundColor)) 357 { 358 sb.AppendLine($"--swift-button-secondary-foreground-color: {buttonSecondaryForegroundColor};"); 359 sb.AppendLine($"--swift-button-secondary-foreground-color-rgb: {HexToRGB(buttonSecondaryForegroundColor)};"); 360 } 361 if (!string.IsNullOrEmpty(buttonSecondaryBorderColor)) 362 { 363 sb.AppendLine($"--swift-button-secondary-border-color: {buttonSecondaryBorderColor};"); 364 sb.AppendLine($"--swift-button-secondary-border-color-rgb: {HexToRGB(buttonSecondaryBorderColor)};"); 365 } 366 if (!string.IsNullOrEmpty(buttonSecondaryHoverBackgroundColor)) 367 { 368 sb.AppendLine($"--swift-button-secondary-hover-background-color: {buttonSecondaryHoverBackgroundColor};"); 369 sb.AppendLine($"--swift-button-secondary-hover-background-color-rgb: {HexToRGB(buttonSecondaryHoverBackgroundColor)};"); 370 } 371 if (!string.IsNullOrEmpty(buttonSecondaryHoverForegroundColor)) 372 { 373 sb.AppendLine($"--swift-button-secondary-hover-foreground-color: {buttonSecondaryHoverForegroundColor};"); 374 sb.AppendLine($"--swift-button-secondary-hover-foreground-color-rgb: {HexToRGB(buttonSecondaryHoverForegroundColor)};"); 375 } 376 if (!string.IsNullOrEmpty(buttonSecondaryHoverBorderColor)) 377 { 378 sb.AppendLine($"--swift-button-secondary-hover-border-color: {buttonSecondaryHoverBorderColor};"); 379 sb.AppendLine($"--swift-button-secondary-hover-border-color-rgb: {HexToRGB(buttonSecondaryHoverBorderColor)};"); 380 } 381 if (!string.IsNullOrEmpty(buttonLinkColor)) 382 { 383 sb.AppendLine($"--swift-button-link-color: {buttonLinkColor};"); 384 sb.AppendLine($"--swift-button-link-color-rgb: {HexToRGB(buttonLinkColor)};"); 385 } 386 if (!string.IsNullOrEmpty(buttonLinkHoverColor)) 387 { 388 sb.AppendLine($"--swift-button-link-hover-color: {buttonLinkHoverColor};"); 389 sb.AppendLine($"--swift-button-link-hover-color-rgb: {HexToRGB(buttonLinkHoverColor)};"); 390 } 391 if (!string.IsNullOrEmpty(accessibilityOutlineColor)) 392 { 393 sb.AppendLine($"--swift-a11y-outline-color: {accessibilityOutlineColor};"); 394 sb.AppendLine($"--swift-a11y-outline-color-rgb: {HexToRGB(accessibilityOutlineColor)};"); 395 } 396 sb.AppendLine("}"); 397 398 Dynamicweb.Core.Helpers.TextFileHelper.WriteTextFile(sb.ToString() + Environment.NewLine, Dynamicweb.Context.Current.Server.MapPath($"/Files/Templates/Designs/Swift/_parsed/Swift_css/Swift_theme_styles_{Dynamicweb.Content.Services.Pages.GetPage(Model.PageID).AreaId}.tmp"), true); 399 } 400 } 401 402 @if (themeClassName != "") 403 { 404 string iconPath = "/Files/Templates/Designs/Swift/Assets/icons/"; 405 406 <div class="g-col-12 g-col-lg-4"> 407 <div class="swift-checkered p-3"> 408 <div class="theme-option theme @themeClassName p-lg-3"> 409 <div class="mb-2 pb-1 border-bottom d-flex align-items-center"> 410 <span class="icon-3 me-2"> 411 @ReadFile(iconPath + "sun.svg") 412 </span> 413 <h4 class="m-0 p-0">@themeName</h4> 414 </div> 415 <div class="d-flex flex-column gap-1 mb-2"> 416 <p class="mb-0">This is the body text of the theme.</p> 417 <p class="mb-0" style="color: var(--swift-accent-color)">This is the accent color of the theme.</p> 418 </div> 419 <div> 420 <button class="btn btn-primary me-1">Primary</button> 421 <button class="btn btn-secondary">Secondary</button> 422 <button class="btn btn-link">Link</button> 423 </div> 424 </div> 425 </div> 426 </div> 427 <div class="g-col-12 g-col-lg-8 mb-4 mb-lg-0"> 428 <div class="grid fs-7"> 429 <div class="g-col-12 g-col-lg-3"> 430 <table class="table table-borderless table-sm w-100"> 431 <thead> 432 <tr> 433 <th colspan="2" class="fw-bold">@Translate("Base")</th> 434 </tr> 435 </thead> 436 <tr> 437 <td>@Translate("Foreground")</td> 438 <td>@GetColorSquare(foregroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@foregroundColor');">@foregroundColor</a></td> 439 </tr> 440 <tr> 441 <td>@Translate("Background")</td> 442 <td>@GetColorSquare(backgroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@backgroundColor');">@backgroundColor</a></td> 443 </tr> 444 <tr> 445 <td>@Translate("Accent")</td> 446 <td>@GetColorSquare(accentColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@accentColor');">@accentColor</a></td> 447 </tr> 448 <tr> 449 <td>@Translate("Border")</td> 450 <td>@GetColorSquare(borderColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@borderColor');">@borderColor</a></td> 451 </tr> 452 </table> 453 </div> 454 <div class="g-col-12 g-col-lg-3"> 455 <table class="table table-borderless table-sm w-100"> 456 <thead> 457 <tr> 458 <th colspan="2" class="fw-bold">@Translate("Primary button")</th> 459 </tr> 460 </thead> 461 <tr> 462 <td>@Translate("Foreground")</td> 463 <td>@GetColorSquare(buttonPrimaryForegroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonPrimaryForegroundColor');">@buttonPrimaryForegroundColor</a></td> 464 </tr> 465 <tr> 466 <td>@Translate("Background")</td> 467 <td>@GetColorSquare(buttonPrimaryBackgroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonPrimaryBackgroundColor');">@buttonPrimaryBackgroundColor</a></td> 468 </tr> 469 @if (!string.IsNullOrEmpty(buttonPrimaryBorderColor)) 470 { 471 <tr> 472 <td>@Translate("Border")</td> 473 <td>@GetColorSquare(buttonPrimaryBorderColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonPrimaryBorderColor');">@buttonPrimaryBorderColor</a></td> 474 </tr> 475 } 476 <thead> 477 <tr> 478 <th colspan="2" class="fw-bold">@Translate("Primary button hover")</th> 479 </tr> 480 </thead> 481 @if (!string.IsNullOrEmpty(buttonPrimaryHoverForegroundColor)) 482 { 483 <tr> 484 <td>@Translate("Foreground")</td> 485 <td>@GetColorSquare(buttonPrimaryHoverForegroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonPrimaryHoverForegroundColor');">@buttonPrimaryHoverForegroundColor</a></td> 486 </tr> 487 } 488 @if (!string.IsNullOrEmpty(buttonPrimaryHoverBackgroundColor)) 489 { 490 <tr> 491 <td>@Translate("Background")</td> 492 <td>@GetColorSquare(buttonPrimaryHoverBackgroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonPrimaryHoverBackgroundColor');">@buttonPrimaryHoverBackgroundColor</a></td> 493 </tr> 494 } 495 @if (!string.IsNullOrEmpty(buttonPrimaryHoverBorderColor)) 496 { 497 <tr> 498 <td>@Translate("Border")</td> 499 <td>@GetColorSquare(buttonPrimaryHoverBorderColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonPrimaryHoverBorderColor');">@buttonPrimaryHoverBorderColor</a></td> 500 </tr> 501 } 502 </table> 503 </div> 504 <div class="g-col-12 g-col-lg-3"> 505 <table class="table table-borderless table-sm w-100"> 506 <thead> 507 <tr> 508 <th colspan="2" class="fw-bold">@Translate("Secondary button")</th> 509 </tr> 510 </thead> 511 <tr> 512 <td>@Translate("Foreground")</td> 513 <td>@GetColorSquare(buttonSecondaryForegroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonSecondaryForegroundColor');">@buttonSecondaryForegroundColor</a></td> 514 </tr> 515 <tr> 516 <td>@Translate("Background")</td> 517 <td>@GetColorSquare(buttonSecondaryBackgroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonSecondaryBackgroundColor');">@buttonSecondaryBackgroundColor</a></td> 518 </tr> 519 @if (!string.IsNullOrEmpty(buttonSecondaryBorderColor)) 520 { 521 <tr> 522 <td>@Translate("Border")</td> 523 <td>@GetColorSquare(buttonSecondaryBorderColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonSecondaryBorderColor');">@buttonSecondaryBorderColor</a></td> 524 </tr> 525 } 526 <thead> 527 <tr> 528 <th colspan="2" class="fw-bold">@Translate("Secondary button hover")</th> 529 </tr> 530 </thead> 531 @if (!string.IsNullOrEmpty(buttonSecondaryHoverForegroundColor)) 532 { 533 <tr> 534 <td>@Translate("Foreground")</td> 535 <td>@GetColorSquare(buttonSecondaryHoverForegroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonSecondaryHoverForegroundColor');">@buttonSecondaryHoverForegroundColor</a></td> 536 </tr> 537 } 538 @if (!string.IsNullOrEmpty(buttonSecondaryHoverBackgroundColor)) 539 { 540 <tr> 541 <td>@Translate("Background")</td> 542 <td>@GetColorSquare(buttonSecondaryHoverBackgroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonSecondaryHoverBackgroundColor');">@buttonSecondaryHoverBackgroundColor</a></td> 543 </tr> 544 } 545 @if (!string.IsNullOrEmpty(buttonSecondaryHoverBorderColor)) 546 { 547 <tr> 548 <td>@Translate("Border")</td> 549 <td>@GetColorSquare(buttonSecondaryHoverBorderColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonSecondaryHoverBorderColor');">@buttonSecondaryHoverBorderColor</a></td> 550 </tr> 551 } 552 @if (!string.IsNullOrEmpty(accessibilityOutlineColor)) 553 { 554 <tr> 555 <td>@Translate("Focus outline")</td> 556 <td>@GetColorSquare(accessibilityOutlineColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@accessibilityOutlineColor');">@accessibilityOutlineColor</a></td> 557 </tr> 558 } 559 </table> 560 </div> 561 <div class="g-col-12 g-col-lg-3"> 562 <table class="table table-borderless table-sm w-100"> 563 <thead> 564 <tr> 565 <th colspan="2" class="fw-bold">@Translate("Link button")</th> 566 </tr> 567 </thead> 568 <tr> 569 <td>@Translate("Link color")</td> 570 <td>@GetColorSquare(buttonLinkColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonLinkColor');">@buttonLinkColor</a></td> 571 </tr> 572 <thead> 573 <tr> 574 <th colspan="2" class="fw-bold">@Translate("Link button hover")</th> 575 </tr> 576 </thead> 577 @if (!string.IsNullOrEmpty(buttonLinkHoverColor)) 578 { 579 <tr> 580 <td>@Translate("Link hover color")</td> 581 <td>@GetColorSquare(buttonLinkHoverColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonLinkHoverColor');">@buttonLinkHoverColor</a></td> 582 </tr> 583 } 584 585 @if (!string.IsNullOrEmpty(accessibilityOutlineColor)) 586 { 587 <tr> 588 <td>@Translate("Focus outline")</td> 589 <td>@GetColorSquare(accessibilityOutlineColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@accessibilityOutlineColor');">@accessibilityOutlineColor</a></td> 590 </tr> 591 } 592 </table> 593 </div> 594 <div class="g-col-12 g-col-lg-3"> 595 <table class="table table-borderless table-sm w-100"> 596 <tr> 597 <td class="fw-bold">@Translate("Implementation")</td> 598 </tr> 599 <tr> 600 <td> 601 @{ 602 string implementation = $"<div class=\"theme {themeClassName}\"></div>"; 603 } 604 <div class="text-muted"> 605 <code class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@themeClassName');"> 606 @Dynamicweb.Core.Encoders.HtmlEncoder.HtmlEncode(implementation) 607 </code> 608 </div> 609 </td> 610 </tr> 611 </table> 612 </div> 613 @{ 614 bool hasUsageData = Converter.ToBoolean(Dynamicweb.Context.Current.Request["auditUsages"]); 615 if (hasUsageData) 616 { 617 var themeUsage = GetThemeUsageById(themeClassName); 618 int allUsages = themeUsage?.AllUsages ?? 0; 619 string buttonAttributes = allUsages > 0 ? $"data-bs-toggle=\"modal\" data-bs-target=\"#themeUsage_{Model.ID}\"" : string.Empty; 620 string badgeStyle = allUsages > 0 ? "bg-success" : "bg-danger"; 621 622 <div class="g-col-12 g-col-lg-9 position-relative"> 623 <button type="button" class="btn btn-primary btn-sm position-absolute end-0" @buttonAttributes> 624 Usages 625 <span class="position-absolute top-0 start-100 translate-middle badge rounded-pill text-white @badgeStyle">@allUsages</span> 626 </button> 627 628 @if (allUsages > 0) 629 { 630 int websiteUsages = themeUsage?.WebsiteUsages.Count ?? 0; 631 int pageUsages = themeUsage?.PageUsages.Count ?? 0; 632 int pagePropertyUsages = themeUsage?.PagePropertyUsages.Count ?? 0; 633 int gridRowUsages = themeUsage?.GridRowUsages.Count ?? 0; 634 int paragraphUsages = themeUsage?.ParagraphUsages.Count ?? 0; 635 636 <!-- Modal --> 637 <div class="modal fade" id="themeUsage_@(Model.ID)" tabindex="-1" aria-labelledby="usagesModelLabel" aria-hidden="true"> 638 <div class="modal-dialog modal-xl modal-dialog-centered modal-dialog-scrollable"> 639 <div class="modal-content"> 640 <div class="modal-header"> 641 <h5 class="modal-title" id="usagesModelLabel">@allUsages Usages of '@(themeName)' (@(themeClassName))</h5> 642 <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> 643 </div> 644 <div class="modal-body"> 645 <div class="accordion" id="accordionWrapper"> 646 @if(websiteUsages > 0) 647 { 648 <div class="accordion-item"> 649 <h2 class="accordion-header" id="headingWebsites"> 650 <button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#collapseWebsites" aria-expanded="true" aria-controls="collapseWebsites"> 651 <span class="pe-2">Websites</span><span class="badge rounded-pill bg-secondary text-light">@websiteUsages</span> 652 </button> 653 </h2> 654 <div id="collapseWebsites" class="accordion-collapse collapse show" aria-labelledby="headingWebsites" data-bs-parent="#accordionWrapper"> 655 <div class="accordion-body"> 656 <ul> 657 @foreach (var usage in themeUsage.WebsiteUsages) 658 { 659 var website = Dynamicweb.Content.Services.Areas.GetArea(usage); 660 <li><span class="fw-bold">@website.Name</span>@($" (ID: {usage})")</li> 661 } 662 </ul> 663 </div> 664 </div> 665 </div> 666 } 667 @if (pageUsages > 0) 668 { 669 var pages = Dynamicweb.Content.Services.Pages.GetPages(themeUsage.PageUsages.ToArray()); 670 671 <div class="accordion-item"> 672 <h2 class="accordion-header" id="headingPages"> 673 <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapsePages" aria-expanded="false" aria-controls="collapsePages"> 674 <span class="pe-2">Pages</span><span class="badge rounded-pill bg-secondary text-light">@pageUsages</span> 675 </button> 676 </h2> 677 <div id="collapsePages" class="accordion-collapse collapse" aria-labelledby="headingPages" data-bs-parent="#accordionWrapper"> 678 <div class="accordion-body"> 679 <ul> 680 @foreach (var usage in themeUsage.PageUsages) 681 { 682 <li><span class="fw-bold">@pages.FirstOrDefault(p => p.ID == usage).GetDisplayName()</span>@($" (ID: {usage})")</li> 683 } 684 </ul> 685 </div> 686 </div> 687 </div> 688 } 689 @if (pagePropertyUsages > 0) 690 { 691 var pages = Dynamicweb.Content.Services.Pages.GetPages(themeUsage.PageUsages.ToArray()); 692 693 <div class="accordion-item"> 694 <h2 class="accordion-header" id="headingPageProperties"> 695 <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapsePageProperties" aria-expanded="false" aria-controls="collapsePageProperties"> 696 <span class="pe-2">Page Properties</span><span class="badge rounded-pill bg-secondary text-light">@pagePropertyUsages</span> 697 </button> 698 </h2> 699 <div id="collapsePageProperties" class="accordion-collapse collapse" aria-labelledby="headingPageProperties" data-bs-parent="#accordionWrapper"> 700 <div class="accordion-body"> 701 <ul> 702 @foreach (var usage in themeUsage.PagePropertyUsages) 703 { 704 <li><span class="fw-bold">@pages.FirstOrDefault(p => p.ID == usage).GetDisplayName()</span>@($" (ID: {usage})")</li> 705 } 706 </ul> 707 </div> 708 </div> 709 </div> 710 } 711 @if (gridRowUsages > 0) 712 { 713 var rows = Dynamicweb.Content.Services.Grids.GetGridRows().Where(r => themeUsage.GridRowUsages.Contains(r.ID)).ToList(); 714 715 <div class="accordion-item"> 716 <h2 class="accordion-header" id="headingRows"> 717 <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseRows" aria-expanded="false" aria-controls="collapseRows"> 718 <span class="pe-2">Rows</span><span class="badge rounded-pill bg-secondary text-light">@gridRowUsages</span> 719 </button> 720 </h2> 721 <div id="collapseRows" class="accordion-collapse collapse" aria-labelledby="headingRows" data-bs-parent="#accordionWrapper"> 722 <div class="accordion-body"> 723 <ul> 724 @foreach (var usage in themeUsage.GridRowUsages) 725 { 726 var row = rows.FirstOrDefault(r => r.ID == usage); 727 var page = Dynamicweb.Content.Services.Pages.GetPage(row.PageId); 728 <li>Page: <span class="fw-bold">@(page.GetDisplayName())</span>@($"( ID: {page.ID}) - Row: ")<span class="fw-bold">@(row.DefinitionId)</span>@($" (ID: {usage})")</li> 729 } 730 </ul> 731 </div> 732 </div> 733 </div> 734 } 735 @if (paragraphUsages > 0) 736 { 737 var paragraphs = Dynamicweb.Content.Services.Paragraphs.GetParagraphs().Where(p => themeUsage.ParagraphUsages.Contains(p.ID)).ToList(); 738 739 <div class="accordion-item"> 740 <h2 class="accordion-header" id="headingParagraphs"> 741 <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseParagraphs" aria-expanded="false" aria-controls="collapseParagraphs"> 742 <span class="pe-2">Paragraphs</span><span class="badge rounded-pill bg-secondary text-light">@paragraphUsages</span> 743 </button> 744 </h2> 745 <div id="collapseParagraphs" class="accordion-collapse collapse" aria-labelledby="headingParagraphs" data-bs-parent="#accordionWrapper"> 746 <div class="accordion-body"> 747 <ul> 748 @foreach (var usage in themeUsage.ParagraphUsages) 749 { 750 var paragraph = paragraphs.FirstOrDefault(p => p.ID == usage); 751 var page = Dynamicweb.Content.Services.Pages.GetPage(paragraph.PageID); 752 <li>Page: <span class="fw-bold">@(page.GetDisplayName())</span>@($"( ID: {page.ID}) - Paragraph: ")<span class="fw-bold">@paragraph.Header</span>@($" (ID: {usage})")</li> 753 } 754 </ul> 755 </div> 756 </div> 757 </div> 758 } 759 </div> 760 </div> 761 </div> 762 </div> 763 </div> 764 } 765 </div> 766 } 767 } 768 </div> 769 </div> 770 } 771 <div class="g-col-12"> 772 <hr /> 773 </div> 774
Error executing template "Designs/Swift/Paragraph/Swift_Theme.cshtml" System.Data.SqlClient.SqlException (0x80131904): STRING_AGG aggregation result exceeded the limit of 8000 bytes. Use LOB types to avoid result truncation. at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction) at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose) at System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady) at System.Data.SqlClient.SqlDataReader.TryConsumeMetaData() at System.Data.SqlClient.SqlDataReader.get_MetaData() at System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString, Boolean isInternal, Boolean forDescribeParameterEncryption, Boolean shouldCacheForAlwaysEncrypted) at System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async, Int32 timeout, Task& task, Boolean asyncWrite, Boolean inRetry, SqlDataReader ds, Boolean describeParameterEncryptionRequest) at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, TaskCompletionSource`1 completion, Int32 timeout, Task& task, Boolean& usedCache, Boolean asyncWrite, Boolean inRetry) at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method) at System.Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior behavior, String method) at Dynamicweb.Data.Database.CreateDataReader(IDbCommand command, CommandBehavior behavior) at Dynamicweb.Data.Database.CreateDataReader(String sql, IDbConnection connection, IDbTransaction transaction, CommandBehavior behavior, Int32 commandTimeout, Dictionary`2 sqlParams) at Dynamicweb.Data.Database.CreateDataReader(String sql, IDbConnection connection, IDbTransaction transaction, Int32 commandTimeout, Dictionary`2 sqlParams) at Dynamicweb.Data.Database.CreateDataReader(String sql) at CompiledRazorTemplates.Dynamic.RazorEngine_8e3f1b11eb0041ceb2ca487c2be837e6.UpdateThemeUsages(String sqlQuery, List`1 themeUsages) in E:\Dynamicweb.net\Solutions\Dynamicweb\dw2022.cloud.dynamicweb-cms.com\Files\Templates\Designs\Swift\Paragraph\Swift_Theme.cshtml:line 202 at CompiledRazorTemplates.Dynamic.RazorEngine_8e3f1b11eb0041ceb2ca487c2be837e6.GetAllThemeUsages() in E:\Dynamicweb.net\Solutions\Dynamicweb\dw2022.cloud.dynamicweb-cms.com\Files\Templates\Designs\Swift\Paragraph\Swift_Theme.cshtml:line 184 at CompiledRazorTemplates.Dynamic.RazorEngine_8e3f1b11eb0041ceb2ca487c2be837e6.GetThemeUsageById(String themeId) in E:\Dynamicweb.net\Solutions\Dynamicweb\dw2022.cloud.dynamicweb-cms.com\Files\Templates\Designs\Swift\Paragraph\Swift_Theme.cshtml:line 238 at CompiledRazorTemplates.Dynamic.RazorEngine_8e3f1b11eb0041ceb2ca487c2be837e6.Execute() in E:\Dynamicweb.net\Solutions\Dynamicweb\dw2022.cloud.dynamicweb-cms.com\Files\Templates\Designs\Swift\Paragraph\Swift_Theme.cshtml:line 617 at RazorEngine.Templating.TemplateBase.RazorEngine.Templating.ITemplate.Run(ExecuteContext context, TextWriter reader) at RazorEngine.Templating.RazorEngineService.RunCompile(ITemplateKey key, TextWriter writer, Type modelType, Object model, DynamicViewBag viewBag) at RazorEngine.Templating.RazorEngineServiceExtensions.<>c__DisplayClass16_0.<RunCompile>b__0(TextWriter writer) at RazorEngine.Templating.RazorEngineServiceExtensions.WithWriter(Action`1 withWriter) at Dynamicweb.Rendering.RazorTemplateRenderingProvider.Render(Template template) at Dynamicweb.Rendering.TemplateRenderingService.Render(Template template) at Dynamicweb.Rendering.Template.RenderRazorTemplate() ClientConnectionId:b42d1cec-597c-4eed-bdc2-e0762a41101a Error Number:9829,State:1,Class:16
1 @inherits Dynamicweb.Rendering.ViewModelTemplate<Dynamicweb.Frontend.ParagraphViewModel> 2 @using System.Globalization 3 @using System.Drawing 4 @using Dynamicweb.Core 5 6 @functions{ 7 // Get Hex Color from color picker and translate to RGB color 8 public static string HexToRGB(string hexString) 9 { 10 if (hexString.Equals("none") || string.IsNullOrEmpty(hexString)) 11 return hexString; 12 13 //replace # occurences 14 if (hexString.IndexOf('#') != -1) 15 hexString = hexString.Replace("#", ""); 16 try 17 { 18 int r, g, b = 0; 19 r = int.Parse(hexString.Substring(0, 2), NumberStyles.AllowHexSpecifier); 20 g = int.Parse(hexString.Substring(2, 2), NumberStyles.AllowHexSpecifier); 21 b = int.Parse(hexString.Substring(4, 2), NumberStyles.AllowHexSpecifier); 22 23 string rgb = r + "," + g + "," + b; 24 return rgb; 25 } 26 catch (System.Exception) 27 { 28 return hexString; 29 } 30 } 31 32 public static string GetColorSquare(string hex) 33 { 34 return $"<div class=\"swift-checkered d-inline-block me-1\" style=\"height:1.25rem;width:1.25rem;\"><div style=\"background-color: {hex};border:.0625rem solid grey\" class=\"w-100 h-100\"></div></div>"; 35 } 36 37 public class HSL 38 { 39 public double h { get; set; } 40 public double s { get; set; } 41 public double l { get; set; } 42 } 43 44 //Convert HEX to HSL 45 public static HSL HexToHsl(string hexString) 46 { 47 System.Drawing.Color color = System.Drawing.ColorTranslator.FromHtml(hexString); 48 49 float _R = (color.R / 255f); 50 float _G = (color.G / 255f); 51 float _B = (color.B / 255f); 52 53 float _Min = Math.Min(Math.Min(_R, _G), _B); 54 float _Max = Math.Max(Math.Max(_R, _G), _B); 55 float _Delta = _Max - _Min; 56 57 float S = 0; 58 float L = (float)((_Max + _Min) / 2.0f); 59 60 if (_Delta != 0) 61 { 62 if (L < 0.5f) 63 { 64 S = (float)(_Delta / (_Max + _Min)); 65 } 66 else 67 { 68 S = (float)(_Delta / (2.0f - _Max - _Min)); 69 } 70 } 71 72 HSL hsl = new HSL(); 73 hsl.h = Math.Round(color.GetHue(), 2); 74 hsl.s = Math.Round(S, 2) * 100; 75 hsl.l = Math.Round(L, 2) * 100; 76 77 return hsl; 78 } 79 80 //Find contrast color (white, black) 81 public static Color GetContrastColor(string hexString) 82 { 83 System.Drawing.Color bg = System.Drawing.ColorTranslator.FromHtml(hexString); 84 85 int nThreshold = 105; 86 int bgDelta = Convert.ToInt32((bg.R * 0.299) + (bg.G * 0.587) + 87 (bg.B * 0.114)); 88 89 Color foreColor = (255 - bgDelta < nThreshold) ? Color.Black : Color.White; 90 return foreColor; 91 } 92 93 public string GetColorVariation(string hexString) 94 { 95 var contrast = GetContrastColor(hexString); 96 HSL currentHslColor = HexToHsl(hexString); 97 HSL variantHslColor = currentHslColor; 98 99 if (contrast == Color.Black) 100 { 101 variantHslColor.l = 85; //The background is dark - Color should be light 102 } 103 else 104 { 105 variantHslColor.l = 40; //The background is light - Color should be less light 106 } 107 108 //Color is very light 109 if (currentHslColor.l > 85) 110 { 111 variantHslColor.l = 95; 112 } 113 114 string colorString = variantHslColor.h + ", " + variantHslColor.s + "%, " + variantHslColor.l + "%"; 115 return colorString; 116 } 117 118 private class ThemeDatabaseUsage 119 { 120 public string TableName { get; set; } 121 public string ColumnName { get; set; } 122 } 123 124 private class ThemeUsage 125 { 126 public string Id { get; set; } 127 public List<int> WebsiteUsages { get; set; } = new List<int>(); 128 public List<int> PageUsages { get; set; } = new List<int>(); 129 public List<int> PagePropertyUsages { get; set; } = new List<int>(); 130 public List<int> GridRowUsages { get; set; } = new List<int>(); 131 public List<int> ParagraphUsages { get; set; } = new List<int>(); 132 public int AllUsages { get; set; } = 0; 133 } 134 135 private List<ThemeDatabaseUsage> GetThemeColumnsFromSchema() 136 { 137 string cacheKey = "ThemesFromDatabase"; 138 if (Dynamicweb.Context.Current.Items.Contains(cacheKey)) 139 { 140 return (List<ThemeDatabaseUsage>)Dynamicweb.Context.Current.Items[cacheKey]; 141 } 142 var schema = Dynamicweb.Data.Database.CreateDataReader("SELECT table_name, column_name FROM information_schema.columns WHERE column_name LIKE '%Theme%'"); 143 144 var rawData = new List<ThemeDatabaseUsage>(); 145 while (schema.Read()) { 146 rawData.Add(new ThemeDatabaseUsage {TableName = schema["table_name"].ToString(), ColumnName = schema["column_name"].ToString() }); 147 } 148 Dynamicweb.Context.Current.Items[cacheKey] = rawData; 149 return rawData; 150 } 151 152 private List<ThemeUsage> GetAllThemeUsages() 153 { 154 string cacheKey = "ThemeUsages"; 155 if (Dynamicweb.Context.Current.Items.Contains(cacheKey)) 156 { 157 return (List<ThemeUsage>)Dynamicweb.Context.Current.Items[cacheKey]; 158 } 159 160 var rawData = GetThemeColumnsFromSchema(); 161 var themeUsages = new List<ThemeUsage>(); 162 163 var sqlQuery = ""; 164 foreach (var row in rawData) 165 { 166 if (!string.IsNullOrEmpty(sqlQuery)) { sqlQuery += " UNION ALL "; } 167 sqlQuery += $"SELECT '{row.TableName}' AS TableName, '{row.ColumnName}' AS ColumnName, {row.ColumnName} AS ColumnValue, Id, AreaId, Page.PageId, PageProperties.PageId as 'PagePropertiesId', GridRowId, ParagraphId" + 168 $" FROM [{row.TableName}]" + 169 $" LEFT JOIN Area ON AreaItemType = '{row.TableName.Replace("ItemType_","")}' AND AreaItemId = Id" + 170 $" LEFT JOIN Page ON PageItemType = '{row.TableName.Replace("ItemType_","")}' AND PageItemId = Id" + 171 $" LEFT JOIN Page as PageProperties ON AreaItemTypePageProperty = '{row.TableName.Replace("ItemType_","")}' AND PageProperties.PagePropertyItemId = Id" + 172 $" LEFT JOIN GridRow ON GridRowItemType = '{row.TableName.Replace("ItemType_","")}' AND GridRowItemId = Id" + 173 $" LEFT JOIN Paragraph ON ParagraphItemType = '{row.TableName.Replace("ItemType_","")}' AND ParagraphItemId = Id" + 174 $" WHERE {row.ColumnName} != '' AND {row.ColumnName} IS NOT NULL" + 175 $" AND (AreaId IS NULL OR AreaId = {Pageview.AreaID})" + 176 $" AND (Page.PageId IS NULL OR Page.PageAreaId = {Pageview.AreaID})" + 177 $" AND (PageProperties.PageId IS NULL OR PageProperties.PageAreaId = {Pageview.AreaID})" + 178 $" AND (GridRowId IS NULL OR GridRowPageId IN (SELECT value From string_split(@pageIds, ',')))" + 179 $" AND (ParagraphId IS NULL OR ParagraphPageId IN (SELECT value From string_split(@pageIds, ',')))"; 180 181 var maxMsSqlServerCharLimit = 60000; 182 if (sqlQuery.Length > maxMsSqlServerCharLimit) 183 { 184 UpdateThemeUsages(sqlQuery, themeUsages); 185 sqlQuery = ""; 186 } 187 } 188 189 if (!string.IsNullOrEmpty(sqlQuery)) 190 { 191 UpdateThemeUsages(sqlQuery, themeUsages); 192 } 193 UpdateAllUsages(themeUsages); 194 195 Dynamicweb.Context.Current.Items[cacheKey] = themeUsages; 196 return themeUsages; 197 } 198 199 private void UpdateThemeUsages(string sqlQuery, List<ThemeUsage> themeUsages) 200 { 201 sqlQuery = $"DECLARE @pageIds NVARCHAR(max) = (SELECT STRING_AGG(PageId,',') FROM Page WHERE PageAreaId = {Pageview.AreaID}) " + sqlQuery; 202 var rawData = Dynamicweb.Data.Database.CreateDataReader(sqlQuery); 203 while (rawData.Read()) 204 { 205 var themeId = rawData["ColumnValue"].ToString(); 206 var themeUsageExists = themeUsages.FirstOrDefault(t => t.Id == themeId) != null; 207 if (!themeUsageExists) 208 { 209 themeUsages.Add(new ThemeUsage { Id = themeId }); 210 } 211 212 var themeUsage = themeUsages.FirstOrDefault(t => t.Id == themeId); 213 if (themeUsage == null) continue; 214 215 if (Converter.ToInt32(rawData["AreaId"].ToString()) > 0) { themeUsage.WebsiteUsages.Add(Converter.ToInt32(rawData["AreaId"].ToString())); } 216 if (Converter.ToInt32(rawData["PageId"].ToString()) > 0) { themeUsage.PageUsages.Add(Converter.ToInt32(rawData["PageId"].ToString())); } 217 if (Converter.ToInt32(rawData["PagePropertiesId"].ToString()) > 0) { themeUsage.PagePropertyUsages.Add(Converter.ToInt32(rawData["PagePropertiesId"].ToString())); } 218 if (Converter.ToInt32(rawData["GridRowId"].ToString()) > 0) { themeUsage.GridRowUsages.Add(Converter.ToInt32(rawData["GridRowId"].ToString())); } 219 if (Converter.ToInt32(rawData["ParagraphId"].ToString()) > 0) { themeUsage.ParagraphUsages.Add(Converter.ToInt32(rawData["ParagraphId"].ToString())); } 220 } 221 } 222 223 private void UpdateAllUsages(List<ThemeUsage> themeUsages) 224 { 225 foreach (var themeUsage in themeUsages) 226 { 227 int websiteUsages = themeUsage?.WebsiteUsages.Count ?? 0; 228 int pageUsages = themeUsage?.PageUsages.Count ?? 0; 229 int pagePropertyUsages = themeUsage?.PagePropertyUsages.Count ?? 0; 230 int gridRowUsages = themeUsage?.GridRowUsages.Count ?? 0; 231 int paragraphUsages = themeUsage?.ParagraphUsages.Count ?? 0; 232 themeUsage.AllUsages = websiteUsages + pageUsages + pagePropertyUsages + gridRowUsages + paragraphUsages; 233 } 234 } 235 236 private ThemeUsage GetThemeUsageById(string themeId) 237 { 238 var themeUsages = GetAllThemeUsages(); 239 return themeUsages.FirstOrDefault(t => t.Id == themeId); 240 } 241 242 } 243 244 @{ 245 string themeName = !string.IsNullOrWhiteSpace(Model.Item.GetString("Name")) ? Model.Item.GetString("Name") : "Default"; 246 string themeClassName = !string.IsNullOrWhiteSpace(Model.Item.GetString("CSSClassName")) ? Model.Item.GetString("CSSClassName").Replace(" ", "").Trim().ToLower() : ""; 247 248 //Theme colors 249 string foregroundColor = Model.Item.GetString("ForegroundColor", "currentColor"); 250 string backgroundColor = Model.Item.GetString("BackgroundColor", "transparent"); 251 string accentColor = Model.Item.GetString("accentColor", "currentColor"); 252 string borderColor = Model.Item.GetString("BorderColor", "transparent"); 253 254 //Primary button 255 string buttonPrimaryForegroundColor = Model.Item.GetString("ButtonPrimaryForegroundColor", "currentColor"); 256 string buttonPrimaryBackgroundColor = Model.Item.GetString("ButtonPrimaryBackgroundColor", "transparent"); 257 string buttonPrimaryBorderColor = Model.Item.GetString("ButtonPrimaryBorderColor", "transparent"); 258 259 string buttonPrimaryHoverBackgroundColorAuto = "transparent"; 260 if (buttonPrimaryBackgroundColor != "transparent") 261 { 262 buttonPrimaryHoverBackgroundColorAuto = "hsl(" + GetColorVariation(buttonPrimaryBackgroundColor) + ")"; 263 } 264 string buttonPrimaryHoverForegroundColor = Model.Item.GetString("ButtonPrimaryHoverForegroundColor", buttonPrimaryForegroundColor); 265 string buttonPrimaryHoverBackgroundColor = Model.Item.GetString("ButtonPrimaryHoverBackgroundColor", buttonPrimaryHoverBackgroundColorAuto); 266 string buttonPrimaryHoverBorderColor = Model.Item.GetString("ButtonPrimaryHoverBorderColor", buttonPrimaryBorderColor); 267 268 //Secondary buton 269 string buttonSecondaryForegroundColor = Model.Item.GetString("ButtonSecondaryForegroundColor", "currentColor"); 270 string buttonSecondaryBackgroundColor = Model.Item.GetString("ButtonSecondaryBackgroundColor", "transparent"); 271 string buttonSecondaryBorderColor = Model.Item.GetString("ButtonSecondaryBorderColor", "transparent"); 272 273 string buttonSecondaryHoverBackgroundColorAuto = "transparent"; 274 if (buttonSecondaryBackgroundColor != "transparent") 275 { 276 buttonSecondaryHoverBackgroundColorAuto = "hsl(" + GetColorVariation(buttonSecondaryBackgroundColor) + ")"; 277 } 278 string buttonSecondaryHoverForegroundColor = Model.Item.GetString("ButtonSecondaryHoverForegroundColor", buttonSecondaryForegroundColor); 279 string buttonSecondaryHoverBackgroundColor = Model.Item.GetString("ButtonSecondaryHoverBackgroundColor", buttonSecondaryHoverBackgroundColorAuto); 280 string buttonSecondaryHoverBorderColor = Model.Item.GetString("ButtonSecondaryHoverBorderColor", buttonSecondaryBorderColor); 281 282 //Link buton 283 string buttonLinkColor = Model.Item.GetString("ButtonLinkColor", "currentColor"); 284 string buttonLinkHoverColorAuto = "currentColor"; 285 if (buttonLinkColor != "currentColor") 286 { 287 buttonLinkHoverColorAuto = "hsl(" + GetColorVariation(buttonLinkColor) + ")"; 288 } 289 string buttonLinkHoverColor = Model.Item.GetString("ButtonLinkHoverColor", buttonLinkHoverColorAuto); 290 291 string accessibilityOutlineColor = Model.Item.GetString("OutlineColor") != null ? Model.Item.GetString("OutlineColor") : ""; 292 293 if (!string.IsNullOrEmpty(themeClassName)) 294 { 295 var sb = new System.Text.StringBuilder(); 296 297 sb.AppendLine("." + themeClassName + "{"); 298 if (!string.IsNullOrEmpty(foregroundColor)) 299 { 300 sb.AppendLine($"--swift-foreground-color: {foregroundColor};"); 301 sb.AppendLine($"--swift-foreground-color-rgb: {HexToRGB(foregroundColor)};"); 302 } 303 if (!string.IsNullOrEmpty(backgroundColor)) 304 { 305 sb.AppendLine($"--swift-background-color: {backgroundColor};"); 306 sb.AppendLine($"--swift-background-color-rgb: {HexToRGB(backgroundColor)};"); 307 } 308 if (!string.IsNullOrEmpty(accentColor)) 309 { 310 sb.AppendLine($"--swift-accent-color: {accentColor};"); 311 sb.AppendLine($"--swift-accent-color-rgb: {HexToRGB(accentColor)};"); 312 } 313 if (!string.IsNullOrEmpty(borderColor)) 314 { 315 sb.AppendLine($"--swift-border-color: {borderColor};"); 316 sb.AppendLine($"--swift-border-color-rgb: {HexToRGB(borderColor)};"); 317 } 318 319 if (!string.IsNullOrEmpty(buttonPrimaryBackgroundColor)) 320 { 321 sb.AppendLine($"--swift-button-primary-background-color: {buttonPrimaryBackgroundColor};"); 322 sb.AppendLine($"--swift-button-primary-background-color-rgb: {HexToRGB(buttonPrimaryBackgroundColor)};"); 323 } 324 if (!string.IsNullOrEmpty(buttonPrimaryForegroundColor)) 325 { 326 sb.AppendLine($"--swift-button-primary-foreground-color: {buttonPrimaryForegroundColor};"); 327 sb.AppendLine($"--swift-button-primary-foreground-color-rgb: {HexToRGB(buttonPrimaryForegroundColor)};"); 328 } 329 if (!string.IsNullOrEmpty(buttonPrimaryBorderColor)) 330 { 331 sb.AppendLine($"--swift-button-primary-border-color: {buttonPrimaryBorderColor};"); 332 sb.AppendLine($"--swift-button-primary-border-color-rgb: {HexToRGB(buttonPrimaryBorderColor)};"); 333 } 334 335 if (!string.IsNullOrEmpty(buttonPrimaryHoverBackgroundColor)) 336 { 337 sb.AppendLine($"--swift-button-primary-hover-background-color: {buttonPrimaryHoverBackgroundColor};"); 338 sb.AppendLine($"--swift-button-primary-hover-background-color-rgb: {HexToRGB(buttonPrimaryHoverBackgroundColor)};"); 339 } 340 if (!string.IsNullOrEmpty(buttonPrimaryHoverForegroundColor)) 341 { 342 sb.AppendLine($"--swift-button-primary-hover-foreground-color: {buttonPrimaryHoverForegroundColor};"); 343 sb.AppendLine($"--swift-button-primary-hover-foreground-color-rgb: {HexToRGB(buttonPrimaryHoverForegroundColor)};"); 344 } 345 if (!string.IsNullOrEmpty(buttonPrimaryHoverBorderColor)) 346 { 347 sb.AppendLine($"--swift-button-primary-hover-border-color: {buttonPrimaryHoverBorderColor};"); 348 sb.AppendLine($"--swift-button-primary-hover-border-color-rgb: {HexToRGB(buttonPrimaryHoverBorderColor)};"); 349 } 350 351 if (!string.IsNullOrEmpty(buttonSecondaryBackgroundColor)) 352 { 353 sb.AppendLine($"--swift-button-secondary-background-color: {buttonSecondaryBackgroundColor};"); 354 sb.AppendLine($"--swift-button-secondary-background-color-rgb: {HexToRGB(buttonSecondaryBackgroundColor)};"); 355 } 356 if (!string.IsNullOrEmpty(buttonSecondaryForegroundColor)) 357 { 358 sb.AppendLine($"--swift-button-secondary-foreground-color: {buttonSecondaryForegroundColor};"); 359 sb.AppendLine($"--swift-button-secondary-foreground-color-rgb: {HexToRGB(buttonSecondaryForegroundColor)};"); 360 } 361 if (!string.IsNullOrEmpty(buttonSecondaryBorderColor)) 362 { 363 sb.AppendLine($"--swift-button-secondary-border-color: {buttonSecondaryBorderColor};"); 364 sb.AppendLine($"--swift-button-secondary-border-color-rgb: {HexToRGB(buttonSecondaryBorderColor)};"); 365 } 366 if (!string.IsNullOrEmpty(buttonSecondaryHoverBackgroundColor)) 367 { 368 sb.AppendLine($"--swift-button-secondary-hover-background-color: {buttonSecondaryHoverBackgroundColor};"); 369 sb.AppendLine($"--swift-button-secondary-hover-background-color-rgb: {HexToRGB(buttonSecondaryHoverBackgroundColor)};"); 370 } 371 if (!string.IsNullOrEmpty(buttonSecondaryHoverForegroundColor)) 372 { 373 sb.AppendLine($"--swift-button-secondary-hover-foreground-color: {buttonSecondaryHoverForegroundColor};"); 374 sb.AppendLine($"--swift-button-secondary-hover-foreground-color-rgb: {HexToRGB(buttonSecondaryHoverForegroundColor)};"); 375 } 376 if (!string.IsNullOrEmpty(buttonSecondaryHoverBorderColor)) 377 { 378 sb.AppendLine($"--swift-button-secondary-hover-border-color: {buttonSecondaryHoverBorderColor};"); 379 sb.AppendLine($"--swift-button-secondary-hover-border-color-rgb: {HexToRGB(buttonSecondaryHoverBorderColor)};"); 380 } 381 if (!string.IsNullOrEmpty(buttonLinkColor)) 382 { 383 sb.AppendLine($"--swift-button-link-color: {buttonLinkColor};"); 384 sb.AppendLine($"--swift-button-link-color-rgb: {HexToRGB(buttonLinkColor)};"); 385 } 386 if (!string.IsNullOrEmpty(buttonLinkHoverColor)) 387 { 388 sb.AppendLine($"--swift-button-link-hover-color: {buttonLinkHoverColor};"); 389 sb.AppendLine($"--swift-button-link-hover-color-rgb: {HexToRGB(buttonLinkHoverColor)};"); 390 } 391 if (!string.IsNullOrEmpty(accessibilityOutlineColor)) 392 { 393 sb.AppendLine($"--swift-a11y-outline-color: {accessibilityOutlineColor};"); 394 sb.AppendLine($"--swift-a11y-outline-color-rgb: {HexToRGB(accessibilityOutlineColor)};"); 395 } 396 sb.AppendLine("}"); 397 398 Dynamicweb.Core.Helpers.TextFileHelper.WriteTextFile(sb.ToString() + Environment.NewLine, Dynamicweb.Context.Current.Server.MapPath($"/Files/Templates/Designs/Swift/_parsed/Swift_css/Swift_theme_styles_{Dynamicweb.Content.Services.Pages.GetPage(Model.PageID).AreaId}.tmp"), true); 399 } 400 } 401 402 @if (themeClassName != "") 403 { 404 string iconPath = "/Files/Templates/Designs/Swift/Assets/icons/"; 405 406 <div class="g-col-12 g-col-lg-4"> 407 <div class="swift-checkered p-3"> 408 <div class="theme-option theme @themeClassName p-lg-3"> 409 <div class="mb-2 pb-1 border-bottom d-flex align-items-center"> 410 <span class="icon-3 me-2"> 411 @ReadFile(iconPath + "sun.svg") 412 </span> 413 <h4 class="m-0 p-0">@themeName</h4> 414 </div> 415 <div class="d-flex flex-column gap-1 mb-2"> 416 <p class="mb-0">This is the body text of the theme.</p> 417 <p class="mb-0" style="color: var(--swift-accent-color)">This is the accent color of the theme.</p> 418 </div> 419 <div> 420 <button class="btn btn-primary me-1">Primary</button> 421 <button class="btn btn-secondary">Secondary</button> 422 <button class="btn btn-link">Link</button> 423 </div> 424 </div> 425 </div> 426 </div> 427 <div class="g-col-12 g-col-lg-8 mb-4 mb-lg-0"> 428 <div class="grid fs-7"> 429 <div class="g-col-12 g-col-lg-3"> 430 <table class="table table-borderless table-sm w-100"> 431 <thead> 432 <tr> 433 <th colspan="2" class="fw-bold">@Translate("Base")</th> 434 </tr> 435 </thead> 436 <tr> 437 <td>@Translate("Foreground")</td> 438 <td>@GetColorSquare(foregroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@foregroundColor');">@foregroundColor</a></td> 439 </tr> 440 <tr> 441 <td>@Translate("Background")</td> 442 <td>@GetColorSquare(backgroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@backgroundColor');">@backgroundColor</a></td> 443 </tr> 444 <tr> 445 <td>@Translate("Accent")</td> 446 <td>@GetColorSquare(accentColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@accentColor');">@accentColor</a></td> 447 </tr> 448 <tr> 449 <td>@Translate("Border")</td> 450 <td>@GetColorSquare(borderColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@borderColor');">@borderColor</a></td> 451 </tr> 452 </table> 453 </div> 454 <div class="g-col-12 g-col-lg-3"> 455 <table class="table table-borderless table-sm w-100"> 456 <thead> 457 <tr> 458 <th colspan="2" class="fw-bold">@Translate("Primary button")</th> 459 </tr> 460 </thead> 461 <tr> 462 <td>@Translate("Foreground")</td> 463 <td>@GetColorSquare(buttonPrimaryForegroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonPrimaryForegroundColor');">@buttonPrimaryForegroundColor</a></td> 464 </tr> 465 <tr> 466 <td>@Translate("Background")</td> 467 <td>@GetColorSquare(buttonPrimaryBackgroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonPrimaryBackgroundColor');">@buttonPrimaryBackgroundColor</a></td> 468 </tr> 469 @if (!string.IsNullOrEmpty(buttonPrimaryBorderColor)) 470 { 471 <tr> 472 <td>@Translate("Border")</td> 473 <td>@GetColorSquare(buttonPrimaryBorderColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonPrimaryBorderColor');">@buttonPrimaryBorderColor</a></td> 474 </tr> 475 } 476 <thead> 477 <tr> 478 <th colspan="2" class="fw-bold">@Translate("Primary button hover")</th> 479 </tr> 480 </thead> 481 @if (!string.IsNullOrEmpty(buttonPrimaryHoverForegroundColor)) 482 { 483 <tr> 484 <td>@Translate("Foreground")</td> 485 <td>@GetColorSquare(buttonPrimaryHoverForegroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonPrimaryHoverForegroundColor');">@buttonPrimaryHoverForegroundColor</a></td> 486 </tr> 487 } 488 @if (!string.IsNullOrEmpty(buttonPrimaryHoverBackgroundColor)) 489 { 490 <tr> 491 <td>@Translate("Background")</td> 492 <td>@GetColorSquare(buttonPrimaryHoverBackgroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonPrimaryHoverBackgroundColor');">@buttonPrimaryHoverBackgroundColor</a></td> 493 </tr> 494 } 495 @if (!string.IsNullOrEmpty(buttonPrimaryHoverBorderColor)) 496 { 497 <tr> 498 <td>@Translate("Border")</td> 499 <td>@GetColorSquare(buttonPrimaryHoverBorderColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonPrimaryHoverBorderColor');">@buttonPrimaryHoverBorderColor</a></td> 500 </tr> 501 } 502 </table> 503 </div> 504 <div class="g-col-12 g-col-lg-3"> 505 <table class="table table-borderless table-sm w-100"> 506 <thead> 507 <tr> 508 <th colspan="2" class="fw-bold">@Translate("Secondary button")</th> 509 </tr> 510 </thead> 511 <tr> 512 <td>@Translate("Foreground")</td> 513 <td>@GetColorSquare(buttonSecondaryForegroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonSecondaryForegroundColor');">@buttonSecondaryForegroundColor</a></td> 514 </tr> 515 <tr> 516 <td>@Translate("Background")</td> 517 <td>@GetColorSquare(buttonSecondaryBackgroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonSecondaryBackgroundColor');">@buttonSecondaryBackgroundColor</a></td> 518 </tr> 519 @if (!string.IsNullOrEmpty(buttonSecondaryBorderColor)) 520 { 521 <tr> 522 <td>@Translate("Border")</td> 523 <td>@GetColorSquare(buttonSecondaryBorderColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonSecondaryBorderColor');">@buttonSecondaryBorderColor</a></td> 524 </tr> 525 } 526 <thead> 527 <tr> 528 <th colspan="2" class="fw-bold">@Translate("Secondary button hover")</th> 529 </tr> 530 </thead> 531 @if (!string.IsNullOrEmpty(buttonSecondaryHoverForegroundColor)) 532 { 533 <tr> 534 <td>@Translate("Foreground")</td> 535 <td>@GetColorSquare(buttonSecondaryHoverForegroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonSecondaryHoverForegroundColor');">@buttonSecondaryHoverForegroundColor</a></td> 536 </tr> 537 } 538 @if (!string.IsNullOrEmpty(buttonSecondaryHoverBackgroundColor)) 539 { 540 <tr> 541 <td>@Translate("Background")</td> 542 <td>@GetColorSquare(buttonSecondaryHoverBackgroundColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonSecondaryHoverBackgroundColor');">@buttonSecondaryHoverBackgroundColor</a></td> 543 </tr> 544 } 545 @if (!string.IsNullOrEmpty(buttonSecondaryHoverBorderColor)) 546 { 547 <tr> 548 <td>@Translate("Border")</td> 549 <td>@GetColorSquare(buttonSecondaryHoverBorderColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonSecondaryHoverBorderColor');">@buttonSecondaryHoverBorderColor</a></td> 550 </tr> 551 } 552 @if (!string.IsNullOrEmpty(accessibilityOutlineColor)) 553 { 554 <tr> 555 <td>@Translate("Focus outline")</td> 556 <td>@GetColorSquare(accessibilityOutlineColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@accessibilityOutlineColor');">@accessibilityOutlineColor</a></td> 557 </tr> 558 } 559 </table> 560 </div> 561 <div class="g-col-12 g-col-lg-3"> 562 <table class="table table-borderless table-sm w-100"> 563 <thead> 564 <tr> 565 <th colspan="2" class="fw-bold">@Translate("Link button")</th> 566 </tr> 567 </thead> 568 <tr> 569 <td>@Translate("Link color")</td> 570 <td>@GetColorSquare(buttonLinkColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonLinkColor');">@buttonLinkColor</a></td> 571 </tr> 572 <thead> 573 <tr> 574 <th colspan="2" class="fw-bold">@Translate("Link button hover")</th> 575 </tr> 576 </thead> 577 @if (!string.IsNullOrEmpty(buttonLinkHoverColor)) 578 { 579 <tr> 580 <td>@Translate("Link hover color")</td> 581 <td>@GetColorSquare(buttonLinkHoverColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@buttonLinkHoverColor');">@buttonLinkHoverColor</a></td> 582 </tr> 583 } 584 585 @if (!string.IsNullOrEmpty(accessibilityOutlineColor)) 586 { 587 <tr> 588 <td>@Translate("Focus outline")</td> 589 <td>@GetColorSquare(accessibilityOutlineColor)<a class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@accessibilityOutlineColor');">@accessibilityOutlineColor</a></td> 590 </tr> 591 } 592 </table> 593 </div> 594 <div class="g-col-12 g-col-lg-3"> 595 <table class="table table-borderless table-sm w-100"> 596 <tr> 597 <td class="fw-bold">@Translate("Implementation")</td> 598 </tr> 599 <tr> 600 <td> 601 @{ 602 string implementation = $"<div class=\"theme {themeClassName}\"></div>"; 603 } 604 <div class="text-muted"> 605 <code class="align-top" role="button" title="@Translate("Click to copy")" onclick="copyTextToClipboard('@themeClassName');"> 606 @Dynamicweb.Core.Encoders.HtmlEncoder.HtmlEncode(implementation) 607 </code> 608 </div> 609 </td> 610 </tr> 611 </table> 612 </div> 613 @{ 614 bool hasUsageData = Converter.ToBoolean(Dynamicweb.Context.Current.Request["auditUsages"]); 615 if (hasUsageData) 616 { 617 var themeUsage = GetThemeUsageById(themeClassName); 618 int allUsages = themeUsage?.AllUsages ?? 0; 619 string buttonAttributes = allUsages > 0 ? $"data-bs-toggle=\"modal\" data-bs-target=\"#themeUsage_{Model.ID}\"" : string.Empty; 620 string badgeStyle = allUsages > 0 ? "bg-success" : "bg-danger"; 621 622 <div class="g-col-12 g-col-lg-9 position-relative"> 623 <button type="button" class="btn btn-primary btn-sm position-absolute end-0" @buttonAttributes> 624 Usages 625 <span class="position-absolute top-0 start-100 translate-middle badge rounded-pill text-white @badgeStyle">@allUsages</span> 626 </button> 627 628 @if (allUsages > 0) 629 { 630 int websiteUsages = themeUsage?.WebsiteUsages.Count ?? 0; 631 int pageUsages = themeUsage?.PageUsages.Count ?? 0; 632 int pagePropertyUsages = themeUsage?.PagePropertyUsages.Count ?? 0; 633 int gridRowUsages = themeUsage?.GridRowUsages.Count ?? 0; 634 int paragraphUsages = themeUsage?.ParagraphUsages.Count ?? 0; 635 636 <!-- Modal --> 637 <div class="modal fade" id="themeUsage_@(Model.ID)" tabindex="-1" aria-labelledby="usagesModelLabel" aria-hidden="true"> 638 <div class="modal-dialog modal-xl modal-dialog-centered modal-dialog-scrollable"> 639 <div class="modal-content"> 640 <div class="modal-header"> 641 <h5 class="modal-title" id="usagesModelLabel">@allUsages Usages of '@(themeName)' (@(themeClassName))</h5> 642 <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> 643 </div> 644 <div class="modal-body"> 645 <div class="accordion" id="accordionWrapper"> 646 @if(websiteUsages > 0) 647 { 648 <div class="accordion-item"> 649 <h2 class="accordion-header" id="headingWebsites"> 650 <button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#collapseWebsites" aria-expanded="true" aria-controls="collapseWebsites"> 651 <span class="pe-2">Websites</span><span class="badge rounded-pill bg-secondary text-light">@websiteUsages</span> 652 </button> 653 </h2> 654 <div id="collapseWebsites" class="accordion-collapse collapse show" aria-labelledby="headingWebsites" data-bs-parent="#accordionWrapper"> 655 <div class="accordion-body"> 656 <ul> 657 @foreach (var usage in themeUsage.WebsiteUsages) 658 { 659 var website = Dynamicweb.Content.Services.Areas.GetArea(usage); 660 <li><span class="fw-bold">@website.Name</span>@($" (ID: {usage})")</li> 661 } 662 </ul> 663 </div> 664 </div> 665 </div> 666 } 667 @if (pageUsages > 0) 668 { 669 var pages = Dynamicweb.Content.Services.Pages.GetPages(themeUsage.PageUsages.ToArray()); 670 671 <div class="accordion-item"> 672 <h2 class="accordion-header" id="headingPages"> 673 <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapsePages" aria-expanded="false" aria-controls="collapsePages"> 674 <span class="pe-2">Pages</span><span class="badge rounded-pill bg-secondary text-light">@pageUsages</span> 675 </button> 676 </h2> 677 <div id="collapsePages" class="accordion-collapse collapse" aria-labelledby="headingPages" data-bs-parent="#accordionWrapper"> 678 <div class="accordion-body"> 679 <ul> 680 @foreach (var usage in themeUsage.PageUsages) 681 { 682 <li><span class="fw-bold">@pages.FirstOrDefault(p => p.ID == usage).GetDisplayName()</span>@($" (ID: {usage})")</li> 683 } 684 </ul> 685 </div> 686 </div> 687 </div> 688 } 689 @if (pagePropertyUsages > 0) 690 { 691 var pages = Dynamicweb.Content.Services.Pages.GetPages(themeUsage.PageUsages.ToArray()); 692 693 <div class="accordion-item"> 694 <h2 class="accordion-header" id="headingPageProperties"> 695 <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapsePageProperties" aria-expanded="false" aria-controls="collapsePageProperties"> 696 <span class="pe-2">Page Properties</span><span class="badge rounded-pill bg-secondary text-light">@pagePropertyUsages</span> 697 </button> 698 </h2> 699 <div id="collapsePageProperties" class="accordion-collapse collapse" aria-labelledby="headingPageProperties" data-bs-parent="#accordionWrapper"> 700 <div class="accordion-body"> 701 <ul> 702 @foreach (var usage in themeUsage.PagePropertyUsages) 703 { 704 <li><span class="fw-bold">@pages.FirstOrDefault(p => p.ID == usage).GetDisplayName()</span>@($" (ID: {usage})")</li> 705 } 706 </ul> 707 </div> 708 </div> 709 </div> 710 } 711 @if (gridRowUsages > 0) 712 { 713 var rows = Dynamicweb.Content.Services.Grids.GetGridRows().Where(r => themeUsage.GridRowUsages.Contains(r.ID)).ToList(); 714 715 <div class="accordion-item"> 716 <h2 class="accordion-header" id="headingRows"> 717 <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseRows" aria-expanded="false" aria-controls="collapseRows"> 718 <span class="pe-2">Rows</span><span class="badge rounded-pill bg-secondary text-light">@gridRowUsages</span> 719 </button> 720 </h2> 721 <div id="collapseRows" class="accordion-collapse collapse" aria-labelledby="headingRows" data-bs-parent="#accordionWrapper"> 722 <div class="accordion-body"> 723 <ul> 724 @foreach (var usage in themeUsage.GridRowUsages) 725 { 726 var row = rows.FirstOrDefault(r => r.ID == usage); 727 var page = Dynamicweb.Content.Services.Pages.GetPage(row.PageId); 728 <li>Page: <span class="fw-bold">@(page.GetDisplayName())</span>@($"( ID: {page.ID}) - Row: ")<span class="fw-bold">@(row.DefinitionId)</span>@($" (ID: {usage})")</li> 729 } 730 </ul> 731 </div> 732 </div> 733 </div> 734 } 735 @if (paragraphUsages > 0) 736 { 737 var paragraphs = Dynamicweb.Content.Services.Paragraphs.GetParagraphs().Where(p => themeUsage.ParagraphUsages.Contains(p.ID)).ToList(); 738 739 <div class="accordion-item"> 740 <h2 class="accordion-header" id="headingParagraphs"> 741 <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseParagraphs" aria-expanded="false" aria-controls="collapseParagraphs"> 742 <span class="pe-2">Paragraphs</span><span class="badge rounded-pill bg-secondary text-light">@paragraphUsages</span> 743 </button> 744 </h2> 745 <div id="collapseParagraphs" class="accordion-collapse collapse" aria-labelledby="headingParagraphs" data-bs-parent="#accordionWrapper"> 746 <div class="accordion-body"> 747 <ul> 748 @foreach (var usage in themeUsage.ParagraphUsages) 749 { 750 var paragraph = paragraphs.FirstOrDefault(p => p.ID == usage); 751 var page = Dynamicweb.Content.Services.Pages.GetPage(paragraph.PageID); 752 <li>Page: <span class="fw-bold">@(page.GetDisplayName())</span>@($"( ID: {page.ID}) - Paragraph: ")<span class="fw-bold">@paragraph.Header</span>@($" (ID: {usage})")</li> 753 } 754 </ul> 755 </div> 756 </div> 757 </div> 758 } 759 </div> 760 </div> 761 </div> 762 </div> 763 </div> 764 } 765 </div> 766 } 767 } 768 </div> 769 </div> 770 } 771 <div class="g-col-12"> 772 <hr /> 773 </div> 774