diff --git a/src/sdk/PnP.Core/Model/SharePoint/Branding/Internal/BrandingManager.cs b/src/sdk/PnP.Core/Model/SharePoint/Branding/Internal/BrandingManager.cs index 1124c20eac..657c538b99 100644 --- a/src/sdk/PnP.Core/Model/SharePoint/Branding/Internal/BrandingManager.cs +++ b/src/sdk/PnP.Core/Model/SharePoint/Branding/Internal/BrandingManager.cs @@ -425,7 +425,8 @@ public async Task GetChromeOptionsAsync() p => p.HorizontalQuickLaunch, // Load these properties now as they're needed in the HasCommunicationSiteFeaturesAsync method p => p.WebTemplate, - p => p.Features).ConfigureAwait(false); + p => p.Features, + p => p.AllProperties).ConfigureAwait(false); var menuState = await GetMenuStateBatchAsync(batch).ConfigureAwait(false); @@ -451,6 +452,28 @@ private void ProcessChromeOptionsResponse(IWeb web, bool hasCommunicationSiteFea Emphasis = web.HeaderEmphasis }; + // Modern Header Feature MC1098935 + if (web.AllProperties.Values.TryGetValue("HeaderOverlayColor", out var HeaderOverlayColor) && int.TryParse(HeaderOverlayColor.ToString(), out var headerOverlayColor) && Enum.IsDefined(typeof(OverlayColorType), headerOverlayColor)) + { + chromeOptions.Header.OverlayColor = (OverlayColorType)headerOverlayColor; + } + if (web.AllProperties.Values.TryGetValue("HeaderOverlayOpacity", out var HeaderOverlayOpacity) && int.TryParse(HeaderOverlayOpacity.ToString(), out var headerOverlayOpacity)) + { + chromeOptions.Header.OverlayOpacity = headerOverlayOpacity; + } + if (web.AllProperties.Values.TryGetValue("HeaderOverlayGradientDirection", out var HeaderOverlayGradientDirection) && int.TryParse(HeaderOverlayGradientDirection.ToString(), out var headerOverlayGradientDirection) && Enum.IsDefined(typeof(OverlayGradientDirectionType), headerOverlayGradientDirection)) + { + chromeOptions.Header.OverlayGradientDirection = (OverlayGradientDirectionType)headerOverlayGradientDirection; + } + if (web.AllProperties.Values.TryGetValue("HeaderColorIndexInLightMode", out var HeaderColorIndexInLightMode) && int.TryParse(HeaderColorIndexInLightMode.ToString(), out var headerColorIndexInLightMode)) + { + chromeOptions.Header.ColorIndexInLightMode = headerColorIndexInLightMode; + } + if (web.AllProperties.Values.TryGetValue("HeaderColorIndexInDarkMode", out var HeaderColorIndexInDarkMode) && int.TryParse(HeaderColorIndexInDarkMode.ToString(), out var headerColorIndexInDarkMode)) + { + chromeOptions.Header.ColorIndexInDarkMode = headerColorIndexInDarkMode; + } + chromeOptions.Navigation = new NavigationOptions { MegaMenuEnabled = web.MegaMenuEnabled, @@ -467,6 +490,34 @@ private void ProcessChromeOptionsResponse(IWeb web, bool hasCommunicationSiteFea Enabled = web.FooterEnabled }; + // Modern Footer Feature MC1098935 + if (web.AllProperties.Values.TryGetValue("FooterAlignment", out var FooterAlignment) && int.TryParse(FooterAlignment.ToString(), out var footerAlignment) && Enum.IsDefined(typeof(FooterLinkAlignment), footerAlignment)) + { + chromeOptions.Footer.LinkAlignment = (FooterLinkAlignment)footerAlignment; + } + if (web.AllProperties.Values.TryGetValue("FooterOverlayColor", out var FooterOverlayColor) && int.TryParse(FooterOverlayColor.ToString(), out var footerOverlayColor) && Enum.IsDefined(typeof(OverlayColorType), footerOverlayColor)) + { + chromeOptions.Footer.OverlayColor = (OverlayColorType)footerOverlayColor; + } + if (web.AllProperties.Values.TryGetValue("FooterOverlayOpacity", out var FooterOverlayOpacity) && int.TryParse(FooterOverlayOpacity.ToString(), out var footerOverlayOpacity)) + { + chromeOptions.Footer.OverlayOpacity = footerOverlayOpacity; + } + if (web.AllProperties.Values.TryGetValue("FooterOverlayGradientDirection", out var FooterOverlayGradientDirection) && int.TryParse(FooterOverlayGradientDirection.ToString(), out var footerOverlayGradientDirection) && Enum.IsDefined(typeof(OverlayGradientDirectionType), footerOverlayGradientDirection)) + { + chromeOptions.Footer.OverlayGradientDirection = (OverlayGradientDirectionType)footerOverlayGradientDirection; + } + + if (web.AllProperties.Values.TryGetValue("FooterColorIndexInLightMode", out var FooterColorIndexInLightMode) && int.TryParse(FooterColorIndexInLightMode.ToString(), out var footerColorIndexInLightMode)) + { + chromeOptions.Footer.ColorIndexInLightMode = footerColorIndexInLightMode; + } + if (web.AllProperties.Values.TryGetValue("FooterColorIndexInDarkMode", out var FooterColorIndexInDarkMode) && int.TryParse(FooterColorIndexInDarkMode.ToString(), out var footerColorIndexInDarkMode)) + { + chromeOptions.Footer.ColorIndexInDarkMode = footerColorIndexInDarkMode; + } + + if (menuState != null) { (chromeOptions.Footer as FooterOptions).MenuState = menuState; @@ -482,6 +533,31 @@ private void ProcessChromeOptionsResponse(IWeb web, bool hasCommunicationSiteFea } } } + + chromeOptions.Font = new FontOptions(); + //Font Options + if (web.AllProperties.Values.TryGetValue("FontOptionForSiteTitle", out var FontOptionForSiteTitle) + | web.AllProperties.Values.TryGetValue("FontOptionForSiteNav", out var FontOptionForSiteNav) + | web.AllProperties.Values.TryGetValue("FontOptionForSiteFooterTitle", out var FontOptionForSiteFooterTitle) + | web.AllProperties.Values.TryGetValue("FontOptionForSiteFooterNav", out var FontOptionForSiteFooterNav)) + { + if(!string.IsNullOrWhiteSpace(FontOptionForSiteTitle?.ToString())) + { + chromeOptions.Font.SiteTitle = JsonSerializer.Deserialize(FontOptionForSiteTitle.ToString()); + } + if (!string.IsNullOrWhiteSpace(FontOptionForSiteNav?.ToString())) + { + chromeOptions.Font.SiteNav = JsonSerializer.Deserialize(FontOptionForSiteNav.ToString()); + } + if (!string.IsNullOrWhiteSpace(FontOptionForSiteFooterTitle?.ToString())) + { + chromeOptions.Font.SiteFooterTitle = JsonSerializer.Deserialize(FontOptionForSiteFooterTitle.ToString()); + } + if (!string.IsNullOrWhiteSpace(FontOptionForSiteFooterNav?.ToString())) + { + chromeOptions.Font.SiteFooterNav = JsonSerializer.Deserialize(FontOptionForSiteFooterNav.ToString()); + } + } } public IChromeOptions GetChromeOptions() @@ -504,7 +580,8 @@ public async Task> GetChromeOptionsBatchAsync p => p.HorizontalQuickLaunch, // Load these properties now as they're needed in the HasCommunicationSiteFeaturesAsync method p => p.WebTemplate, - p => p.Features).ConfigureAwait(false); + p => p.Features, + p => p.AllProperties).ConfigureAwait(false); var menuState = await GetMenuStateBatchAsync(batch).ConfigureAwait(false); @@ -593,13 +670,28 @@ private static ApiCall BuildSetChromeOptionsApiCall(IChromeOptions chromeOptions { headerLayout = chromeOptions.Header.Layout, headerEmphasis = chromeOptions.Header.Emphasis, + headerOverlayColor = chromeOptions.Header.OverlayColor, + headerOverlayOpacity = chromeOptions.Header.OverlayOpacity, + headerOverlayGradientDirection = chromeOptions.Header.OverlayGradientDirection, + headerColorIndexInLightMode = chromeOptions.Header.ColorIndexInLightMode, + headerColorIndexInDarkMode = chromeOptions.Header.ColorIndexInDarkMode, hideTitleInHeader = chromeOptions.Header.HideTitle, logoAlignment = chromeOptions.Header.LogoAlignment, megaMenuEnabled = chromeOptions.Navigation != null ? chromeOptions.Navigation.MegaMenuEnabled : false, horizontalQuickLaunch = chromeOptions.Navigation != null ? chromeOptions.Navigation.HorizontalQuickLaunch : false, footerEnabled = chromeOptions.Footer != null ? chromeOptions.Footer.Enabled : false, footerLayout = chromeOptions.Footer != null ? chromeOptions.Footer.Layout : FooterLayoutType.Simple, - footerEmphasis = chromeOptions.Footer != null ? chromeOptions.Footer.Emphasis : FooterVariantThemeType.Strong + footerEmphasis = chromeOptions.Footer != null ? chromeOptions.Footer.Emphasis : FooterVariantThemeType.Strong, + footerAlignment = chromeOptions.Footer != null ? chromeOptions.Footer.LinkAlignment: FooterLinkAlignment.Right, + footerOverlayColor = chromeOptions.Footer != null ? chromeOptions.Footer.OverlayColor : OverlayColorType.None, + footerOverlayOpacity = chromeOptions.Footer != null ? chromeOptions.Footer.OverlayOpacity : 0, + footerOverlayGradientDirection = chromeOptions.Footer != null ? chromeOptions.Footer.OverlayGradientDirection : OverlayGradientDirectionType.TopToBottom, + footerColorIndexInLightMode = chromeOptions.Footer != null ? chromeOptions.Footer.ColorIndexInLightMode : -1, + footerColorIndexInDarkMode = chromeOptions.Footer != null ? chromeOptions.Footer.ColorIndexInDarkMode : -1, + fontOptionForSiteTitle = chromeOptions.Font != null ? chromeOptions.Font.SiteTitle : null, + fontOptionForSiteNav = chromeOptions.Font != null ? chromeOptions.Font.SiteNav : null, + fontOptionForSiteFooterTitle = chromeOptions.Font != null ? chromeOptions.Font.SiteFooterTitle : null, + fontOptionForSiteFooterNav = chromeOptions.Font != null ? chromeOptions.Font.SiteFooterNav : null, }; string jsonBody = JsonSerializer.Serialize(body); @@ -720,7 +812,210 @@ private static void ReflectChromeUpdatesInCurrentWeb(PnPContext context, IChrome context.Web.SetSystemProperty(p => p.FooterLayout, chromeOptions.Footer.Layout); } } - #endregion + + #region OutOfBoxFontPackages + + public async Task> GetOutOfBoxFontPackagesAsync() + { + var batch = context.NewBatch(); + var fontPackages = await GetOutOfBoxFontPackagesBatchAsync(batch).ConfigureAwait(false); + await context.ExecuteAsync(batch).ConfigureAwait(false); + return fontPackages.Result; + } + + public List GetOutOfBoxFontPackages() + { + return GetOutOfBoxFontPackagesAsync().GetAwaiter().GetResult(); + } + + public async Task>> GetOutOfBoxFontPackagesBatchAsync(Batch batch) + { + ApiCall apiCall = BuildGetOutOfBoxFontPackagesApiCall(); + return await GetFontPackagesBatchAsync(batch, apiCall).ConfigureAwait(false); + } + + public IBatchSingleResult> GetOutOfBoxFontPackagesBatch(Batch batch) + { + return GetOutOfBoxFontPackagesBatchAsync(batch).GetAwaiter().GetResult(); + } + + public void SetOutOfBoxFontPackage(string fontId) + { + SetOutOfBoxFontPackageAsync(fontId).Wait(); + } + + public async Task SetOutOfBoxFontPackageAsync(string fontId) + { + var batch = context.NewBatch(); + SetOutOfBoxFontPackageBatch(batch, fontId); + await context.ExecuteAsync(batch).ConfigureAwait(false); + } + + public void SetOutOfBoxFontPackageBatch(Batch batch, string fontId) + { + SetOutOfBoxFontPackageBatchAsync(batch, fontId).GetAwaiter().GetResult(); + } + + public Task SetOutOfBoxFontPackageBatchAsync(Batch batch, string fontId) + { + BuildAndSetOutOfBoxFontPackageApiCall(batch, fontId).Wait(); + return Task.CompletedTask; + } + + private static ApiCall BuildGetOutOfBoxFontPackagesApiCall() + { + return new ApiCall("_api/OutOfBoxFontPackages", ApiType.SPORest); + } + + private async Task BuildAndSetOutOfBoxFontPackageApiCall(Batch batch,string fontId) + { + var apiCall = new ApiCall($"_api/OutOfBoxFontPackages/GetById('{fontId}')/Apply", ApiType.SPORest) + { // The provided JSON is of the minimal odata type + Headers = new Dictionary + { + { "Content-Type", "application/json;odata.metadata=nometadata" }, + } + }; + + await (context.Web as Web).RawRequestBatchAsync(batch, apiCall, HttpMethod.Post, "SetOutOfBoxFontPackage").ConfigureAwait(false); + } + + #endregion OutOfBoxFontPackages + + #region Branding Center FontPackages + public async Task> GetFontPackagesAsync() + { + var batch = context.NewBatch(); + var fontPackages = await GetFontPackagesBatchAsync(batch).ConfigureAwait(false); + await context.ExecuteAsync(batch).ConfigureAwait(false); + return fontPackages.Result; + } + + public List GetFontPackages() + { + return GetFontPackagesAsync().GetAwaiter().GetResult(); + } + + public async Task>> GetFontPackagesBatchAsync(Batch batch) + { + ApiCall apiCall = BuildGetFontPackagesApiCall(); + return await GetFontPackagesBatchAsync(batch, apiCall).ConfigureAwait(false); + } + + public IBatchSingleResult> GetFontPackagesBatch(Batch batch) + { + return GetFontPackagesBatchAsync(batch).GetAwaiter().GetResult(); + } + + public async Task> GetSiteFontPackagesAsync() + { + var batch = context.NewBatch(); + var fontPackages = await GetSiteFontPackagesBatchAsync(batch).ConfigureAwait(false); + await context.ExecuteAsync(batch).ConfigureAwait(false); + return fontPackages.Result; + } + + public void SetFontPackage(string fontId) + { + SetFontPackageAsync(fontId).GetAwaiter().GetResult(); + } + + public async Task SetFontPackageAsync(string fontId) + { + var batch = context.NewBatch(); + SetFontPackageBatch(batch, fontId); + await context.ExecuteAsync(batch).ConfigureAwait(false); + } + + public void SetFontPackageBatch(Batch batch, string fontId) + { + SetPackageBatchAsync(batch,fontId).GetAwaiter().GetResult(); + } + + public Task SetPackageBatchAsync(Batch batch, string fontId) + { + BuildAndSetFontPackageApiCall(batch, fontId).Wait(); + return Task.CompletedTask; + } + + private static ApiCall BuildGetFontPackagesApiCall() + { + return new ApiCall("_api/FontPackages", ApiType.SPORest); + } + + private async Task BuildAndSetFontPackageApiCall(Batch batch, string fontId) + { + var apiCall = new ApiCall($"_api/FontPackages/GetById('{fontId}')/Apply", ApiType.SPORest) + { // The provided JSON is of the minimal odata type + Headers = new Dictionary + { + { "Content-Type", "application/json;odata.metadata=nometadata" }, + } + }; + + await (context.Web as Web).RawRequestBatchAsync(batch, apiCall, HttpMethod.Post, "SetFontPackages").ConfigureAwait(false); + } + + #endregion Branding Center FontPackages + + #region SiteFontPackages + public List GetSiteFontPackages() + { + return GetSiteFontPackagesAsync().GetAwaiter().GetResult(); + } + + public async Task>> GetSiteFontPackagesBatchAsync(Batch batch) + { + ApiCall apiCall = BuildGetSiteFontPackagesApiCall(); + return await GetFontPackagesBatchAsync(batch, apiCall).ConfigureAwait(false); + } + + public IBatchSingleResult> GetSiteFontPackagesBatch(Batch batch) + { + return GetSiteFontPackagesBatchAsync(batch).GetAwaiter().GetResult(); + } + + private static ApiCall BuildGetSiteFontPackagesApiCall() + { + return new ApiCall("_api/SiteFontPackages", ApiType.SPORest); + } + #endregion SiteFontPackages + + private async Task SetFontPackageBatchAsync(Batch batch, ApiCall apiCall) + { + await (context.Web as Web).RawRequestBatchAsync(batch, apiCall, HttpMethod.Post, "SaveMenuState").ConfigureAwait(false); + } + + + internal async Task>> GetFontPackagesBatchAsync(Batch batch, ApiCall apiCall) + { + // Since we're doing a raw batch request the processing of the batch response needs be implemented + apiCall.RawSingleResult = new List(); + apiCall.RawResultsHandler = (json, apiCall) => + { + ProcessGetFontPackagesResponse(json, (List)apiCall.RawSingleResult); + }; + + // Add the request to the batch + var batchRequest = await (context.Web as Web).RawRequestBatchAsync(batch, apiCall, HttpMethod.Get).ConfigureAwait(false); + + // Return the batch result as Enumerable + return new BatchSingleResult>(batch, batchRequest.Id, (List)apiCall.RawSingleResult); + } + + + internal static void ProcessGetFontPackagesResponse(string jsonString, List fontPackageList) + { + var jDoc = JsonSerializer.Deserialize(jsonString); + var results = jDoc.GetProperty("value").ValueKind == JsonValueKind.Null ? "[]" : jDoc.GetProperty("value").GetRawText(); + + var jsonFontPackageList = JsonSerializer.Deserialize>(results); + + foreach (var fontPackage in jsonFontPackageList) + { + fontPackageList.Add(fontPackage); + } + } } } diff --git a/src/sdk/PnP.Core/Model/SharePoint/Branding/Internal/ChromeOptions.cs b/src/sdk/PnP.Core/Model/SharePoint/Branding/Internal/ChromeOptions.cs index f5bc40d244..2e69a43cbc 100644 --- a/src/sdk/PnP.Core/Model/SharePoint/Branding/Internal/ChromeOptions.cs +++ b/src/sdk/PnP.Core/Model/SharePoint/Branding/Internal/ChromeOptions.cs @@ -17,5 +17,7 @@ internal ChromeOptions(PnPContext pnpContext) public IFooterOptions Footer { get; internal set; } + public IFontOptions Font { get; internal set; } + } } diff --git a/src/sdk/PnP.Core/Model/SharePoint/Branding/Internal/Enums/SiteLogoType.cs b/src/sdk/PnP.Core/Model/SharePoint/Branding/Internal/Enums/SiteLogoType.cs index 159e497c06..5e6fa0e47c 100644 --- a/src/sdk/PnP.Core/Model/SharePoint/Branding/Internal/Enums/SiteLogoType.cs +++ b/src/sdk/PnP.Core/Model/SharePoint/Branding/Internal/Enums/SiteLogoType.cs @@ -23,6 +23,11 @@ internal enum SiteLogoType /// /// Global navigation logo /// - GlobalNavLogo = 3 + GlobalNavLogo = 3, + + /// + /// Footer background image + /// + FooterBackground = 4 } } diff --git a/src/sdk/PnP.Core/Model/SharePoint/Branding/Internal/FontOption.cs b/src/sdk/PnP.Core/Model/SharePoint/Branding/Internal/FontOption.cs new file mode 100644 index 0000000000..8a21dc4a35 --- /dev/null +++ b/src/sdk/PnP.Core/Model/SharePoint/Branding/Internal/FontOption.cs @@ -0,0 +1,23 @@ +using System.Text.Json.Serialization; + +namespace PnP.Core.Model.SharePoint +{ + internal sealed class FontOption : IFontOption + { + /// + /// fontFamilyKey + /// + [JsonPropertyName("fontFamilyKey")] + public string FamilyKey { get; set; } + /// + /// fontFace + /// + [JsonPropertyName("fontFace")] + public string Face { get; set; } + /// + /// fontVariantWeight + /// + [JsonPropertyName("fontVariantWeight")] + public string VariantWeight { get; set; } + } +} diff --git a/src/sdk/PnP.Core/Model/SharePoint/Branding/Internal/FontOptions.cs b/src/sdk/PnP.Core/Model/SharePoint/Branding/Internal/FontOptions.cs new file mode 100644 index 0000000000..3c4c63e01f --- /dev/null +++ b/src/sdk/PnP.Core/Model/SharePoint/Branding/Internal/FontOptions.cs @@ -0,0 +1,10 @@ +namespace PnP.Core.Model.SharePoint +{ + internal sealed class FontOptions : IFontOptions + { + public IFontOption SiteTitle { get; set; } = null; + public IFontOption SiteNav { get; set; } = null; + public IFontOption SiteFooterTitle { get; set; } = null; + public IFontOption SiteFooterNav { get; set; } = null; + } +} diff --git a/src/sdk/PnP.Core/Model/SharePoint/Branding/Internal/FontPackage.cs b/src/sdk/PnP.Core/Model/SharePoint/Branding/Internal/FontPackage.cs new file mode 100644 index 0000000000..e49e29f69e --- /dev/null +++ b/src/sdk/PnP.Core/Model/SharePoint/Branding/Internal/FontPackage.cs @@ -0,0 +1,12 @@ +namespace PnP.Core.Model.SharePoint +{ + internal sealed class FontPackage : IFontPackage + { + public string ID { get; set; } + public bool IsHidden { get; set; } + public bool IsValid { get; set; } + public string PackageJson { get; set; } + public int Store { get; set; } + public string Title { get; set; } + } +} diff --git a/src/sdk/PnP.Core/Model/SharePoint/Branding/Internal/FooterOptions.cs b/src/sdk/PnP.Core/Model/SharePoint/Branding/Internal/FooterOptions.cs index 400bbcc79b..ff19a80cab 100644 --- a/src/sdk/PnP.Core/Model/SharePoint/Branding/Internal/FooterOptions.cs +++ b/src/sdk/PnP.Core/Model/SharePoint/Branding/Internal/FooterOptions.cs @@ -2,6 +2,7 @@ using System.IO; using System.Linq; using System.Net.Http; +using System.Text.Json; using System.Threading.Tasks; namespace PnP.Core.Model.SharePoint @@ -25,6 +26,13 @@ internal FooterOptions(PnPContext pnpContext) public string DisplayName { get; set; } + public FooterLinkAlignment LinkAlignment { get; set; } + public OverlayColorType OverlayColor { get; set; } + public int OverlayOpacity { get; set; } + public OverlayGradientDirectionType OverlayGradientDirection { get; set; } + public int ColorIndexInLightMode { get; set; } + public int ColorIndexInDarkMode { get; set; } + public async Task SetLogoAsync(string fileName, Stream content, bool overwrite = false) { // Upload the image @@ -99,5 +107,53 @@ internal MenuStateWrapper GetMenuStateToPersist(string serverRelativeUrl) return menuStateWrapper; } + public async Task SetFooterBackgroundImageAsync(string fileName, Stream content, double focalX = 0, double focalY = 0, bool overwrite = false) + { + // Upload the image + IFile siteLogo = await UploadImageToSiteAssetsAsync(fileName, content, overwrite).ConfigureAwait(false); + // Set the uploaded file as header background + await (PnPContext.Web as Web).RawRequestAsync(BuildSetSiteLogoApiCall(siteLogo.ServerRelativeUrl, SiteLogoType.FooterBackground, SiteLogoAspect.Square, focalX, focalY), HttpMethod.Post, "SetSiteLogo").ConfigureAwait(false); + } + + public void SetFooterBackgroundImage(string fileName, Stream content, double focalX = 0, double focalY = 0, bool overwrite = false) + { + SetFooterBackgroundImageAsync(fileName, content, focalX, focalY, overwrite).GetAwaiter().GetResult(); + } + + public async Task ClearFooterBackgroundImageAsync() + { + await (PnPContext.Web as Web).RawRequestAsync(BuildSetSiteLogoApiCall("", SiteLogoType.FooterBackground, SiteLogoAspect.Square, 0, 0), HttpMethod.Post, "SetSiteLogo").ConfigureAwait(false); + } + + public void ClearFooterBackgroundImage() + { + ClearFooterBackgroundImageAsync().GetAwaiter().GetResult(); + } + + private static ApiCall BuildSetSiteLogoApiCall(string serverRelativeUrl, SiteLogoType type, SiteLogoAspect aspect, double focalX = 0, double focalY = 0) + { + string jsonBody; + if (type == SiteLogoType.FooterBackground) + { + jsonBody = JsonSerializer.Serialize(new + { + relativeLogoUrl = serverRelativeUrl, + type = (int)type, + aspect = (int)aspect, + focalx = focalX, + focaly = focalY + }); + } + else + { + jsonBody = JsonSerializer.Serialize(new + { + relativeLogoUrl = serverRelativeUrl, + type = (int)type, + aspect = (int)aspect + }); + } + return new ApiCall("_api/siteiconmanager/setsitelogo", ApiType.SPORest, jsonBody); + } } } diff --git a/src/sdk/PnP.Core/Model/SharePoint/Branding/Internal/HeaderOptions.cs b/src/sdk/PnP.Core/Model/SharePoint/Branding/Internal/HeaderOptions.cs index 026e9baa82..bb04794f57 100644 --- a/src/sdk/PnP.Core/Model/SharePoint/Branding/Internal/HeaderOptions.cs +++ b/src/sdk/PnP.Core/Model/SharePoint/Branding/Internal/HeaderOptions.cs @@ -25,6 +25,11 @@ internal HeaderOptions(PnPContext pnpContext) public bool HideTitle { get; set; } public LogoAlignment LogoAlignment { get; set; } + public OverlayColorType OverlayColor { get; set; } = OverlayColorType.None; + public int OverlayOpacity { get; set; } = 0; + public OverlayGradientDirectionType OverlayGradientDirection { get; set; } = OverlayGradientDirectionType.TopToBottom; + public int ColorIndexInLightMode { get; set; } = -1; + public int ColorIndexInDarkMode { get; set; } = -1; public async Task SetSiteLogoAsync(string fileName, Stream content, bool overwrite = false) { @@ -145,10 +150,11 @@ public void ResetSiteLogoThumbnail() public async Task SetHeaderBackgroundImageAsync(string fileName, Stream content, double focalX = 0, double focalY = 0, bool overwrite = false) { - if (Layout != HeaderLayoutType.Extended) - { - throw new ClientException(ErrorType.Unsupported, PnPCoreResources.Exception_Unsupported_BackgroundImageHeaderIsNotOfTypeExtended); - } + // => modern Header does allow background images for all layouts + //if (Layout != HeaderLayoutType.Extended) + //{ + // throw new ClientException(ErrorType.Unsupported, PnPCoreResources.Exception_Unsupported_BackgroundImageHeaderIsNotOfTypeExtended); + //} // Upload the image IFile siteLogo = await UploadImageToSiteAssetsAsync(fileName, content, overwrite).ConfigureAwait(false); diff --git a/src/sdk/PnP.Core/Model/SharePoint/Branding/Public/IBrandingManager.cs b/src/sdk/PnP.Core/Model/SharePoint/Branding/Public/IBrandingManager.cs index c0b0e5fa5b..61ec1d41a0 100644 --- a/src/sdk/PnP.Core/Model/SharePoint/Branding/Public/IBrandingManager.cs +++ b/src/sdk/PnP.Core/Model/SharePoint/Branding/Public/IBrandingManager.cs @@ -223,5 +223,142 @@ public interface IBrandingManager /// void SetChromeOptionsBatch(IChromeOptions chromeOptions); #endregion + + #region OutOfBoxFontPackages + + /// + /// Gets the out of the box fonts available + /// + /// Site's + Task> GetOutOfBoxFontPackagesAsync(); + + /// + /// Gets the out of the box fonts available + /// + /// Site's + List GetOutOfBoxFontPackages(); + + /// + /// Gets the out of the box fonts available + /// + /// + /// Site's + Task>> GetOutOfBoxFontPackagesBatchAsync(Batch batch); + + /// + /// Gets the out of the box fonts available + /// + /// Site's + IBatchSingleResult> GetOutOfBoxFontPackagesBatch(Batch batch); + + /// + /// Sets the out of the box font with the given id on the Site + /// + /// + void SetOutOfBoxFontPackage(string fontId); + + /// + /// Sets the out of the box font with the given id on the Site + /// + /// + Task SetOutOfBoxFontPackageAsync(string fontId); + + /// + /// Sets the out of the box font with the given id on the Site + /// + /// + /// + void SetOutOfBoxFontPackageBatch(Batch batch, string fontId); + + /// + /// Sets the out of the box font with the given id on the Site + /// + /// + /// + Task SetOutOfBoxFontPackageBatchAsync(Batch batch, string fontId); + + #endregion OutOfBoxFontPackages + + #region Branding Center FontPackages + + /// + /// Gets the fonts available in branding center + /// + /// Site's + Task> GetFontPackagesAsync(); + + /// + /// Gets the fonts available in branding center + /// + /// Site's + List GetFontPackages(); + + /// + /// Gets the fonts available in branding center + /// + /// Site's + Task>> GetFontPackagesBatchAsync(Batch batch); + + /// + /// Gets the fonts available in branding center + /// + /// Site's + IBatchSingleResult> GetFontPackagesBatch(Batch batch); + + /// + /// Sets the branding center font with the given id on the Site + /// + /// + void SetFontPackage(string fontId); + + /// + /// Sets the branding center font with the given id on the Site + /// + /// + Task SetFontPackageAsync(string fontId); + + /// + /// Sets the branding center font with the given id on the Site + /// + /// + /// + void SetFontPackageBatch(Batch batch, string fontId); + + /// + /// Sets the branding center font with the given id on the Site + /// + /// + /// + Task SetPackageBatchAsync(Batch batch, string fontId); + + #endregion Branding Center FontPackages + + #region SiteFontPackages + + /// + /// Gets the fonts installed on the site + /// + /// Site's + Task> GetSiteFontPackagesAsync(); + + /// + /// Gets the fonts installed on the site + /// + /// Site's + List GetSiteFontPackages(); + + /// + /// Gets the fonts installed on the site + /// + /// Site's + Task>> GetSiteFontPackagesBatchAsync(Batch batch); + + /// + /// Gets the fonts installed on the site + /// + /// Site's + IBatchSingleResult> GetSiteFontPackagesBatch(Batch batch); + + #endregion SiteFontPackages } } diff --git a/src/sdk/PnP.Core/Model/SharePoint/Branding/Public/IChromeOptions.cs b/src/sdk/PnP.Core/Model/SharePoint/Branding/Public/IChromeOptions.cs index c436b31c31..257244d726 100644 --- a/src/sdk/PnP.Core/Model/SharePoint/Branding/Public/IChromeOptions.cs +++ b/src/sdk/PnP.Core/Model/SharePoint/Branding/Public/IChromeOptions.cs @@ -20,5 +20,9 @@ public interface IChromeOptions /// IFooterOptions Footer { get; } + /// + /// Site font chrome configuration + /// + IFontOptions Font { get; } } } diff --git a/src/sdk/PnP.Core/Model/SharePoint/Branding/Public/IFontOption.cs b/src/sdk/PnP.Core/Model/SharePoint/Branding/Public/IFontOption.cs new file mode 100644 index 0000000000..f4c76fca0a --- /dev/null +++ b/src/sdk/PnP.Core/Model/SharePoint/Branding/Public/IFontOption.cs @@ -0,0 +1,28 @@ +using System.Text.Json.Serialization; + +namespace PnP.Core.Model.SharePoint +{ + /// + /// specify font to use for header / footer + /// + public interface IFontOption + { + /// + /// fontFamilyKey + /// + [JsonPropertyName("fontFamilyKey")] + string FamilyKey { get; set; } + + /// + /// fontFace + /// + [JsonPropertyName("fontFace")] + string Face { get; set; } + + /// + /// fontVariantWeight + /// + [JsonPropertyName("fontVariantWeight")] + string VariantWeight { get; set; } + } +} diff --git a/src/sdk/PnP.Core/Model/SharePoint/Branding/Public/IFontOptions.cs b/src/sdk/PnP.Core/Model/SharePoint/Branding/Public/IFontOptions.cs new file mode 100644 index 0000000000..02dd49ac92 --- /dev/null +++ b/src/sdk/PnP.Core/Model/SharePoint/Branding/Public/IFontOptions.cs @@ -0,0 +1,28 @@ +namespace PnP.Core.Model.SharePoint +{ + /// + /// Options to configure a the site font chrome. + /// + public interface IFontOptions + { + /// + /// fontOptionForSiteTitle + /// + IFontOption SiteTitle { get; set; } + + /// + /// fontOptionForSiteNav + /// + IFontOption SiteNav { get; set; } + + /// + /// fontOptionForSiteFooterTitle + /// + IFontOption SiteFooterTitle { get; set; } + + /// + /// fontOptionForSiteFooterNav + /// + IFontOption SiteFooterNav { get; set; } + } +} diff --git a/src/sdk/PnP.Core/Model/SharePoint/Branding/Public/IFontPackage.cs b/src/sdk/PnP.Core/Model/SharePoint/Branding/Public/IFontPackage.cs new file mode 100644 index 0000000000..373462f37c --- /dev/null +++ b/src/sdk/PnP.Core/Model/SharePoint/Branding/Public/IFontPackage.cs @@ -0,0 +1,41 @@ +namespace PnP.Core.Model.SharePoint +{ + /// + /// Returned by + /// /_api/OutOfBoxFontPackages + /// /_api/SiteFontPackages + /// /_api/FontPackages + /// + public interface IFontPackage + { + /// + /// Font Package ID example /_api/OutOfBoxFontPackages/GetById('5f955493-db94-446f-93bf-2c7567861329') + /// + string ID { get; set; } + + /// + /// dont show this font in the font picker + /// + bool IsHidden { get; set; } + + /// + /// IsValid + /// + bool IsValid { get; set; } + + /// + /// json-string containg settings for the font package + /// + string PackageJson { get; set; } + + /// + /// 0 = Branding Center, 1 = out of the box font + /// + int Store { get; set; } + + /// + /// display name of the font package + /// + string Title { get; set; } + } +} diff --git a/src/sdk/PnP.Core/Model/SharePoint/Branding/Public/IFooterOptions.cs b/src/sdk/PnP.Core/Model/SharePoint/Branding/Public/IFooterOptions.cs index c459ac2a50..bf609695f0 100644 --- a/src/sdk/PnP.Core/Model/SharePoint/Branding/Public/IFooterOptions.cs +++ b/src/sdk/PnP.Core/Model/SharePoint/Branding/Public/IFooterOptions.cs @@ -23,6 +23,35 @@ public interface IFooterOptions /// FooterVariantThemeType Emphasis { get; set; } + /// + /// specifies the alignment of links in the footer + /// + FooterLinkAlignment LinkAlignment { get; set; } + + /// + /// Specifies the available overlay color types that can be applied to header or footer. + /// + OverlayColorType OverlayColor { get; set; } + /// + /// Gets or sets the opacity level of the overlay [0-100]. + /// + int OverlayOpacity { get; set; } + + /// + /// Defines the possible directions for an overlay gradient layout. + /// + OverlayGradientDirectionType OverlayGradientDirection { get; set; } + + /// + /// seesm to be alays -1 + /// + int ColorIndexInLightMode { get; set; } + + /// + /// seesm to be alays -1 + /// + int ColorIndexInDarkMode { get; set; } + /// /// The footer display name /// @@ -57,5 +86,40 @@ public interface IFooterOptions /// /// void ClearLogo(); + + + /// + /// Sets the site's footer background image. + /// + /// Name of your image file + /// The contents of the file + /// X axis focal point for the footer image + /// Y axis focal point for the footer image + /// Indicates whether the file should be overwritten if already existing. + /// + Task SetFooterBackgroundImageAsync(string fileName, Stream content, double focalX = 0, double focalY = 0, bool overwrite = false); + + /// + /// Sets the site's footer background image. + /// + /// Name of your image file + /// The contents of the file + /// X axis focal point for the footer image + /// Y axis focal point for the footer image + /// Indicates whether the file should be overwritten if already existing. + /// + void SetFooterBackgroundImage(string fileName, Stream content, double focalX = 0, double focalY = 0, bool overwrite = false); + + /// + /// Clears the footer background image + /// + /// + Task ClearFooterBackgroundImageAsync(); + + /// + /// Clears the footer background image + /// + /// + void ClearFooterBackgroundImage(); } } diff --git a/src/sdk/PnP.Core/Model/SharePoint/Branding/Public/IHeaderOptions.cs b/src/sdk/PnP.Core/Model/SharePoint/Branding/Public/IHeaderOptions.cs index 1cddd86c77..151530216f 100644 --- a/src/sdk/PnP.Core/Model/SharePoint/Branding/Public/IHeaderOptions.cs +++ b/src/sdk/PnP.Core/Model/SharePoint/Branding/Public/IHeaderOptions.cs @@ -28,6 +28,31 @@ public interface IHeaderOptions /// public LogoAlignment LogoAlignment { get; set; } + /// + /// Specifies the available overlay color types that can be applied to header or footer. + /// + public OverlayColorType OverlayColor { get; set; } + + /// + /// Gets or sets the opacity level of the overlay [0-100]. + /// + public int OverlayOpacity { get; set; } + + /// + /// Defines the possible directions for an overlay gradient layout. + /// + public OverlayGradientDirectionType OverlayGradientDirection { get; set; } + + /// + /// seesm to be alays -1 + /// + public int ColorIndexInLightMode { get; set; } + + /// + /// seesm to be alays -1 + /// + public int ColorIndexInDarkMode { get; set; } + /// /// Sets the site's logo to the provided image. For group connected sites calling this method is /// equal to calling SetSiteLogoThumbnail as logo and logo thumbnail are both set the same. diff --git a/src/sdk/PnP.Core/Model/SharePoint/Core/Public/Enums/FooterLinkAlignment.cs b/src/sdk/PnP.Core/Model/SharePoint/Core/Public/Enums/FooterLinkAlignment.cs new file mode 100644 index 0000000000..5508f6f738 --- /dev/null +++ b/src/sdk/PnP.Core/Model/SharePoint/Core/Public/Enums/FooterLinkAlignment.cs @@ -0,0 +1,17 @@ +namespace PnP.Core.Model.SharePoint +{ + /// + /// specifies the alignment of links in the footer + /// + public enum FooterLinkAlignment + { + /// + /// Right alignment ( Value = 0 ) + /// + Right = 0, + /// + /// Left alignment ( Value = 2 ) + /// + Left = 2, + } +} diff --git a/src/sdk/PnP.Core/Model/SharePoint/Core/Public/Enums/OverlayColorType.cs b/src/sdk/PnP.Core/Model/SharePoint/Core/Public/Enums/OverlayColorType.cs new file mode 100644 index 0000000000..c03a740877 --- /dev/null +++ b/src/sdk/PnP.Core/Model/SharePoint/Core/Public/Enums/OverlayColorType.cs @@ -0,0 +1,32 @@ +namespace PnP.Core.Model.SharePoint +{ + /// + /// Specifies the available overlay color types that can be applied to header or footer. + /// + /// This enumeration provides options for selecting predefined overlay colors, including solid + /// colors and gradient styles. The values can be used to customize the appearance of UI elements or graphical + /// overlays. + public enum OverlayColorType + { + /// + /// -1 = not set + /// + None = -1, + /// + /// 0 = white + /// + White = 0, + /// + /// 1 = black + /// + Black = 1, + /// + /// 2 = light gradient + /// + LightGradient = 2, + /// + /// 3 = dark gradient + /// + DarkGradient = 3 + } +} diff --git a/src/sdk/PnP.Core/Model/SharePoint/Core/Public/Enums/OverlayGradientDirectionType.cs b/src/sdk/PnP.Core/Model/SharePoint/Core/Public/Enums/OverlayGradientDirectionType.cs new file mode 100644 index 0000000000..521509f206 --- /dev/null +++ b/src/sdk/PnP.Core/Model/SharePoint/Core/Public/Enums/OverlayGradientDirectionType.cs @@ -0,0 +1,19 @@ +namespace PnP.Core.Model.SharePoint +{ + /// + /// Defines the possible directions for an overlay gradient layout. + /// + /// This enumeration specifies the orientation of the gradient, determining the direction in + /// which the gradient colors are applied. + public enum OverlayGradientDirectionType + { + /// + /// Specifies that the layout order proceeds from top to bottom. + /// + TopToBottom = 0, + /// + /// Specifies that the layout order proceeds from bottom to top. + /// + BottomToTop = 1 + } +}