New 15km bike park in the heart of Pines forrest
This is a legitimate expert-level trail, but much of the difficulty can be mitigated by slowing down and picking your line carefully.
Disse modeller fås i to forskellige stelmuligheder. En carbon frontende kombineret med en 6061 aluminium bagende eller et mere budgetvenligt chassis helt i aluminium. Disse modeller fås i to forskellige stelmuligheder. En carbon frontende kombineret med en 6061 aluminium bagende eller et mere budgetvenligt chassis helt i aluminium. Disse modeller fås i to forskellige stelmuligheder. En carbon frontende kombineret med en 6061 aluminium bagende eller et mere budgetvenligt chassis helt i aluminium.
Levering inden 7 hverdage
3 års garanti
SHIMANO'S EP8: Kommer udstyret med den nye EP8 motor fra Shimano STePS. Den giver en øget ydeevne på 85 Nm, mindre vægt, en yderligere reduktion i størrelse og mindre friktion. Oven i købet tilbyder det nye interne batteri en udvidet rækkevidde og superhurtige opladningsmuligheder.
INTERN BLOCK: Først introduceret i 2015, e-bike-versionen af 'Internal Block' er indbygget direkte i rammen og forhindrer gaffelkronen i at ramme rammen i tilfælde af et styrt eller en ekstrem styrevinkel. Som en ekstra beskyttelse er der ekstra gummikofangere på stellet for at undgå skader på stellet fra gaffelkronen.
SATELLITPUNKTER: eONE-SIXTY har en perfekt placeret satellit-tænd/sluk-knap, ved toprørets ende af toprøret, og en velbeskyttet satellit-opladningsport, placeret i hovedrammetrekanten lige over motoren.
CLEVER HJUL: For at give de e-full suspension cykler præcis styring, fantastisk 'rulning over forhindringer'-adfærd og alligevel maksimal trækkraft, har vi kombineret et 29er forhjul med et 2,5" dæk og et 650B baghjul, udstyret med et lidt bredere 2,6" dæk. Den perfekte kombination af præcision, legende og trækkraft.
THERMO GATE: Specielt placerede åbninger på kulstofmodellerne nær hovedrøret, der fungerer som en skorsten og tillader den varme luft at sprede sig for at garantere den optimale driftstemperatur for det interne batteri. 'Thermo Gate' gør det muligt for batteriet at yde sit bedste under alle forhold.
VANDBÆRER: På grund af det integrerede batteri var vi i stand til at tilbyde fastgørelsespunkter til vandflaskebure, så flasker eller tilbehør som en lås eller pumpe til rammen kunne monteres i hovedrammetrekanten. Fantastisk, hvis du vil holde ryggen fri for hydreringspakker og rygsække.
CARBON ELLER ALUMINIUM: Disse modeller fås i to forskellige rammemuligheder. En carbon frontende kombineret med en 6061 aluminium bagende eller et mere budgetvenligt chassis helt i aluminium.
| Mærke navn | Merida |
| Batterieffekt (Wh) | 641 |
| Batteri model | Shimano E8036 630Wh |
| Batteri type | Lithium-Ion |
| Batterispænding (V) | 38 |
| Kontrolpanel | LCD panel |
| Motor mærke | Shimano |
| Motorens maksimale drejningsmoment (Nm) | 85 |
| Motor model | SHIMANO STEPS E8000 (EP8) DK |
| Motoreffekt (Watt) | 250 |
| Motor type | Center |
| Rækkevidde | 75 |
| Manufacturer | Merida |
| Ekstraudstyr | Bell Lock Light |
| Bremse bag | BR |
| Bremsetype | Hydraulic disc |
| Bremser | Ultegra x3 |
| Kæde | Ultegra speed 3 |
| Kædehjul | Ultegra speed 3.19 |
| Farve | |
| Skifter foran | Shimano XT 2.0 |
| Skifter bag | Shimano XT 2.0 |
| Forgaffel | Full |
| Stel | Extended |
| Gear | 11 |
| Gearmodel | Shimano XT 2.0 |
| Geartype | External Derailleur |
| Køn | Boys |
| Materialeforbrug | Aluminum Chromoly |
| Anbefalet brug | Mountain bike Living |
| Sadel | Leather |
| Affjedring | Full |
| Dæk | Swan |
| Hjulstørrelse | 29" |
| Volume | 0,62 m³ |
| Weight | 8,2 kg |
| Netto weight | 9 kg |
| Width | 35 cm |
| Height | 115 cm |
Error executing template "/Designs/Swift/Paragraph/Swift_ProductDetailsMediaTable.cshtml" System.ArgumentNullException: Value cannot be null. (Parameter 'source') at System.Linq.ThrowHelper.ThrowArgumentNullException(ExceptionArgument argument) at System.Linq.Enumerable.Contains[TSource](IEnumerable`1 source, TSource value, IEqualityComparer`1 comparer) at CompiledRazorTemplates.Dynamic.RazorEngine_57336dd21a174ed1875669c8bbb69017.<>c__DisplayClass0_0.<ExecuteAsync>b__0(AssetCategoryViewModel x) at System.Linq.Enumerable.WhereListIterator`1.MoveNext() at System.Linq.Enumerable.SelectManySingleSelectorIterator`2.ToArray() at System.Linq.Buffer`1..ctor(IEnumerable`1 source) at System.Linq.OrderedEnumerable`1.GetEnumerator()+MoveNext() at System.Linq.Enumerable.UnionIterator`1.MoveNext() at CompiledRazorTemplates.Dynamic.RazorEngine_57336dd21a174ed1875669c8bbb69017.ExecuteAsync() at RazorEngine.Templating.TemplateBase.Run(ExecuteContext context, TextWriter reader) at RazorEngine.Templating.RazorEngineCore.RunTemplate(ICompiledTemplate template, TextWriter writer, Object model, DynamicViewBag viewBag) at RazorEngine.Templating.RazorEngineService.Run(ITemplateKey key, TextWriter writer, Type modelType, Object model, DynamicViewBag viewBag) at RazorEngine.Templating.DynamicWrapperService.Run(ITemplateKey key, TextWriter writer, Type modelType, Object model, DynamicViewBag viewBag) at RazorEngine.Templating.RazorEngineServiceExtensions.Run(IRazorEngineService service, String name, TextWriter writer, Type modelType, Object model, DynamicViewBag viewBag) at RazorEngine.Templating.RazorEngineServiceExtensions.<>c__DisplayClass23_0.<Run>b__0(TextWriter writer) at RazorEngine.Templating.RazorEngineServiceExtensions.WithWriter(Action`1 withWriter) at RazorEngine.Templating.RazorEngineServiceExtensions.Run(IRazorEngineService service, String name, Type modelType, Object model, DynamicViewBag viewBag) at Dynamicweb.Rendering.RazorTemplateRenderingProvider.Render(Template template) in /_/src/Application/Providers/Dynamicweb.Rendering.Providers.NetCore/Razor/RazorTemplateRenderingProvider.cs:line 68 at Dynamicweb.Rendering.TemplateRenderingService.Render(Template template) in E:\A10\_w\2\s\src\Core\Dynamicweb.Core\Rendering\TemplateRenderingService.cs:line 21 at Dynamicweb.Rendering.Template.RenderRazorTemplate() in E:\A10\_w\2\s\src\Core\Dynamicweb.Core\Rendering\Template.cs:line 805
1 @inherits Dynamicweb.Rendering.ViewModelTemplate<Dynamicweb.Frontend.ParagraphViewModel> @using Dynamicweb.Ecommerce.ProductCatalog @using System.Text.RegularExpressions; @using System.IO @functions { public ProductViewModel product { get; set; } = new ProductViewModel(); public string[] supportedImageFormats { get; set; } public string[] supportedVideoFormats { get; set; } public string[] supportedDocumentFormats { get; set; } public string[] allSupportedFormats { get; set; } public class RatioSettings { public string Ratio { get; set; } public string CssClass { get; set; } public string CssVariable { get; set; } public string Fill { get; set; } } public RatioSettings GetRatioSettings() { var ratioSettings = new RatioSettings(); string ratio = Model.Item.GetRawValueString("ImageAspectRatio", ""); ratio = ratio != "0" ? ratio : ""; string cssClass = ratio != "" && ratio != "fill" ? " ratio" : ""; string cssVariable = ratio != "" && ratio != "fill" ? "--bs-aspect-ratio: " + ratio : ""; ratioSettings.Ratio = ratio; ratioSettings.CssClass = cssClass; ratioSettings.CssVariable = cssVariable; ratioSettings.Fill = ratio == "fill" ? " h-100" : ""; return ratioSettings; } public Dictionary<string, object> GetVideoParams(MediaViewModel asset, string size) { string assetName = !string.IsNullOrEmpty(asset.DisplayName) ? asset.DisplayName : asset.Name; string type = GetVideoType(asset.Value); bool openInModal = Model.Item.GetString("OpenVideoInModal") == "true" ? true : false; bool autoPlay = Model.Item.GetBoolean("VideoAutoPlay"); var videoParams = new Dictionary<string, object>(); videoParams.Add("AssetName", asset.Name); videoParams.Add("AssetVideoType", type); videoParams.Add("AssetDisplayName", asset.DisplayName); videoParams.Add("OpenVideoInModal", openInModal); videoParams.Add("VideoAutoPlay", autoPlay); videoParams.Add("Size", size); videoParams.Add("Id", Model.ID); return videoParams; } public string GetVideoType(string assetValue) { string type = assetValue.IndexOf("youtu.be", StringComparison.OrdinalIgnoreCase) >= 0 || assetValue.IndexOf("youtube", StringComparison.OrdinalIgnoreCase) >= 0 ? "youtube" : string.Empty; type = assetValue.IndexOf("vimeo", StringComparison.OrdinalIgnoreCase) >= 0 ? "vimeo" : type; type = string.IsNullOrEmpty(type) ? "selfhosted" : type; return type; } public string GetYoutubeScreenDump(string assetValue) { var regex = new Regex(@"(?:youtube\.com\/.*[\?&]v=|youtu\.be\/)([\w-]+)"); Match match = regex.Match(assetValue); string videoId = match.Success ? match.Groups[1].Value : string.Empty; string youtubeThumbnail = $"https://img.youtube.com/vi/{videoId}/mqdefault.jpg"; return youtubeThumbnail; } } @{ @* Get the product data *@ ProductViewModel product = null; if (Dynamicweb.Context.Current.Items.Contains("ProductDetails")) { product = (ProductViewModel)Dynamicweb.Context.Current.Items["ProductDetails"]; } else if (Pageview.Page.Item["DummyProduct"] != null && Pageview.IsVisualEditorMode) { var pageViewModel = Dynamicweb.Frontend.ContentViewModelFactory.CreatePageInfoViewModel(Pageview.Page); ProductListViewModel productList = pageViewModel.Item.GetValue("DummyProduct") != null ? pageViewModel.Item.GetValue("DummyProduct") as ProductListViewModel : new ProductListViewModel(); if (productList?.Products is object) { product = productList.Products[0]; } } } @if (product is object) { @* Supported formats *@ supportedImageFormats = new string[] { ".jpg", ".jpeg", ".webp", ".png", ".gif", ".bmp", ".tiff" }; supportedVideoFormats = new string[] { "youtu.be", "youtube", "vimeo", ".mp4", ".webm" }; supportedDocumentFormats = new string[] { ".pdf", ".docx", ".xlsx", ".ppt", ".pptx", ".igs", ".ipt", ".sat", ".stp", ".dwg", ".dxf", ".dwf" }; allSupportedFormats = supportedImageFormats.Concat(supportedVideoFormats).Concat(supportedDocumentFormats).ToArray(); @* Collect the assets *@ var selectedAssetCategories = Model.Item.GetList("ImageAssets")?.GetRawValue().OfType<string>(); bool includeImagePatternImages = Model.Item.GetBoolean("ImagePatternImages"); @* Needed image data collection to support both DefaultImage, ImagePatterns and Image Assets *@ string defaultImage = product.DefaultImage != null ? product.DefaultImage.Value : ""; IEnumerable<MediaViewModel> assetsImages = product.AssetCategories.Where(x => selectedAssetCategories.Contains(x.SystemName)).SelectMany(x => x.Assets); assetsImages = assetsImages.OrderByDescending(x => x.Value.Equals(defaultImage)); IEnumerable<MediaViewModel> assetsList = new MediaViewModel[] { }; assetsList = assetsList.Union(assetsImages); assetsList = includeImagePatternImages ? assetsList.Union(product.ImagePatternImages) : assetsList; assetsList = includeImagePatternImages && assetsList.Count() == 0 ? assetsList.Append(product.DefaultImage) : assetsList; bool defaultImageFallback = Model.Item.GetBoolean("DefaultImageFallback"); bool showOnlyPrimaryImage = Model.Item.GetBoolean("ShowOnlyPrimaryImage"); int totalAssets = 0; if (showOnlyPrimaryImage == false) { foreach (MediaViewModel asset in assetsList) { var assetValue = asset.Value; foreach (string format in allSupportedFormats) { if (assetValue.IndexOf(format, StringComparison.OrdinalIgnoreCase) >= 0) { totalAssets++; } } } } if ((totalAssets == 0 && product.DefaultImage != null && selectedAssetCategories.Count() == 0) || (showOnlyPrimaryImage == true && product.DefaultImage != null)) { assetsList = new List<MediaViewModel>(){ product.DefaultImage }; totalAssets = 1; } int videoNumber = 0; @* Layout settings *@ string spacing = Model.Item.GetRawValueString("Spacing", "p-0"); spacing = spacing == "none" ? "p-0" : spacing; spacing = spacing == "small" ? "p-3" : spacing; spacing = spacing == "large" ? "p-5" : spacing; string theme = !string.IsNullOrWhiteSpace(Model.Item.GetRawValueString("Theme")) ? " theme " + Model.Item.GetRawValueString("Theme").Replace(" ", "").Trim().ToLower() : ""; bool hideThumbnails = Model.Item.GetBoolean("HideThumbnails"); string iconPath = "/Files/Templates/Designs/Swift/Assets/icons/"; int modalVideoNumber = 0; @* Get assets from selected categories or get all assets *@ if (totalAssets != 0 && assetsList.Any()) { <div class="@spacing@(theme) item_@Model.Item.SystemName.ToLower()"> @if (!string.IsNullOrEmpty(Model.Item.GetString("Title")) && !Model.Item.GetBoolean("HideTitle")) { string titleFontSize = Model.Item.GetRawValueString("TitleFontSize", "h3"); <h3 class="@titleFontSize mb-3"> @Model.Item.GetString("Title") </h3> } <div class="table-responsive"> <table class="table table-hover align-middle mb-0" style="table-layout: fixed;"> <thead> <tr> @if (!hideThumbnails) { <th style="width:60px"> </th> } <th>@Translate("Name")</th> <th class="text-end d-none d-lg-table-cell">@Translate("Download")</th> <th class="text-end" style="width:100px">@Translate("File type")</th> </tr> </thead> <tbody class="border-top-0"> @foreach (MediaViewModel asset in assetsList) { var assetValue = asset.Value; string assetName = !string.IsNullOrEmpty(asset.DisplayName) ? asset.DisplayName : asset.Value.Substring(asset.Value.LastIndexOf('/') + 1); bool isVideo = false; foreach (string format in supportedVideoFormats) { //Videos if (assetValue.IndexOf(format, StringComparison.OrdinalIgnoreCase) >= 0) { isVideo = true; } } if (!isVideo) { if (assetValue.StartsWith("/Files/", StringComparison.OrdinalIgnoreCase)) { string filePath = Dynamicweb.Context.Current.Server.MapPath(assetValue); long fileSize = 0; if (File.Exists(filePath)) { fileSize = new System.IO.FileInfo(filePath) != null ? new System.IO.FileInfo(filePath).Length / 1024 : 0; foreach (string format in allSupportedFormats) { if (assetValue.IndexOf(format, StringComparison.OrdinalIgnoreCase) >= 0) { <tr> @if (!hideThumbnails) { //From @RenderAsset string imageTheme = !string.IsNullOrWhiteSpace(Model.Item.GetRawValueString("ImageTheme")) ? " theme " + Model.Item.GetRawValueString("ImageTheme").Replace(" ", "").Trim().ToLower() : ""; <td class="@(imageTheme) px-0"> @foreach (string imageFormat in supportedImageFormats) { //Images if (assetValue.IndexOf(imageFormat, StringComparison.OrdinalIgnoreCase) >= 0) { string productName = product.Name; productName += !string.IsNullOrEmpty(asset.Keywords) ? " " + asset.Keywords : ""; string imagePath = !string.IsNullOrEmpty(asset.Value) ? asset.Value : product.DefaultImage.Value; string imageLinkPath = imagePath; imagePath = $"/Admin/Public/GetImage.ashx?image={imagePath}&width=60&format=webp"; imagePath = !imageLinkPath.StartsWith("/Files/", StringComparison.OrdinalIgnoreCase) ? asset.Value : imagePath; string assetTitle = !string.IsNullOrEmpty(asset.DisplayName) ? "title=\"" + asset.DisplayName + "\"" : ""; RatioSettings ratioSettings = GetRatioSettings(); <a href="@imageLinkPath" class="d-block @(ratioSettings.CssClass)@(ratioSettings.Fill)" style="@(ratioSettings.CssVariable)" download> <div class="d-flex align-items-center justify-content-center overflow-hidden h-100"> <img loading="lazy" src="@imagePath" class="mw-100 mh-100" alt="@productName" @assetTitle itemprop="image"> </div> </a> } } @foreach (string videoFormat in supportedVideoFormats) { //Videos if (assetValue.IndexOf(videoFormat, StringComparison.OrdinalIgnoreCase) >= 0) { string productName = product.Name; productName += !string.IsNullOrEmpty(asset.Keywords) ? " " + asset.Keywords : ""; string assetTitle = !string.IsNullOrEmpty(asset.DisplayName) ? "title=\"" + asset.DisplayName + "\"" : ""; RatioSettings ratioSettings = GetRatioSettings(); string type = GetVideoType(asset.Value); string videoScreendumpPath = type == "youtube" ? GetYoutubeScreenDump(asset.Value) : string.Empty; videoScreendumpPath = type == "selfhosted" ? System.Uri.EscapeUriString(asset.Value) : videoScreendumpPath; string videoJsClass = type == "vimeo" ? "js-vimeo-video-thumbnail" : string.Empty; <div class="d-block @(ratioSettings.CssClass)@(ratioSettings.Fill)" style="@(ratioSettings.CssVariable)"> <div class="d-flex align-items-center justify-content-center overflow-hidden h-100"> <div class="icon-2 position-absolute" style="z-index: 1">@ReadFile(iconPath + "play-circle.svg")</div> @if (type != "selfhosted") { <img src="@videoScreendumpPath" loading="lazy" decoding="async" alt="@productName" @assetTitle class="@videoJsClass mw-100 mh-100" data-asset-value="@asset.Value" style="object-fit: cover;"> } else { string videoType = Path.GetExtension(asset.Value).ToLower(); <video preload="auto" class="h-100 w-100" style="object-fit: contain;"> <source src="@(videoScreendumpPath)#t=0.001" type="video/@videoType.Replace(".", "")"> </video> } </div> </div> } } @foreach (string documentFormat in supportedDocumentFormats) { //Documents if (assetValue.IndexOf(documentFormat, StringComparison.OrdinalIgnoreCase) >= 0) { string productName = product.Name; productName += !string.IsNullOrEmpty(asset.Keywords) ? " " + asset.Keywords : ""; string imagePath = !string.IsNullOrEmpty(asset.Value) ? asset.Value : product.DefaultImage.Value; string imageLinkPath = imagePath; imagePath = $"/Admin/Public/GetImage.ashx?image={imagePath}&width=60&format=webp"; string assetTitle = !string.IsNullOrEmpty(asset.DisplayName) ? "title=\"" + asset.DisplayName + "\"" : ""; RatioSettings ratioSettings = GetRatioSettings(); <a href="@imageLinkPath" class="d-block @(ratioSettings.CssClass)@(ratioSettings.Fill)" style="@(ratioSettings.CssVariable)" download alt="@productName"> @if (asset.Value.IndexOf(".pdf", StringComparison.OrdinalIgnoreCase) >= 0) { <div class="d-flex align-items-center justify-content-center overflow-hidden h-100"> <img loading="lazy" src="@imagePath" class="mw-100 mh-100" alt="@productName" @assetTitle /> </div> } else { <div class="d-flex align-items-center justify-content-center overflow-hidden h-100"> <div class="icon-3 position-absolute" style="z-index: 1">@ReadFile(iconPath + "file-text.svg")</div> </div> } </a> } } </td> } <td> <a href="@assetValue" class="text-decoration-none text-break" download="@assetName" title="@assetName"> @assetName </a> </td> <td class="text-end d-none d-lg-table-cell"> <a href="@assetValue" class="text-decoration-none" download="@assetName" title="@assetName"> @fileSize KB <div class="icon-2" style="z-index: 1">@ReadFile(iconPath + "download.svg")</div> </a> </td> <td class="text-end">@format</td> </tr> } } } } else { <tr> @if (!hideThumbnails) { //From @RenderAsset string imageTheme = !string.IsNullOrWhiteSpace(Model.Item.GetRawValueString("ImageTheme")) ? " theme " + Model.Item.GetRawValueString("ImageTheme").Replace(" ", "").Trim().ToLower() : ""; <td class="@(imageTheme) px-0"> @foreach (string format in supportedImageFormats) { //Images if (assetValue.IndexOf(format, StringComparison.OrdinalIgnoreCase) >= 0) { string productName = product.Name; productName += !string.IsNullOrEmpty(asset.Keywords) ? " " + asset.Keywords : ""; string imagePath = !string.IsNullOrEmpty(asset.Value) ? asset.Value : product.DefaultImage.Value; string imageLinkPath = imagePath; imagePath = $"/Admin/Public/GetImage.ashx?image={imagePath}&width=60&format=webp"; imagePath = !imageLinkPath.StartsWith("/Files/", StringComparison.OrdinalIgnoreCase) ? asset.Value : imagePath; string assetTitle = !string.IsNullOrEmpty(asset.DisplayName) ? "title=\"" + asset.DisplayName + "\"" : ""; RatioSettings ratioSettings = GetRatioSettings(); <a href="@imageLinkPath" class="d-block @(ratioSettings.CssClass)@(ratioSettings.Fill)" style="@(ratioSettings.CssVariable)" download> <div class="d-flex align-items-center justify-content-center overflow-hidden h-100"> <img loading="lazy" src="@imagePath" class="mw-100 mh-100" alt="@productName" @assetTitle itemprop="image"> </div> </a> } } @foreach (string format in supportedVideoFormats) { //Videos if (assetValue.IndexOf(format, StringComparison.OrdinalIgnoreCase) >= 0) { string type = GetVideoType(asset.Value); string videoScreendumpPath = type == "youtube" ? GetYoutubeScreenDump(asset.Value) : string.Empty; videoScreendumpPath = type == "selfhosted" ? System.Uri.EscapeUriString(asset.Value) : videoScreendumpPath; string videoJsClass = type == "vimeo" ? "js-vimeo-video-thumbnail" : string.Empty; string productName = product.Name; productName += !string.IsNullOrEmpty(asset.Keywords) ? " " + asset.Keywords : ""; string assetTitle = !string.IsNullOrEmpty(asset.DisplayName) ? "title=\"" + asset.DisplayName + "\"" : ""; RatioSettings ratioSettings = GetRatioSettings(); <div class="d-block @(ratioSettings.CssClass)@(ratioSettings.Fill)" style="@(ratioSettings.CssVariable)"> <div class="d-flex align-items-center justify-content-center overflow-hidden h-100"> <div class="icon-2 position-absolute" style="z-index: 1">@ReadFile(iconPath + "play-circle.svg")</div> @if (type != "selfhosted") { <img src="@videoScreendumpPath" loading="lazy" decoding="async" alt="@productName" @assetTitle class="@videoJsClass mw-100 mh-100" data-asset-value="@asset.Value" style="object-fit: cover;"> } else { string videoType = Path.GetExtension(asset.Value).ToLower(); <video preload="auto" class="h-100 w-100" style="object-fit: contain;"> <source src="@(videoScreendumpPath)#t=0.001" type="video/@videoType.Replace(".", "")"> </video> } </div> </div> } } @foreach (string format in supportedDocumentFormats) { //Documents if (assetValue.IndexOf(format, StringComparison.OrdinalIgnoreCase) >= 0) { string productName = product.Name; productName += !string.IsNullOrEmpty(asset.Keywords) ? " " + asset.Keywords : ""; string imagePath = !string.IsNullOrEmpty(asset.Value) ? asset.Value : product.DefaultImage.Value; string imageLinkPath = imagePath; imagePath = $"/Admin/Public/GetImage.ashx?image={imagePath}&width=60&format=webp"; string assetTitle = !string.IsNullOrEmpty(asset.DisplayName) ? "title=\"" + asset.DisplayName + "\"" : ""; RatioSettings ratioSettings = GetRatioSettings(); <a href="@imageLinkPath" class="d-block @(ratioSettings.CssClass)@(ratioSettings.Fill)" style="@(ratioSettings.CssVariable)" download alt="@productName"> @if (asset.Value.IndexOf(".pdf", StringComparison.OrdinalIgnoreCase) >= 0) { <div class="d-flex align-items-center justify-content-center overflow-hidden h-100"> <img loading="lazy" src="@imagePath" class="mw-100 mh-100" alt="@productName" @assetTitle /> </div> } else { <div class="d-flex align-items-center justify-content-center overflow-hidden h-100"> <div class="icon-3 position-absolute" style="z-index: 1">@ReadFile(iconPath + "file-text.svg")</div> </div> } </a> } } </td> } <td> <a href="@assetValue" class="text-decoration-none text-break" download="@assetName" title="@assetName"> @assetName </a> </td> <td> </td> <td> </td> </tr> } } else { string videoType = asset.Value.IndexOf("youtu.be", StringComparison.OrdinalIgnoreCase) >= 0 || asset.Value.IndexOf("youtube", StringComparison.OrdinalIgnoreCase) >= 0 ? "Youtube" : ""; videoType = asset.Value.IndexOf("vimeo", StringComparison.OrdinalIgnoreCase) >= 0 ? "Vimeo" : videoType; <tr data-bs-toggle="modal" data-bs-target="#modal_@(Model.ID)_@videoNumber" style="cursor: pointer"> @if (!hideThumbnails) { //From @RenderAsset string imageTheme = !string.IsNullOrWhiteSpace(Model.Item.GetRawValueString("ImageTheme")) ? " theme " + Model.Item.GetRawValueString("ImageTheme").Replace(" ", "").Trim().ToLower() : ""; <td class="@(imageTheme) px-0"> @foreach (string format in supportedImageFormats) { //Images if (assetValue.IndexOf(format, StringComparison.OrdinalIgnoreCase) >= 0) { string productName = product.Name; productName += !string.IsNullOrEmpty(asset.Keywords) ? " " + asset.Keywords : ""; string imagePath = !string.IsNullOrEmpty(asset.Value) ? asset.Value : product.DefaultImage.Value; string imageLinkPath = imagePath; imagePath = $"/Admin/Public/GetImage.ashx?image={imagePath}&width=60&format=webp"; imagePath = !imageLinkPath.StartsWith("/Files/", StringComparison.OrdinalIgnoreCase) ? asset.Value : imagePath; string assetTitle = !string.IsNullOrEmpty(asset.DisplayName) ? "title=\"" + asset.DisplayName + "\"" : ""; RatioSettings ratioSettings = GetRatioSettings(); <a href="@imageLinkPath" class="d-block @(ratioSettings.CssClass)@(ratioSettings.Fill)" style="@(ratioSettings.CssVariable)" download> <div class="d-flex align-items-center justify-content-center overflow-hidden h-100"> <img loading="lazy" src="@imagePath" class="mw-100 mh-100" alt="@productName" @assetTitle itemprop="image"> </div> </a> } } @foreach (string format in supportedVideoFormats) { //Videos if (assetValue.IndexOf(format, StringComparison.OrdinalIgnoreCase) >= 0) { string type = GetVideoType(asset.Value); string videoScreendumpPath = type == "youtube" ? GetYoutubeScreenDump(asset.Value) : string.Empty; videoScreendumpPath = type == "selfhosted" ? System.Uri.EscapeUriString(asset.Value) : videoScreendumpPath; string videoJsClass = type == "vimeo" ? "js-vimeo-video-thumbnail" : string.Empty; string productName = product.Name; productName += !string.IsNullOrEmpty(asset.Keywords) ? " " + asset.Keywords : ""; string assetTitle = !string.IsNullOrEmpty(asset.DisplayName) ? "title=\"" + asset.DisplayName + "\"" : ""; RatioSettings ratioSettings = GetRatioSettings(); <div class="d-block @(ratioSettings.CssClass)@(ratioSettings.Fill)" style="@(ratioSettings.CssVariable)"> <div class="d-flex align-items-center justify-content-center overflow-hidden h-100"> <div class="icon-2 position-absolute" style="z-index: 1">@ReadFile(iconPath + "play-circle.svg")</div> @if (type != "selfhosted") { <img src="@videoScreendumpPath" loading="lazy" decoding="async" alt="@productName" @assetTitle class="@videoJsClass mw-100 mh-100" data-asset-value="@asset.Value" style="object-fit: cover;"> } else { string fileExtension = Path.GetExtension(asset.Value).ToLower(); <video preload="auto" class="h-100 w-100" style="object-fit: contain;"> <source src="@(videoScreendumpPath)#t=0.001" type="video/@fileExtension.Replace(".", "")"> </video> } </div> </div> } } @foreach (string documentFormat in supportedDocumentFormats) { //Documents if (assetValue.IndexOf(documentFormat, StringComparison.OrdinalIgnoreCase) >= 0) { string productName = product.Name; productName += !string.IsNullOrEmpty(asset.Keywords) ? " " + asset.Keywords : ""; string imagePath = !string.IsNullOrEmpty(asset.Value) ? asset.Value : product.DefaultImage.Value; string imageLinkPath = imagePath; imagePath = $"/Admin/Public/GetImage.ashx?image={imagePath}&width=60&format=webp"; string assetTitle = !string.IsNullOrEmpty(asset.DisplayName) ? "title=\"" + asset.DisplayName + "\"" : ""; RatioSettings ratioSettings = GetRatioSettings(); <a href="@imageLinkPath" class="d-block @(ratioSettings.CssClass)@(ratioSettings.Fill)" style="@(ratioSettings.CssVariable)" download alt="@productName"> @if (asset.Value.IndexOf(".pdf", StringComparison.OrdinalIgnoreCase) >= 0) { <div class="d-flex align-items-center justify-content-center overflow-hidden h-100"> <img loading="lazy" src="@imagePath" class="mw-100 mh-100" alt="@productName" @assetTitle /> </div> } else { <div class="d-flex align-items-center justify-content-center overflow-hidden h-100"> <div class="icon-3 position-absolute" style="z-index: 1">@ReadFile(iconPath + "file-text.svg")</div> </div> } </a> } } </td> } <td> @assetName </td> <td class="d-none d-lg-table-cell"> </td> <td align="right">@videoType</td> </tr> videoNumber++; } } </tbody> </table> </div> @foreach (MediaViewModel asset in assetsList) { var assetName = asset.Value.ToLower(); foreach (string videoFormat in supportedVideoFormats) { //Videos if (assetName.IndexOf(videoFormat, StringComparison.OrdinalIgnoreCase) >= 0) { <div class="modal fade js-video-modal" id="modal_@(Model.ID)_@modalVideoNumber" tabindex="-1" aria-labelledby="productDetailsTableModalTitle_@(Model.ID)_@modalVideoNumber" aria-hidden="true"> <div class="modal-dialog modal-dialog-centered modal-xl"> <div class="modal-content"> <div class="modal-header visually-hidden"> <h5 class="modal-title" id="productDetailsTableModalTitle_@(Model.ID)_@modalVideoNumber">@product.Title</h5> <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> </div> <div class="modal-body p-2 p-lg-3 h-100"> @{ var videoParams = GetVideoParams(asset, "modal"); @RenderPartial("Components/VideoPlayer.cshtml", new Dynamicweb.Frontend.FileViewModel { Path = asset.Value }, videoParams) } </div> </div> </div> </div> modalVideoNumber++; } } } </div> } else if (Pageview.IsVisualEditorMode) { <div class="h-100 @theme"> <div class="alert alert-dark m-0"> @Translate("No assets are available") </div> </div> } }