
Balancing the risks and opportunities of AI
AI tools provide big opportunities, but also come with risks. We are ready to guide you, so you can leverage the opportunities with mitigating the risks
AI tools like Microsoft Copilot offer immense potential to transform businesses. With new AI tools like DeepSeek etc. emerging there are a lot of different opportunities, at the same time, data security concerns from governmental instances and organizations are rising, and initiatives like the AI Act have been put into force. So, let’s remember: With great power comes great responsibility.
One of the areas where you need to pay attention, when leveraging the power of AI, is data security. At 9altitudes, we understand the importance of guiding our customers through the complexities and risks associated with AI. As your trusted advisor, we take a balanced and pragmatic approach to ensure you can leverage AI effectively and responsibly.
Therefore, we have gathered 6 advises specifically for you, who want to start leveraging AI while balancing the risks:
1. Acknowledge the importance of data security
Several governmental instances and organizations have raised concerns the past months about data security when working with AI. We recognize that many of these concerns are valid – security, compliance, and governance are important. As a company wishing to leverage the power of AI, you should remember that you (potentially) give the AI access to a wide range of organizational data, if not configured correctly, it could expose sensitive or regulated information. Therefore it’s important to consider how AI will impact your data governance.
Transparency is key, and we are here to help you navigate these concerns.
2. Differentiate between the different AI tools – and their security level
While general AI concerns are valid, it's important to differentiate them from the actual safeguards Microsoft has implemented for their AI-platform, Copilot. Microsoft has robust compliance and security features, making sure your data remains within your control under Microsoft's data policies and is not used to train their foundation models. Tools like Microsoft Purview and Security Copilot can help monitor and mitigate risks related to AI usage.
These safeguards are a fundamental part of how Copilot was designed, but you should remember that not all AI-platforms have the same focus on data protection. So when you are choosing which AI-platform to use, our advice is, that you take this into consideration as well.
3. Create a structured AI governance framework
To ensure responsible AI usage, we recommend establishing clear policies on who can use which AI-tools, what data the tool can access, and how outputs should be validated. Conducting Data Protection Impact Assessments (DPIAs) before widespread deployment is essential. Implementing role-based access control (RBAC) can restrict data exposure, and activating Microsoft Purview can aid in data classification, auditing, and risk detection.
4. Educating and empowering of your end users
Empowering your employees with knowledge is crucial. At 9altitudes, we are ready to provide training on data sensitivity and AI-generated content validation. Encouraging critical thinking is vital - Copilot is an assistant, not a decision-maker. Implementing human review processes before acting on AI-driven insights ensures accuracy and reliability.
Training should not stand alone. Users should know your company guidelines, so that they know how to use AI in compliance with your goals, ethics and compliance standards
5. Get tailored advice based on your company's risk profile
Every business is unique, and so are its risk profiles. High-regulation industries like finance, healthcare, and the public sector may require stricter controls, private instances, or even disabling AI-tools for specific workloads. Where some low-risk environments can proceed with standard security best practices and Microsoft's default safeguards. We tailor our advice to fit your specific needs.
6. Consider alternative AI strategies if necessary
For businesses highly concerned with cloud data processing, on-prem AI solutions or private GPT models may be viable alternatives. And open-source models running on Azure confidential computing, private cloud or other alternatives can reduce exposure. We help you explore all options to find the best fit for your business.
Bottom line
At 9altitudes, we believe in neither blindly recommending nor rejecting Copilot. Instead, we assess, configure, and govern AI responsibly based on your company's risk appetite, regulatory obligations, and data governance maturity. Trust us to guide you through the AI landscape, ensuring you can harness its power while mitigating risks.
Error executing template "Designs/Swift/Paragraph/9a_Content_RelatedContentBanner.cshtml" System.ArgumentException: field "$facets" was not indexed with SortedSetDocValues at Lucene.Net.Facet.SortedSet.DefaultSortedSetDocValuesReaderState..ctor(IndexReader reader, String field) at Dynamicweb.Indexing.Lucene.LuceneIndexProvider.<get_ReaderState>b__14_0(String path) at Dynamicweb.Indexing.Lucene.LuceneIndexProvider.SearchInternal(IQuery query, QuerySettings settings) at Dynamicweb.Indexing.Queries.IndexQueryProvider.Query(IQuery query, QuerySettings settings) at Dynamicweb.Indexing.Querying.QueryService.Query(IQuery query, QuerySettings settings) at NineAltitudes.CustomCode.NineAContent.ContentClient.NineAContentService.GetResults(Int32 pageSize, IQueryService queryService, IQuery query, Dictionary`2 parameters) at NineAltitudes.CustomCode.NineAContent.ContentClient.NineAContentService.GetContentByTagFilters(Int32 pageAreaId, IEnumerable`1 contentTypes, IEnumerable`1 tagFilters, Int32 pageSize) at CompiledRazorTemplates.Dynamic.RazorEngine_4b4bf40587554eb08b06e1b44c31958a.GetFacetedContent(ParagraphViewModel model, Int32 maxItems, Int32 pageAreaId) at CompiledRazorTemplates.Dynamic.RazorEngine_4b4bf40587554eb08b06e1b44c31958a.ExecuteAsync() at RazorEngine.Templating.TemplateBase.Run(ExecuteContext context, TextWriter reader) at RazorEngine.Templating.RazorEngineCore.RunTemplate(ICompiledTemplate template, TextWriter writer, Object model, DynamicViewBag viewBag) at RazorEngine.Templating.RazorEngineService.Run(ITemplateKey key, TextWriter writer, Type modelType, Object model, DynamicViewBag viewBag) at RazorEngine.Templating.DynamicWrapperService.Run(ITemplateKey key, TextWriter writer, Type modelType, Object model, DynamicViewBag viewBag) at RazorEngine.Templating.RazorEngineServiceExtensions.Run(IRazorEngineService service, String name, TextWriter writer, Type modelType, Object model, DynamicViewBag viewBag) at RazorEngine.Templating.RazorEngineServiceExtensions.<>c__DisplayClass23_0.<Run>b__0(TextWriter writer) at RazorEngine.Templating.RazorEngineServiceExtensions.WithWriter(Action`1 withWriter) at RazorEngine.Templating.RazorEngineServiceExtensions.Run(IRazorEngineService service, String name, Type modelType, Object model, DynamicViewBag viewBag) at Dynamicweb.Rendering.RazorTemplateRenderingProvider.Render(Template template) at Dynamicweb.Rendering.TemplateRenderingService.Render(Template template) at Dynamicweb.Rendering.Template.RenderRazorTemplate()
1 @inherits Dynamicweb.Rendering.ViewModelTemplate<Dynamicweb.Frontend.ParagraphViewModel> 2 @using NineAltitudes.CustomCode.NineAContent; 3 @using Dynamicweb.Rendering; 4 @using Dynamicweb.Core; 5 @using Dynamicweb.Extensibility; 6 @using Dynamicweb.Frontend; 7 @using System.Linq; 8 @using System.IO; 9 @using NineAltitudes.CustomCode.NineAContent.ContentClient; 10 11 @{ 12 int maxItemsInList = Model.Item.GetInt32("MaxItemsInList"); 13 if (maxItemsInList == 0) 14 { 15 maxItemsInList = 10; 16 } 17 18 var pageView = Dynamicweb.Frontend.PageView.Current(); 19 int currentPageAreaId = pageView.AreaID; 20 var content = GetFacetedContent(Model, maxItemsInList, currentPageAreaId); 21 } 22 23 @functions { 24 25 private List<Dynamicweb.Frontend.ItemViewModel> GetFacetedContent(ParagraphViewModel model, int maxItems, int pageAreaId) 26 { 27 var selectedTags = GetSelectedTags(model); 28 29 var contentTypes = model.Item?.GetList("ContentTypes")?.GetRawValue().OfType<string>() ?? Enumerable.Empty<string>(); 30 31 var service = ServiceLocator.Current.GetInstance<INineAContentQueryService>(); 32 33 var contentWithTags = service.GetContentByTagFilters(pageAreaId, contentTypes, selectedTags, maxItems); 34 35 36 var localizedTagPageIds = contentWithTags.Select(tag => tag.PageId).Take(maxItems); 37 var content = GetPagesByPageId(localizedTagPageIds); 38 39 return content; 40 } 41 42 private string[] GetSelectedTags(ParagraphViewModel model) 43 { 44 var industry_filters = model.Item?.GetList("Filters_Tags_Industries")?.GetRawValue().OfType<string>(); 45 var vendor_filters = model.Item?.GetList("Filters_Tags_Vendors")?.GetRawValue().OfType<string>(); 46 var domain_filters = model.Item?.GetList("Filters_Tags_Domains")?.GetRawValue().OfType<string>(); 47 var solution_filters = model.Item?.GetList("Filters_Tags_Solutions")?.GetRawValue().OfType<string>(); 48 var product_filters = model.Item?.GetList("Filters_Tags_Products")?.GetRawValue().OfType<string>(); 49 var country_filters = model.Item?.GetList("Filters_Tags_Countries")?.GetRawValue().OfType<string>(); 50 var service_filters = model.Item?.GetList("Filters_Tags_Services")?.GetRawValue().OfType<string>(); 51 var topic_filters = model.Item?.GetList("Filters_Tags_Topics")?.GetRawValue().OfType<string>(); 52 53 var allTags = (industry_filters ?? []) 54 .Concat(vendor_filters ?? []) 55 .Concat(domain_filters ?? []) 56 .Concat(solution_filters ?? []) 57 .Concat(product_filters ?? []) 58 .Concat(country_filters ?? []) 59 .Concat(service_filters ?? []) 60 .Concat(topic_filters ?? []) 61 .ToArray(); 62 63 return allTags; 64 65 } 66 67 private List<Dynamicweb.Frontend.ItemViewModel> GetPagesByPageId(IEnumerable<int> pageIds) 68 { 69 var lists = new List<Dynamicweb.Frontend.ItemViewModel>(); 70 71 if (pageIds.Any()) 72 { 73 foreach (var tagPageID in pageIds) 74 { 75 var page = Dynamicweb.Content.Services.Pages?.GetPage(Dynamicweb.Core.Converter.ToInt32(tagPageID)) ?? null; 76 var viewModel = Dynamicweb.Frontend.ContentViewModelFactory.CreatePageInfoViewModel(page)?.Item ?? null; 77 78 if (viewModel != null) 79 { 80 lists.Add(viewModel); 81 } 82 } 83 } 84 return lists; 85 86 } 87 88 89 private int? ToInt(string value) 90 { 91 return Converter.ToInt32(value); 92 } 93 94 private DateTime? ToDateTime(string value) 95 { 96 return Converter.ToDateTime(value); 97 } 98 } 99 100 101 @{ 102 //Not a parameter anymore 103 string listBehaviour = Model.Item.GetRawValueString("ListBehaviour", "articles"); 104 105 //Not a parameter anymore 106 string articleListLayout = Model.Item.GetRawValueString("ArticleListLayout", "carousel"); 107 string articleItemLayout = Model.Item.GetRawValueString("ArticleItemLayout", string.Empty); 108 109 string columnTheme = Model.Item.GetRawValueString("ColumnTheme", string.Empty).ToString().Replace(" ", "").Trim().ToLower(); 110 111 string columnThemeClass = columnTheme != string.Empty ? " theme " + columnTheme + " p-3" + (articleListLayout == "carousel" ? " px-lg-4" : string.Empty) : string.Empty; 112 113 var carouselSettings = Model.Item.GetRawValueString("CarouselSettings", "4"); 114 115 string slidesPerPage = $"slider-item-show{carouselSettings}"; 116 string navigationStyle = $"{Model.Item.GetRawValueString("NavigationStyle", "slider-nav-round")}"; 117 string navigationPlacement = $"{Model.Item.GetRawValueString("NavigationPlacement", "slider-nav-on-slides")}"; 118 string indicatorStyle = $"{Model.Item.GetRawValueString("IndicatorStyle", string.Empty)}"; 119 string revealSlides = Model.Item.GetRawValueString("RevealSlides", "reveal") == "reveal" ? "slider-item-reveal" : string.Empty; 120 string sliderItemsGap = Model.Item.GetRawValueString("SliderItemsGap", "slider-item-gap") == "slider-item-nogap" ? "slider-item-nogap" : string.Empty; 121 string navigationAlwaysVisible = (Model.Item.GetBoolean("NavigationAlwaysVisible")) ? "slider-nav-visible" : string.Empty; 122 string navigationVisibleOnTouch = (Model.Item.GetBoolean("NavigationVisibleOnTouch")) ? "slider-nav-touch" : string.Empty; 123 string navigationShowScrollbar = (Model.Item.GetBoolean("NavigationShowScrollbar")) ? "slider-nav-scrollbar" : string.Empty; 124 string scrollBarForceMobile = (Model.Item.GetBoolean("NavigationShowScrollbar")) ? "--swiffy-slider-track-height:0.5rem !important;" : string.Empty; 125 string navigationSmall = (Model.Item.GetBoolean("NavigationSmall")) ? "slider-nav-sm" : string.Empty; 126 string navigationInvertColors = (Model.Item.GetBoolean("NavigationInvertColors")) ? "slider-nav-dark" : string.Empty; 127 string navigationSlideEntirePage = (Model.Item.GetBoolean("NavigationSlideEntirePage")) ? "slider-nav-page" : string.Empty; 128 string navigationNoLoop = (Model.Item.GetBoolean("NavigationNoLoop")) ? "slider-nav-noloop" : string.Empty; 129 string indicatorsOutsideSlider = (Model.Item.GetBoolean("IndicatorsOutsideSlider") && indicatorStyle != string.Empty) ? "slider-indicators-outside" : string.Empty; 130 string indicatorsHighlightActive = (Model.Item.GetBoolean("IndicatorsHighlightActive")) ? "slider-indicators-highlight" : string.Empty; 131 string indicatorsInvertColors = (Model.Item.GetBoolean("IndicatorsInvertedColors")) ? "slider-indicators-dark" : string.Empty; 132 string indicatorsVisibleOnSmallDevices = (Model.Item.GetBoolean("IndicatorsVisibleOnSmallDevices")) ? "slider-indicators-sm" : string.Empty; 133 string animation = Model.Item.GetRawValueString("Animation", string.Empty) != string.Empty ? $"slider-nav-animation {Model.Item.GetRawValueString("Animation")}" : string.Empty; 134 string autoplay = (Model.Item.GetBoolean("Autoplay")) ? "slider-nav-autoplay" : string.Empty; 135 string autoplayInterval = Model.Item.GetRawValueString("AutoplayInterval", string.Empty); 136 bool hideSliderNavigation = false; 137 138 var totalItems = content.Count(); 139 var count = content.Count(); 140 var hasItems = content.Any(); 141 142 var percent = count > 0 ? Convert.ToInt32(Math.Round(((double)count / totalItems) * 100, 0)) : 0; 143 var disableLoadMoreButton = count == totalItems ? true : false; 144 145 var loadMore = !disableLoadMoreButton ? $"onclick=\"document.querySelector('#PageSize_{Pageview.CurrentParagraph.ID}').value='{count + maxItemsInList}'; this.dispatchEvent(new window.Event('change', {{ bubbles: true }}))\"" : null; 146 var disabled = disableLoadMoreButton ? "disabled" : null; 147 148 bool showLoadMore = Model.Item.GetBoolean("ShowLoadMore"); 149 150 string titleFontSize = Model.Item.GetString("TitleFontSize", string.Empty); 151 string gridSettings = Model.Item.GetString("GridSettings", "4"); 152 153 bool showButton = Model.Item.GetBoolean("ShowButton"); 154 bool showDates = Model.Item.GetBoolean("ShowDates"); 155 string ratio = Model.Item.GetString("ImageAspectRatio", string.Empty); 156 ratio = ratio != "0" ? ratio : string.Empty; 157 158 string articleItemTheme = Model.Item.GetString("ArticleItemTheme", string.Empty).Replace(" ","").Trim().ToLower(); 159 string articleItemShape = Model.Item.GetString("ArticleItemShape", "boxed"); 160 161 162 if (navigationStyle == "slider-nav-none") 163 { 164 hideSliderNavigation = true; 165 } 166 167 <div class="h-100@(columnThemeClass) item_@Model.Item.SystemName.ToLower()"> 168 <div id="@Model.ID" class="user-select-none" style="scroll-margin-top:var(--header-height,150px)"></div> 169 @{ 170 if (!Model.Item.GetBoolean("HideTitle")) 171 { 172 173 string headingLevel = "h2"; 174 string headingLevelStart = $"<{headingLevel} class=\" mb-4\">"; 175 string headingLevelStop = $"</{headingLevel}>"; 176 @headingLevelStart 177 @Model.Item.GetString("Title") 178 @headingLevelStop 179 } 180 } 181 <div id="Slider_@Model.ID" class="swiffy-slider @(slidesPerPage) @(navigationStyle) @(revealSlides) @(navigationPlacement) @(navigationAlwaysVisible) @(navigationVisibleOnTouch) @(sliderItemsGap) @(indicatorStyle) @(navigationShowScrollbar) @(navigationSmall) @(navigationInvertColors) @(indicatorsOutsideSlider) @(navigationNoLoop) @(indicatorsHighlightActive) @(indicatorsInvertColors) @(indicatorsVisibleOnSmallDevices) @(navigationSlideEntirePage) @(animation) @(autoplay) item_@Model.Item.SystemName.ToLower()" style="--swiffy-slider-nav-light:var(--swift-foreground-color);--swiffy-slider-nav-dark:var(--swift-background-color);visibility:hidden;opacity:0;@(scrollBarForceMobile)" data-slider-nav-autoplay-interval="@(autoplayInterval)"> 182 <div class="slider-container pb-3 py-lg-3 px-lg-3 mt-lg-n3 mx-lg-n3"> 183 184 @{ 185 186 // CARD SPECIFIC SETTINGS 187 188 string orderReverseClass = articleItemLayout == "image-right" ? " order-first order-lg-last" : string.Empty; 189 string articleItemLayoutClass = string.Empty; 190 191 string ratioCssClass = ratio != string.Empty ? " ratio" : string.Empty; 192 string ratioVariable = ratio != string.Empty ? "style=\"--bs-aspect-ratio: " + ratio + "\"" : string.Empty; 193 194 string shapeClass = " rounded-0"; 195 if (articleItemShape == "rounded") 196 { 197 shapeClass = " rounded-4"; 198 } 199 200 string settingsClassGrid = string.Empty; 201 switch (gridSettings) 202 { 203 case "2": 204 settingsClassGrid = " grid-md-2"; 205 break; 206 case "3": 207 settingsClassGrid = " grid-md-3"; 208 break; 209 case "4": 210 settingsClassGrid = " grid-md-2 grid-lg-3 grid-xl-4"; 211 break; 212 case "5": 213 settingsClassGrid = " grid-md-2 grid-lg-3 grid-xl-5"; 214 break; 215 } 216 string gridWrapperStart = articleListLayout == "grid" ? $"<div class=\"article-list grid gap-4 grid-1{settingsClassGrid}\">" : null; 217 string gridWrapperEnd = articleListLayout == "grid" ? "</div>" : null; 218 219 bool hasListContext = Pageview.CurrentParagraph.Item["ListContext"] is object; 220 } 221 222 <!--CARDS BEGIN HERE --> 223 224 @foreach (var item in content) 225 { 226 string title = !string.IsNullOrEmpty(item.GetString("Title")) && !item.GetBoolean("HideTitle") ? item.GetString("Title") : string.Empty; 227 string coverTitle = title; 228 string coverImagePath = item.GetString("Image", string.Empty); 229 bool hasFocalPoint = item.GetBoolean("Image.ImageHasFocalPoint"); 230 231 int focalX = hasFocalPoint ? (int)item.GetDouble("ItemPublisher:Item.CoverImage.FocalX") : 0; 232 int focalY = hasFocalPoint ? (int)item.GetDouble("ItemPublisher:Item.CoverImage.FocalY") : 0; 233 234 int xPos = 100 - ((100 - focalX) / 2); 235 int yPos = ((100 - focalY) / 2); 236 string cssPosition = $"{xPos}% {yPos}%"; 237 238 string summary = !string.IsNullOrEmpty(item.GetString("Summary")) ? item.GetString("Summary") : string.Empty; 239 240 string? publishedDate = item.GetString("PublishedDate"); 241 bool hidePublishedDate = item.GetBoolean("HidePublishedDate"); 242 243 if (hidePublishedDate) 244 { 245 publishedDate = null; 246 } 247 else 248 { 249 publishedDate = ToDateTime(publishedDate)?.ToShortDateString(); 250 if (publishedDate == "01/01/1900" || (publishedDate is not null && (publishedDate.Contains("1900") || publishedDate.Contains("0001")))) 251 { 252 publishedDate = null; 253 } 254 } 255 256 string link = item.Link; 257 string buttonLabel = item.GetString("ButtonLabel", string.Empty); 258 259 260 string iconPath = "/Files/Templates/Designs/Swift/Assets/icons/"; 261 262 int? author = ToInt(item.GetString("Author")); 263 264 bool renderContentWrapper = true; 265 bool renderArticleInfoWrapper = true; 266 267 if (string.IsNullOrEmpty(title) && string.IsNullOrEmpty(summary) && string.IsNullOrEmpty(publishedDate) && !showButton) 268 { 269 renderContentWrapper = false; 270 } 271 272 if (string.IsNullOrEmpty(publishedDate) || !showDates) 273 { 274 renderArticleInfoWrapper = false; 275 } 276 277 switch (articleItemLayout) 278 { 279 case "image-left": 280 case "image-right": 281 articleItemLayoutClass = !string.IsNullOrEmpty(coverImagePath) && renderContentWrapper ? "flex-lg-row" : articleItemLayoutClass; 282 break; 283 } 284 285 string imageObjectFit = ratio != string.Empty ? "object-fit: cover;" : "object-fit: contain;"; 286 287 string? coverTheme = item.GetString("CoverTheme")?.Replace(" ", "").Trim().ToLower() ?? string.Empty; 288 289 string themeClass = string.Empty; 290 string coverImageWrapperClass = string.Empty; 291 292 if (!string.IsNullOrEmpty(coverTheme)) 293 { 294 articleItemTheme = coverTheme; 295 } 296 297 if (articleItemTheme != string.Empty) 298 { 299 themeClass = " theme " + articleItemTheme; 300 } 301 302 // Exclude self from list - if list has context (Tags) and if is on same page 303 bool excludeSelf = false; 304 bool renderItem = true; 305 306 renderItem = hasListContext && excludeSelf ? renderItem = false : !hasListContext && !excludeSelf ? renderItem : renderItem; 307 308 if (renderItem) 309 { 310 <article class="card border-0 @(string.IsNullOrEmpty(themeClass) ? "gap-3" : null) @articleItemLayoutClass@(themeClass)@(shapeClass) overflow-hidden @LiftOnHover() @ShadowOnHover()" itemscope itemtype="https://schema.org/CreativeWork" style="background-color: var(--swift-background-color)"> 311 312 @if (!string.IsNullOrEmpty(coverImagePath)) 313 { 314 if (Path.GetExtension(coverImagePath).ToLower() == ".svg") 315 { 316 coverImageWrapperClass = !renderContentWrapper ? "d-flex justify-content-center align-items-center h-100 w-100 " : "w-100 "; 317 318 <a class="@(coverImageWrapperClass)@(orderReverseClass)" title="@title" href="@link" tabindex="-1"> 319 <div class="d-flex justify-content-center align-items-center overflow-hidden@(ratioCssClass)" @ratioVariable> 320 @ReadFile(coverImagePath) 321 </div> 322 </a> 323 } 324 else 325 { 326 coverImageWrapperClass = articleItemLayout == "image-top" ? "position-relative" : $"col {orderReverseClass}"; 327 coverImageWrapperClass += renderContentWrapper && articleItemLayout != "image-top" ? " col-lg-5" : string.Empty; 328 329 string figureClass = articleItemLayout == "image-top" ? ratioCssClass : "h-lg-100 ratio ratio-16x9"; 330 ratioVariable = articleItemLayout == "image-top" ? ratioVariable : string.Empty; 331 332 <a class="@coverImageWrapperClass" title="@title" href="@link" tabindex="-1"> 333 <figure class="overflow-hidden m-0 mx-auto @(figureClass)" @ratioVariable> 334 @{ 335 coverImagePath = Dynamicweb.Context.Current.Server.UrlEncode(coverImagePath); 336 imageObjectFit = articleItemLayout != "image-top" ? "object-fit: cover" : imageObjectFit; 337 338 string imgSizeSelector = "50vw"; 339 imgSizeSelector = gridSettings == "1" || carouselSettings == "1" ? "100vw" : imgSizeSelector; 340 imgSizeSelector = gridSettings == "2" || carouselSettings == "2" ? "50vw" : imgSizeSelector; 341 imgSizeSelector = gridSettings == "3" || carouselSettings == "3" ? "33vw" : imgSizeSelector; 342 imgSizeSelector = gridSettings == "4" || carouselSettings == "4" ? "25vw" : imgSizeSelector; 343 imgSizeSelector = gridSettings == "5" || carouselSettings == "5" ? "17vw" : imgSizeSelector; 344 345 string coverImagePathM = $"/Admin/Public/GetImage.ashx?image={coverImagePath}&width=640&format=webp"; 346 string coverImagePathL = $"/Admin/Public/GetImage.ashx?image={coverImagePath}&width=960&format=webp"; 347 string imagePathFallBack = coverImagePathM; 348 349 <img srcset=" 350 @coverImagePathM 640w, 351 @coverImagePathL 960w" 352 src="@imagePathFallBack" 353 sizes="(min-width: 992px) @imgSizeSelector, 100vw" 354 loading="lazy" 355 decoding="async" 356 class="img-fluid image-zoom-lg-1-hover" 357 style="@imageObjectFit; object-position: @cssPosition;" 358 alt="@title"> 359 } 360 </figure> 361 </a> 362 } 363 } 364 365 @if (renderContentWrapper) 366 { 367 <div class="col d-flex flex-column @GetPadding(themeClass)"> 368 <div class="card-body p-0 d-flex flex-column gap-2"> 369 @*Show tag stickers*@ 370 371 @if (!string.IsNullOrEmpty(title)) 372 { 373 <a class="text-decoration-none text-decoration-underline-hover" href="@link"> 374 <h3 class="@titleFontSize mb-0" itemprop="headline">@title</h3> 375 </a> 376 } 377 @if (!string.IsNullOrEmpty(summary)) 378 { 379 <p class="m-0 opacity-75">@summary</p> 380 } 381 382 @*Show tag stickers*@ 383 @GetTagStickers(item) 384 385 @if (showButton) 386 { 387 <div class="mt-auto"> 388 389 @if (!string.IsNullOrEmpty(buttonLabel)) 390 { 391 <a href="@link" class="text-start btn btn-link p-0"> 392 @buttonLabel 393 <span class="icon-auto"> 394 @ReadFile(iconPath + "arrow-right.svg") 395 </span> 396 </a> 397 } 398 else 399 { 400 <a href="@link" class="btn btn-link p-0 lh-1 text-start"> 401 <span class="icon-auto"> 402 @ReadFile(iconPath + "arrow-right.svg") 403 </span> 404 </a> 405 } 406 </div> 407 } 408 409 </div> 410 411 @if (renderArticleInfoWrapper) 412 { 413 <div class="card-footer p-0 pt-3 border-top-0"> 414 <div class="d-flex align-items-center justify-content-between gap-3"> 415 @if (author != null && author != 0) 416 { 417 int authorID = author.Value; 418 var authorUser = Dynamicweb.Security.UserManagement.User.GetUserByID(authorID); 419 string authorImage = !string.IsNullOrEmpty(authorUser?.Image) ? authorUser.Image : string.Empty; 420 string authorImagePath = !string.IsNullOrEmpty(authorUser?.Image) ? $"/Admin/Public/GetImage.ashx?image={authorUser.Image}&width=24&height=24&Crop=0&format=webp" : string.Empty; 421 string authorName = !string.IsNullOrEmpty(authorUser?.Name) ? authorName = authorUser.Name : string.Empty; 422 string authorJobTitle = !string.IsNullOrEmpty(authorUser?.JobTitle) ? authorJobTitle = authorUser.JobTitle : string.Empty; 423 424 <div class="d-flex align-items-center gap-2 fs-8 opacity-75"> 425 426 @if (!string.IsNullOrEmpty(authorImage)) 427 { 428 <img class="img-fluid rounded-circle" src="@authorImagePath" loading="lazy" alt="@authorName" width="24" height="24"> 429 } 430 else 431 { 432 <div class="d-flex align-items-center justify-content-center rounded-circle" style="background-color: rgba(var(--swift-foreground-color-rgb),.25)"> 433 <div class="icon-2 p-1"> 434 @ReadFile(iconPath + "user.svg") 435 </div> 436 </div> 437 } 438 439 <div class="d-flex flex-column lh-1"> 440 @if (!string.IsNullOrEmpty(authorName)) 441 { 442 <span itemprop="author">@authorName</span> 443 } 444 @if (!string.IsNullOrEmpty(authorJobTitle)) 445 { 446 <span class="opacity-75">@authorJobTitle</span> 447 } 448 </div> 449 </div> 450 } 451 452 @if (!string.IsNullOrEmpty(publishedDate)) 453 { 454 455 string articleDateTime = publishedDate; 456 457 <div class="d-flex align-items-center gap-1 fs-8 opacity-75"> 458 <div class="icon-1"> 459 @ReadFile(iconPath + "calendar.svg") 460 </div> 461 <time datetime="@articleDateTime" itemprop="datePublished">@publishedDate</time> 462 </div> 463 } 464 </div> 465 </div> 466 } 467 </div> 468 } 469 </article> 470 } 471 472 473 } 474 475 <!-- CARDS END HERE --> 476 </div> 477 478 @if (!hideSliderNavigation) 479 { 480 <button type="button" title="@Translate("Previous slide")" class="slider-nav" style="z-index:1;"> 481 <span class="visually-hidden">@Translate("Previous slide")</span> 482 </button> 483 <button type="button" title="@Translate("Next slide")" class="slider-nav slider-nav-next" style="z-index:1;"> 484 <span class="visually-hidden">@Translate("Next slide")</span> 485 </button> 486 } 487 @if (indicatorStyle != "slider-indicators-hidden") 488 { 489 <div class="slider-indicators" style="z-index:1;"></div> 490 } 491 492 <script type="module" src="/Files/Templates/Designs/Swift/Assets/js/swiffy-slider.js"></script> 493 <script> 494 window.addEventListener("load", () => { 495 initSlider_@(Model.ID)(); 496 }); 497 498 document.addEventListener("updated.swift.pageupdater", function (data) { 499 initSlider_@(Model.ID)(); 500 }); 501 502 function initSlider_@(Model.ID)() { 503 swift.AssetLoader.Load('/Files/Templates/Designs/Swift/Assets/css/swiffy-slider.min.css', 'css'); 504 window.swiffyslider.initSlider(document.querySelector('#Slider_@Model.ID')); 505 document.querySelector('#Slider_@Model.ID').style.opacity = 1; 506 document.querySelector('#Slider_@Model.ID').style.visibility = "visible"; 507 } 508 </script> 509 510 @if (indicatorStyle != "slider-indicators-hidden") 511 { 512 <script type="module"> 513 const slider = document.querySelector('#Slider_@Model.ID'); 514 const sliderContainer = slider.querySelector('.slider-container'); 515 let slides = sliderContainer.querySelectorAll('article'); 516 const sliderIndicators = slider.querySelector('.slider-indicators'); 517 518 slides.forEach((slide, index) => { 519 const indicator = document.createElement('template'); 520 indicator.innerHTML = ` 521 <button type="button" class="${index == 0 ? "active" : ""}" title='@Translate("Go to slide") ${index + 1}'> 522 <span class="visually-hidden">@Translate("Go to slide") ${index + 1}</span> 523 </button> 524 `; 525 sliderIndicators.appendChild(indicator.content); 526 }); 527 </script> 528 } 529 </div> 530 531 532 </div> 533 } 534 535 @functions{ 536 537 538 539 private string GetTagStickers(ItemViewModel item) 540 { 541 var stickers = string.Empty; 542 543 if (item.GetString("ItemPublisher:Item.SystemName") == "Swift_Article") 544 { 545 var showTags = Pageview.CurrentParagraph.Item["ShowTags"] != null ? (Boolean)Pageview.CurrentParagraph.Item["ShowTags"] : false; 546 547 if (showTags && GetTags(item).Count >= 1) 548 { 549 stickers += "<div class=\"d-inline-flex flex-wrap gap-1\">"; 550 foreach (var tag in GetTags(item)) 551 { 552 stickers += CreateSticker(tag); 553 } 554 stickers += "</div>"; 555 } 556 } 557 558 559 /* CUSTOM 9a Content type */ 560 if (item.GetString("ItemPublisher:Item.SystemName") == "9a_Content") 561 { 562 563 } 564 /* CUSTOM END */ 565 566 return stickers; 567 } 568 569 570 571 private List<string> GetTags(ItemViewModel item) 572 { 573 var tags = new List<string>(); 574 575 //foreach (var tag in item.GetLoop("ItemPublisher:Item.Tags.Options")) 576 //{ 577 // if (tag.GetBoolean("ItemPublisher:Item.Tags.Option.IsSelected")) 578 // { 579 // tags.Add(tag.GetString("ItemPublisher:Item.Tags.Option.Label")); 580 // } 581 //} 582 583 return tags; 584 } 585 586 587 private string CreateSticker(string label) 588 { 589 string shape = Pageview.CurrentParagraph.Item["ArticleItemShape"] != null ? Pageview.CurrentParagraph.Item["ArticleItemShape"].ToString() : "boxed"; 590 var sticker = $"<span class=\"badge fw-normal shadow-none\" style=\"border: 1px solid rgba(var(--swift-foreground-color-rgb), 0.2);\">{label}</span>"; 591 return sticker; 592 } 593 594 595 private string LiftOnHover() 596 { 597 bool liftOnHover = Pageview.CurrentParagraph.Item["LiftOnHover"] != null ? (Boolean)Pageview.CurrentParagraph.Item["LiftOnHover"] : false; 598 var lift = liftOnHover ? "lift" : null; 599 return lift; 600 } 601 602 private string ShadowOnHover() 603 { 604 bool shadowOnHover = Pageview.CurrentParagraph.Item["ShadowOnHover"] != null ? (Boolean)Pageview.CurrentParagraph.Item["ShadowOnHover"] : false; 605 var shadow = shadowOnHover ? "shadow-hover" : null; 606 return shadow; 607 } 608 609 private string GetPadding(string theme) 610 { 611 var padding = !string.IsNullOrEmpty(theme) ? "p-3" : null; 612 return padding; 613 } 614 615 private string GetGap(string theme) 616 { 617 var padding = string.IsNullOrEmpty(theme) ? "gap-3" : null; 618 return padding; 619 } 620 }