Voir plus d'images

Carafe - 4 verres inclus

Custom_USP1
100 % anti-goutte
Custom_USP2
Pour les boissons chaudes et froides
Custom_USP3
Passe au lave-vaisselle
€ 59,95 InStock
  • Livraison à partir de 5 euros
  • Délai de livraison: 2-5 jours ouvrés
Veuillez sélectionner une quantité divisible par 4

Lave-vaisselle Oui
Capacité (litres) 1
Hauteur (cm) 27
Largeur (cm) 10
Profondeur (cm) 10
Diamètre (cm) 10
Masse (kg) 0,15
Designer Tools Design
Brand Eva Solo
Numéro d'article 567460
EAN 5706631018845

Livraison offerte pour toute commande de 89 € ou plus

Votre commande est expédiée un ou deux jours ouvrables après avoir été passée. Vous recevez les informations de suivi dès que votre commande quitte notre entrepôt. Le délai de livraison dépend du pays de destination.

Les frais de livraison dépendent du pays de destination et de la méthode d'expédition, que vous sélectionnez lors du paiement.

Error executing template "/Designs/Swift/Paragraph/Swift_ProductDetailsGallery_Custom.cshtml"
System.NullReferenceException: Object reference not set to an instance of an object.
   at CompiledRazorTemplates.Dynamic.RazorEngine_38a2cfd25f854a09b15b2c52b7edffb6.Execute() in D:\dynamicweb.net\Solutions\twodayco3\evasolo.cloud.dynamicweb-cms.com\Files\Templates\Designs\Swift\Paragraph\Swift_ProductDetailsGallery_Custom.cshtml:line 89
   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()

1 @inherits Dynamicweb.Rendering.ViewModelTemplate<Dynamicweb.Frontend.ParagraphViewModel> 2 @using Dynamicweb.Ecommerce.ProductCatalog 3 @using Dynamicweb.Frontend 4 @using System.IO 5 @using System.Web; 6 7 @* CUSTOMIZED STANDARD SWIFT (v1.?) TEMPLATE *@ 8 @* TODO: REFACTURE/UPGRADE TO SWIFT (v1.25.0) *@ 9 @* NOTE: This template use the standard customized item logic; so template need to be selected on item (layout), or one the website (Item paragraph layouts) *@ 10 11 @functions { 12 public ProductViewModel product { get; set; } = new ProductViewModel(); 13 public string galleryLayout { get; set; } 14 public string[] supportedImageFormats { get; set; } 15 public string[] supportedVideoFormats { get; set; } 16 public string[] supportedDocumentFormats { get; set; } 17 public string[] allSupportedFormats { get; set; } 18 19 public class RatioSettings 20 { 21 public string Ratio { get; set; } 22 public string CssClass { get; set; } 23 public string CssVariable { get; set; } 24 public string Fill { get; set; } 25 } 26 27 public RatioSettings GetRatioSettings(string size = "desktop") 28 { 29 var ratioSettings = new RatioSettings(); 30 31 string ratio = Model.Item.GetRawValueString("ImageAspectRatio", ""); 32 ratio = ratio != "0" ? ratio : ""; 33 string cssClass = ratio != "" && ratio != "fill" ? " ratio" : ""; 34 string cssVariable = ratio != "" && ratio != "fill" ? "--bs-aspect-ratio: " + ratio : ""; 35 cssClass = ratio != "" && ratio == "fill" && size == "mobile" ? " ratio" : cssClass; 36 cssVariable = ratio != "" && ratio == "fill" && size == "mobile" ? "--bs-aspect-ratio: 66%" : cssVariable; 37 38 ratioSettings.Ratio = ratio; 39 ratioSettings.CssClass = cssClass; 40 ratioSettings.CssVariable = cssVariable; 41 ratioSettings.Fill = ratio == "fill" ? " h-100" : ""; 42 43 return ratioSettings; 44 } 45 46 // CUSTOM parameter 47 public string GetColumnClass(int total, int assetNumber, bool customIsIconGallery) 48 { 49 string colClass = total > 1 ? "g-col-lg-6" : "g-col-12"; 50 colClass = galleryLayout == "full-first" && assetNumber == 0 ? "g-col-12" : colClass; 51 colClass = galleryLayout == "full-last" && assetNumber == (total - 1) ? "g-col-12" : colClass; 52 colClass = galleryLayout == "advanced-grid" && assetNumber > 1 ? "g-col-4" : colClass; 53 54 colClass = galleryLayout == "advanced-grid" && total == 1 ? "g-col-12" : colClass; 55 colClass = galleryLayout == "advanced-grid" && total == 3 && assetNumber == 2 ? "g-col-12" : colClass; 56 colClass = galleryLayout == "advanced-grid" && total == 4 && assetNumber == 2 ? "g-col-6" : colClass; 57 colClass = galleryLayout == "advanced-grid" && total == 4 && assetNumber == 3 ? "g-col-6" : colClass; 58 colClass = galleryLayout == "advanced-grid" && total == 6 && assetNumber == 5 ? "g-col-12" : colClass; 59 colClass = galleryLayout == "advanced-grid" && total == 7 && assetNumber == 5 ? "g-col-6" : colClass; 60 colClass = galleryLayout == "advanced-grid" && total == 7 && assetNumber == 6 ? "g-col-6" : colClass; 61 colClass = galleryLayout == "advanced-grid" && total == 9 && assetNumber == 8 ? "g-col-12" : colClass; 62 colClass = customIsIconGallery ? "g-col-1" : colClass; // CUSTOM 63 64 return colClass; 65 } 66 67 public string GetArrowsColor() 68 { 69 var invertColor = Model.Item.GetBoolean("InvertModalArrowsColor"); 70 var arrowsColor = invertColor ? " carousel-dark" : string.Empty; 71 return arrowsColor; 72 } 73 } 74 75 @{ 76 @* Get the product data *@ 77 if (Dynamicweb.Context.Current.Items.Contains("ProductDetails")) 78 { 79 product = (ProductViewModel)Dynamicweb.Context.Current.Items["ProductDetails"]; 80 } 81 82 @* Supported formats *@ 83 supportedImageFormats = new string[] { ".jpg", ".jpeg", ".webp", ".png", ".gif", ".bmp", ".tiff" }; 84 supportedVideoFormats = new string[] { "youtu.be", "youtube", "vimeo", ".mp4", ".webm" }; 85 supportedDocumentFormats = new string[] { ".pdf", ".docx", ".xlsx", ".ppt", "pptx" }; 86 allSupportedFormats = supportedImageFormats.Concat(supportedVideoFormats).Concat(supportedDocumentFormats).ToArray(); 87 88 @* Collect the assets *@ 89 var selectedAssetCategories = Model.Item.GetRawValueString("ImageAssets").Split(',').ToList(); 90 bool includeImagePatternImages = Model.Item.GetBoolean("ImagePatternImages"); 91 92 @* Needed image data collection to support both DefaultImage, ImagePatterns and Image Assets *@ 93 string defaultImage = product.DefaultImage != null ? product.DefaultImage.Value : ""; 94 IEnumerable<MediaViewModel> assetsImages = product.AssetCategories.Where(x => selectedAssetCategories.Contains(x.SystemName)).SelectMany(x => x.Assets); 95 // CUSTOM 96 assetsImages = selectedAssetCategories.Contains("Videos") ? assetsImages.OrderByDescending(x => x.Value.Contains("vimeo")) : assetsImages.OrderByDescending(x => x.Value.Equals(defaultImage)); 97 IEnumerable<MediaViewModel> assetsList = new MediaViewModel[] { }; 98 assetsList = assetsList.Union(assetsImages); 99 assetsList = includeImagePatternImages ? assetsList.Union(product.ImagePatternImages) : assetsList; 100 assetsList = includeImagePatternImages && assetsList.Count() == 0 ? assetsList.Append(product.DefaultImage) : assetsList; 101 102 bool defaultImageFallback = Model.Item.GetBoolean("DefaultImageFallback"); 103 // CUSTOM 104 bool customIsIconGallery = selectedAssetCategories.Any(category => category.Contains("Icons")) || selectedAssetCategories.Any(category => category.Contains("Awards")); 105 106 int totalAssets = 0; 107 foreach (MediaViewModel asset in assetsList) 108 { 109 var assetValue = asset.Value.ToLower(); 110 foreach (string format in allSupportedFormats) 111 { 112 if (assetValue.Contains(format)) 113 { 114 totalAssets++; 115 } 116 } 117 } 118 119 if (totalAssets == 0) 120 { 121 if (defaultImageFallback) 122 { 123 assetsList = new List<MediaViewModel>() { product.DefaultImage }; 124 totalAssets = 1; 125 } 126 else 127 { 128 assetsList = new List<MediaViewModel>() { }; 129 totalAssets = 0; 130 } 131 } 132 133 @* Layout settings *@ 134 string spacing = Model.Item.GetRawValueString("Spacing", "4"); 135 spacing = spacing == "none" ? "gap-0" : spacing; 136 spacing = spacing == "small" ? "gap-3" : spacing; 137 spacing = spacing == "large" ? "gap-4" : spacing; 138 139 galleryLayout = Model.Item.GetRawValueString("Layout", "grid"); 140 string theme = !string.IsNullOrWhiteSpace(Model.Item.GetRawValueString("Theme")) ? " theme " + Model.Item.GetRawValueString("Theme").Replace(" ", "").Trim().ToLower() : ""; 141 142 var badgeParms = new Dictionary<string, object>(); 143 badgeParms.Add("size", "h5"); 144 badgeParms.Add("saleBadgeType", Model.Item.GetRawValue("SaleBadgeType")); 145 badgeParms.Add("saleBadgeCssClassName", Model.Item.GetRawValue("SaleBadgeDesign")); 146 badgeParms.Add("newBadgeCssClassName", Model.Item.GetRawValue("NewBadgeDesign")); 147 badgeParms.Add("newPublicationDays", Model.Item.GetInt32("NewPublicationDays")); 148 badgeParms.Add("campaignBadgesValues", Model.Item.GetRawValueString("CampaignBadges")); 149 150 bool saleBadgeEnabled = !string.IsNullOrWhiteSpace(Model.Item.GetRawValueString("SaleBadgeDesign")) && Model.Item.GetRawValueString("SaleBadgeDesign") != "none" ? true : false; 151 bool newBadgeEnabled = !string.IsNullOrWhiteSpace(Model.Item.GetRawValueString("NewBadgeDesign")) && Model.Item.GetRawValueString("NewBadgeDesign") != "none" ? true : false; 152 DateTime createdDate = product.Created.Value; 153 bool showBadges = saleBadgeEnabled && product.Discount.Price != 0 ? true : false; 154 showBadges = (newBadgeEnabled && Model.Item.GetInt32("NewPublicationDays") == 0) || (newBadgeEnabled && (createdDate.AddDays(Model.Item.GetInt32("NewPublicationDays")) > DateTime.Now)) ? true : showBadges; 155 showBadges = !string.IsNullOrEmpty(Model.Item.GetRawValueString("CampaignBadges")) ? true : showBadges; 156 } 157 158 @* Get assets from selected categories or get all assets *@ 159 @if (totalAssets != 0 && assetsList.Count() != 0) 160 { 161 int desktopAssetNumber = 0; 162 int mobileAssetNumber = 0; 163 int mobileAssetThumbnailNumber = 0; 164 int modalAssetNumber = 0; 165 string customBsColumns = customIsIconGallery ? "custom-col-8" : ""; 166 167 @* Desktop: Show the gallery on large screens *@ 168 <div class="d-none d-lg-block h-100 position-relative @theme item_@Model.Item.SystemName.ToLower() desktop"> 169 <div class="grid @spacing @customBsColumns"> 170 @foreach (MediaViewModel asset in assetsList) 171 { 172 var assetName = asset.Value.ToLower(); 173 foreach (string format in allSupportedFormats) 174 { 175 if (assetName.Contains(format)) 176 { 177 <div class="@GetColumnClass(totalAssets, desktopAssetNumber, customIsIconGallery)"> 178 @{@RenderAsset(asset, desktopAssetNumber)} 179 </div> 180 desktopAssetNumber++; 181 } 182 } 183 } 184 </div> 185 186 @if (showBadges) 187 { 188 <div class="position-absolute top-0 left-0 p-2 p-lg-3 w-100"> 189 @RenderPartial("Components/EcommerceBadge.cshtml", product, badgeParms) 190 </div> 191 } 192 </div> 193 194 // CUSTOM 195 if (!customIsIconGallery) 196 { 197 @* Mobile: Show the thumbs on small screens *@ 198 <div class="d-block d-lg-none mx-lg-0 position-relative @theme item_@Model.Item.SystemName.ToLower() mobile"> 199 <div id="SmallScreenImages_@Model.ID" class="carousel@(GetArrowsColor())" data-bs-ride="carousel"> 200 <div class="carousel-inner h-100"> 201 @foreach (MediaViewModel asset in assetsList) 202 { 203 var assetValue = asset.Value.ToLower(); 204 foreach (string format in allSupportedFormats) 205 { 206 if (assetValue.Contains(format)) 207 { 208 string activeSlide = mobileAssetNumber == 0 ? "active" : ""; 209 210 <div class="carousel-item @activeSlide" data-bs-interval="99999"> 211 @{@RenderAsset(asset, mobileAssetNumber, "mobile")} 212 </div> 213 mobileAssetNumber++; 214 } 215 } 216 } 217 </div> 218 </div> 219 220 @if (totalAssets > 1) 221 { 222 <div id="SmallScreenImagesThumbnails_@Model.ID" class="d-flex flex-nowrap gap-2 overflow-x-auto my-3"> 223 @foreach (MediaViewModel asset in assetsList) 224 { 225 var assetValue = asset.Value; 226 foreach (string format in allSupportedFormats) 227 { 228 if (assetValue.Contains(format)) 229 { 230 string imagePath = Dynamicweb.Context.Current.Server.UrlEncode(assetValue); 231 imagePath = assetValue.Contains("youtu.be") || assetValue.Contains("youtube") ? "https://img.youtube.com/vi/" + assetValue.Substring(assetValue.LastIndexOf('/') + 1) + "/default.jpg" : imagePath; 232 string imagePathThumb = !imagePath.Contains("youtube") ? $"/Admin/Public/GetImage.ashx?image={imagePath}&width=160&format=webp" : imagePath; 233 string iconPath = "/Files/Templates/Designs/Swift/Assets/icons/"; 234 235 string videoId = assetValue.Substring(assetValue.LastIndexOf('/') + 1); 236 string vimeoJsClass = assetValue.Contains("vimeo") ? "js-vimeo-video-thumbnail" : ""; 237 imagePathThumb = imagePathThumb.Contains("vimeo") ? "" : imagePathThumb; 238 239 string productName = product.Name; 240 productName += !string.IsNullOrEmpty(asset.Keywords) ? " " + asset.Keywords : ""; 241 string assetTitle = !string.IsNullOrEmpty(asset.DisplayName) ? "title=\"" + asset.DisplayName + "\"" : ""; 242 243 <div class="ratio ratio-4x3 border outline-none" style="flex:0 0 80px" data-bs-target="#SmallScreenImages_@Model.ID" data-bs-slide-to="@mobileAssetThumbnailNumber"> 244 @foreach (string videoFormat in supportedVideoFormats) 245 { 246 if (assetValue.Contains(videoFormat)) 247 { 248 <div class="d-flex align-items-center justify-content-center overflow-hidden h-100"> 249 <div class="icon-3 position-absolute text-light" style="z-index: 1">@ReadFile(iconPath + "play-circle.svg")</div> 250 </div> 251 } 252 } 253 <img src="@imagePathThumb" class="p-1 @vimeoJsClass mw-100 mh-100" data-video-id="@videoId" style="object-fit: cover;" alt="@Dynamicweb.Core.Encoders.HtmlEncoder.HtmlAttributeEncode(productName)" @assetTitle> 254 </div> 255 256 mobileAssetThumbnailNumber++; 257 } 258 } 259 } 260 </div> 261 } 262 263 @if (showBadges) 264 { 265 <div class="position-absolute top-0 left-0 p-2 p-lg-3"> 266 @RenderPartial("Components/EcommerceBadge.cshtml", product, badgeParms) 267 </div> 268 } 269 </div> 270 } 271 else 272 { 273 <div class="d-block d-lg-none h-100 position-relative mobile"> 274 <div class="grid"> 275 @foreach (MediaViewModel asset in assetsList) 276 { 277 var assetName = asset.Value.ToLower(); 278 foreach (string format in allSupportedFormats) 279 { 280 if (assetName.Contains(format)) 281 { 282 <div class="g-col-3"> 283 @RenderAsset(asset, mobileAssetNumber) 284 </div> 285 mobileAssetNumber++; 286 } 287 } 288 } 289 </div> 290 </div> 291 } 292 293 @* Modal with slides *@ 294 <div class="modal fade swift_products-details-images-modal" id="modal_@Model.ID" tabindex="-1" aria-labelledby="productDetailsGalleryModalTitle_@Model.ID" aria-hidden="true"> 295 <div class="modal-dialog modal-dialog-centered modal-xl"> 296 <div class="modal-content"> 297 <div class="modal-header visually-hidden"> 298 <h5 class="modal-title" id="productDetailsGalleryModalTitle_@Model.ID">@product.Title</h5> 299 <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> 300 </div> 301 <div class="modal-body p-2 p-lg-3 h-100"> 302 <div id="ModalCarousel_@Model.ID" class="carousel@(GetArrowsColor()) h-100" data-bs-ride="carousel"> 303 <div class="carousel-inner h-100 @theme"> 304 @foreach (MediaViewModel asset in assetsList) 305 { 306 var assetValue = !string.IsNullOrEmpty(asset.Value) ? asset.Value : product.DefaultImage.Value; 307 foreach (string format in allSupportedFormats) 308 { 309 if (assetValue.Contains(format)) 310 { 311 string imagePath = assetValue; 312 string activeSlide = modalAssetNumber == 0 ? "active" : ""; 313 314 var parms = new Dictionary<string, object>(); 315 parms.Add("cssClass", "d-block mw-100 mh-100 m-auto"); 316 parms.Add("fullwidth", true); 317 parms.Add("columns", Model.GridRowColumnCount); 318 319 <div class="carousel-item @activeSlide h-100" data-bs-interval="99999"> 320 @foreach (string imageFormat in supportedImageFormats) 321 { 322 if (assetValue.Contains(imageFormat)) 323 { 324 @RenderPartial("Components/Image.cshtml", new FileViewModel { Path = imagePath }, parms) 325 } 326 } 327 328 @foreach (string videoFormat in supportedVideoFormats) 329 { 330 if (assetValue.Contains(videoFormat)) 331 { 332 {@RenderVideoPlayer(asset, "modal")} 333 } 334 } 335 </div> 336 337 modalAssetNumber++; 338 } 339 } 340 } 341 <button class="carousel-control-prev" type="button" data-bs-target="#ModalCarousel_@Model.ID" data-bs-slide="prev"> 342 <span class="carousel-control-prev-icon" aria-hidden="true"></span> 343 <span class="visually-hidden">@Translate("Previous")</span> 344 </button> 345 <button class="carousel-control-next" type="button" data-bs-target="#ModalCarousel_@Model.ID" data-bs-slide="next"> 346 <span class="carousel-control-next-icon" aria-hidden="true"></span> 347 <span class="visually-hidden">@Translate("Next")</span> 348 </button> 349 </div> 350 </div> 351 </div> 352 </div> 353 </div> 354 </div> 355 } 356 else if (Pageview.IsVisualEditorMode) 357 { 358 RatioSettings ratioSettings = GetRatioSettings("desktop"); 359 360 <div class="h-100 @theme"> 361 <div class="d-block @(ratioSettings.CssClass)@(ratioSettings.Fill)" style="@(ratioSettings.CssVariable)"> 362 <img src="/Files/Images/missing_image.jpg" loading="lazy" decoding="async" class="mh-100 mw-100" style="object-fit: cover;" alt="@Dynamicweb.Core.Encoders.HtmlEncoder.HtmlAttributeEncode(Translate("Missing image"))"> 363 </div> 364 </div> 365 } 366 367 @helper RenderAsset(MediaViewModel asset, int assetNumber, string size = "desktop") 368 { 369 string theme = !string.IsNullOrWhiteSpace(Model.Item.GetRawValueString("ImageTheme")) ? " theme " + Model.Item.GetRawValueString("ImageTheme").Replace(" ", "").Trim().ToLower() : ""; 370 string assetValue = asset.Value; 371 372 <div class="h-100 @(theme)"> 373 @foreach (string format in supportedImageFormats) 374 { //Images 375 if (assetValue.Contains(format)) 376 { 377 {@RenderImage(asset, assetNumber, size)} 378 } 379 } 380 @foreach (string format in supportedVideoFormats) 381 { //Videos 382 if (assetValue.Contains(format)) 383 { 384 if (Model.Item.GetString("OpenVideoInModal") == "true") 385 { 386 {@RenderVideoScreendump(asset, assetNumber, size)} 387 } 388 else 389 { 390 {@RenderVideoPlayer(asset, size)} 391 } 392 } 393 } 394 @foreach (string format in supportedDocumentFormats) 395 { //Documents 396 if (assetValue.Contains(format)) 397 { 398 {@RenderDocument(asset, assetNumber, size)} 399 } 400 } 401 </div> 402 } 403 404 @helper RenderImage(MediaViewModel asset, int number, string size = "desktop") 405 { 406 string productName = product.Name; 407 string imagePath = !string.IsNullOrEmpty(asset.Value) ? asset.Value : product.DefaultImage.Value; 408 string imageLinkPath = Dynamicweb.Context.Current.Server.UrlEncode(imagePath); 409 410 RatioSettings ratioSettings = GetRatioSettings(size); 411 412 var parms = new Dictionary<string, object>(); 413 parms.Add("alt", productName); 414 parms.Add("itemprop", "image"); 415 parms.Add("fullwidth", true); 416 parms.Add("columns", Model.GridRowColumnCount); 417 if (!string.IsNullOrEmpty(asset.DisplayName)) 418 { 419 parms.Add("title", asset.DisplayName); 420 } 421 422 if (ratioSettings.Ratio == "fill" && galleryLayout != "grid") 423 { 424 parms.Add("cssClass", "w-100 h-100 image-zoom-lg-l-hover"); 425 } 426 else 427 { 428 parms.Add("cssClass", "mw-100 mh-100"); 429 } 430 431 <a href="@imageLinkPath" class="d-block @(ratioSettings.CssClass)@(ratioSettings.Fill)" style="@(ratioSettings.CssVariable)" data-bs-toggle="modal" data-bs-target="#modal_@Model.ID"> 432 <div class="d-flex align-items-center justify-content-center overflow-hidden h-100" data-bs-target="#ModalCarousel_@Model.ID" data-bs-slide-to="@number"> 433 @RenderPartial("Components/Image.cshtml", new FileViewModel { Path = imagePath }, parms) 434 </div> 435 </a> 436 } 437 438 @helper RenderVideoScreendump(MediaViewModel asset, int number, string size = "desktop") 439 { 440 string iconPath = "/Files/Templates/Designs/Swift/Assets/icons/"; 441 442 string videoScreendumpPath = !string.IsNullOrEmpty(asset.Value) ? asset.Value : ""; 443 string videoId = videoScreendumpPath.Substring(videoScreendumpPath.LastIndexOf('/') + 1); 444 videoScreendumpPath = videoScreendumpPath.Contains("youtu.be") || videoScreendumpPath.Contains("youtube") ? "https://img.youtube.com/vi/" + videoId + "/maxresdefault.jpg" : videoScreendumpPath; 445 446 string vimeoJsClass = videoScreendumpPath.Contains("vimeo") ? "js-vimeo-video-thumbnail" : ""; 447 videoScreendumpPath = videoScreendumpPath.Contains("vimeo") ? "" : videoScreendumpPath; 448 449 string productName = product.Name; 450 productName += !string.IsNullOrEmpty(asset.Keywords) ? " " + asset.Keywords : ""; 451 string assetTitle = !string.IsNullOrEmpty(asset.DisplayName) ? "title=\"" + asset.DisplayName + "\"" : ""; 452 453 RatioSettings ratioSettings = GetRatioSettings(size); 454 455 <div class="d-block @(ratioSettings.CssClass)@(ratioSettings.Fill)" style="@(ratioSettings.CssVariable); cursor: pointer" data-bs-toggle="modal" data-bs-target="#modal_@Model.ID"> 456 <div class="d-flex align-items-center justify-content-center overflow-hidden h-100" data-bs-target="#ModalCarousel_@Model.ID" data-bs-slide-to="@number"> 457 <div class="icon-5 position-absolute" style="z-index: 1">@ReadFile(iconPath + "play-circle.svg")</div> 458 <img src="@videoScreendumpPath" loading="lazy" decoding="async" alt="@Dynamicweb.Core.Encoders.HtmlEncoder.HtmlAttributeEncode(productName)" @assetTitle class="@vimeoJsClass mw-100 mh-100" data-video-id="@videoId" style="object-fit: cover;"> 459 </div> 460 </div> 461 } 462 463 @helper RenderVideoPlayer(MediaViewModel asset, string size = "desktop") 464 { 465 string assetName = !string.IsNullOrEmpty(asset.DisplayName) ? asset.DisplayName : asset.Name; 466 string assetValue = asset.Value; 467 string assetDescription = !string.IsNullOrEmpty(product.ShortDescription) ? product.ShortDescription : product.Name; 468 DateTime assetUploadDate = product.Created.Value; 469 string videoId = asset.Value.Substring(asset.Value.LastIndexOf('/') + 1); 470 string type = assetValue.Contains("youtu.be") || assetValue.Contains("youtube") ? "youtube" : ""; 471 type = assetValue.Contains("vimeo") ? "vimeo" : type; 472 type = assetValue.Contains(".mp4") || assetValue.Contains(".webm") ? "selfhosted" : type; 473 474 string openInModal = Model.Item.GetString("OpenVideoInModal"); 475 bool autoPlay = Model.Item.GetBoolean("VideoAutoPlay"); 476 bool onlyAutoPlayInIntersecting = Model.Item.GetBoolean("Custom_VideoOnlyAutoPlayInIntersecting"); 477 bool onlyAutoPlayOnce = Model.Item.GetBoolean("Custom_VideoOnlyAutoPlayOnce"); 478 DateTime uploadDate = product.Created.Value; 479 480 var useSchema = (type != "vimeo"); 481 482 <div class="h-100 plyr-gallery-parent" @(useSchema ? "itemscope itemtype=\"https://schema.org/VideoObject\"" : "")> 483 484 @if (useSchema) 485 { 486 if (type == "selfhosted") 487 { 488 var selfhostedFileInfo = new System.IO.FileInfo(Dynamicweb.Core.SystemInformation.MapPath(assetValue)); 489 if (selfhostedFileInfo != null) 490 { 491 assetUploadDate = selfhostedFileInfo.LastWriteTime; 492 } 493 } 494 495 <span class="visually-hidden" itemprop="name">@assetName</span> 496 <span class="visually-hidden" itemprop="contentUrl">@assetValue</span> 497 <span class="visually-hidden" itemprop="thumbnailUrl">@assetValue</span> 498 <span class="visually-hidden" itemprop="description">@assetDescription</span> 499 <span class="visually-hidden" itemprop="uploadDate">@assetUploadDate.ToString("yyyy-MM-dd'T'HH:mm:ss")</span> 500 } 501 502 @if (type != "selfhosted") 503 { 504 var playerId = $"player_{Pageview.CurrentParagraph.ID}_{videoId}_{size}"; 505 506 <div id="@(playerId)" 507 class="plyr__video-embed custom" 508 data-plyr-provider="@(type)" 509 data-plyr-embed-id="@videoId" 510 style="--plyr-color-main: var(--swift-foreground-color); color:green;"> 511 </div> 512 513 <script type="module" src="~/Files/Templates/Designs/Swift/Assets/js/plyr.js"></script> 514 515 <script type="module"> 516 //CookieConsent("marketing", () => { 517 const player = new Plyr('#@(playerId)', { 518 type: 'video', 519 youtube: { 520 noCookie: true, 521 showinfo: 0 522 }, 523 fullscreen: { 524 enabled: true, 525 iosNative: true 526 }, 527 vimeo: { 528 playsinline: true, 529 }, 530 controls: [], 531 clickToPlay: false, 532 autopause: false 533 }); 534 //}); 535 536 @if (autoPlay && openInModal == "false") 537 { 538 <text> 539 player.config.autoplay = @(!onlyAutoPlayInIntersecting ? "true" : "false"); 540 player.config.muted = true; 541 player.config.volume = 0; 542 player.config.loop = { active: @(!onlyAutoPlayOnce ? "true" : "false") }; 543 544 let useIntersecting = @(onlyAutoPlayInIntersecting ? "true" : "false"); 545 </text> 546 547 if (onlyAutoPlayInIntersecting) 548 { 549 <text> 550 player.on('ready', function () { 551 const observer = new IntersectionObserver(entries => { 552 entries.forEach(entry => { 553 if (useIntersecting) { 554 if (entry.isIntersecting) { 555 player.play(); 556 } 557 else { 558 player.pause(); 559 } 560 } 561 }); 562 }); 563 observer.observe(this.parentElement); 564 }); 565 </text> 566 } 567 568 if (onlyAutoPlayOnce) 569 { 570 <text> 571 player.on('ended', () => { 572 player.stop(); 573 player.restart(); 574 useIntersecting = false; 575 576 var playButton = document.createElement('button'); 577 playButton.type = 'button'; 578 playButton.className = 'plyr__control plyr__control--overlaid'; 579 playButton.setAttribute('aria-plyr', 'play'); 580 playButton.setAttribute('aria-label', 'Play'); 581 playButton.innerHTML = '<svg aria-hidden="true" focusable="false"><use xlink: href="#plyr-play"></use></svg><span class="plyr__sr-only">Play</span>'; 582 playButton.addEventListener('click', function () { 583 this.remove(); 584 player.play(); 585 useIntersecting = true; 586 }); 587 588 player.elements.container.appendChild(playButton); 589 }); 590 </text> 591 } 592 } 593 594 @if (openInModal == "true") { 595 <text> 596 var productDetailsGalleryModal = document.querySelector('#modal_@Model.ID') 597 productDetailsGalleryModal.addEventListener('hidden.bs.modal', function (event) { 598 player.media.pause(); 599 }) 600 </text> 601 } 602 603 </script> 604 } 605 else 606 { 607 string autoPlayAttributes = (autoPlay && openInModal == "false") ? "loop autoplay muted playsinline" : ""; 608 string videoType = Path.GetExtension(assetValue).ToLower(); 609 610 <video preload="auto" @autoPlayAttributes class="h-100 w-100" style="object-fit: cover;"> 611 <source src="@assetValue" type="video/@videoType.Replace(".", "")"> 612 </video> 613 } 614 </div> 615 } 616 617 @helper RenderDocument(MediaViewModel asset, int number, string size = "desktop") 618 { 619 string iconPath = "/Files/Templates/Designs/Swift/Assets/icons/"; 620 621 string productName = product.Name; 622 string imagePath = !string.IsNullOrEmpty(asset.Value) ? asset.Value : product.DefaultImage.Value; 623 string imageLinkPath = imagePath; 624 625 RatioSettings ratioSettings = GetRatioSettings(size); 626 627 var parms = new Dictionary<string, object>(); 628 parms.Add("alt", productName); 629 parms.Add("itemprop", "image"); 630 parms.Add("fullwidth", true); 631 parms.Add("columns", Model.GridRowColumnCount); 632 if (!string.IsNullOrEmpty(asset.DisplayName)) 633 { 634 parms.Add("title", asset.DisplayName); 635 } 636 637 if (ratioSettings.Ratio == "fill" && galleryLayout != "grid") 638 { 639 parms.Add("cssClass", "w-100 h-100 image-zoom-lg-l-hover"); 640 } 641 else 642 { 643 parms.Add("cssClass", "mw-100 mh-100"); 644 } 645 646 <a href="@imageLinkPath" class="d-block @(ratioSettings.CssClass)@(ratioSettings.Fill)" style="@(ratioSettings.CssVariable)" download title="@Dynamicweb.Core.Encoders.HtmlEncoder.HtmlAttributeEncode(Translate("Download"))"> 647 <div class="d-flex align-items-center justify-content-center overflow-hidden h-100"> 648 <div class="icon-5 position-absolute" style="z-index: 1">@ReadFile(iconPath + "download.svg")</div> 649 @if (asset.Value.Contains(".pdf")) 650 { 651 @RenderPartial("Components/Image.cshtml", new FileViewModel { Path = imagePath }, parms) 652 } 653 else 654 { 655 656 } 657 </div> 658 </a> 659 } 660

La description

Elle peut être utilisée pour servir n’importe quelle boisson ainsi que pour décanter et servir du vin. Verre résistant à la chaleur.

Contenu connexe

#EVASOLO COMMUNITY

@evasolo_official | #evasolo | #evatrio | #evasolofurniture