From 2849534bb9ff8275c34d92c2ec5d5f7043e1f373 Mon Sep 17 00:00:00 2001 From: maliming Date: Tue, 25 Aug 2026 15:27:41 +0800 Subject: [PATCH] Resolve branding logo urls with the request path base --- .../Branding/UrlHelperBrandingExtensions.cs | 40 +++++++++++++++++++ .../BrandingProviderLogoExtensions.cs | 20 ++++++++++ .../Ui/Branding/DefaultBrandingProvider.cs | 6 ++- .../Abp/Ui/Branding/IBrandingLogoProvider.cs | 18 +++++++++ .../Basic/Components/Brand/Default.cshtml | 3 +- .../Themes/Basic/Layouts/Account.cshtml | 3 +- 6 files changed, 87 insertions(+), 3 deletions(-) create mode 100644 framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Branding/UrlHelperBrandingExtensions.cs create mode 100644 framework/src/Volo.Abp.UI/Volo/Abp/Ui/Branding/BrandingProviderLogoExtensions.cs create mode 100644 framework/src/Volo.Abp.UI/Volo/Abp/Ui/Branding/IBrandingLogoProvider.cs diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Branding/UrlHelperBrandingExtensions.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Branding/UrlHelperBrandingExtensions.cs new file mode 100644 index 0000000000..f652dac543 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Branding/UrlHelperBrandingExtensions.cs @@ -0,0 +1,40 @@ +using System; +using Microsoft.AspNetCore.Mvc; + +namespace Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Branding; + +public static class UrlHelperBrandingExtensions +{ + /// + /// Resolves a branding url of for the current request. + /// "logo.svg", "/logo.svg" and "~/logo.svg" all mean the same application relative url and keep working + /// under a non-root . + /// External urls ("http://", "https://" and "//host/") are returned as they are. + /// Returns null when is null or white space. + /// + public static string? ResolveBrandingUrl(this IUrlHelper urlHelper, string? url) + { + if (url.IsNullOrWhiteSpace()) + { + return null; + } + + if (IsExternalUrl(url!)) + { + return url; + } + + var applicationRelativeUrl = url!.StartsWith("~/", StringComparison.Ordinal) + ? url + : "~/" + url.TrimStart('/'); + + return urlHelper.Content(applicationRelativeUrl); + } + + private static bool IsExternalUrl(string url) + { + return url.StartsWith("http://", StringComparison.OrdinalIgnoreCase) + || url.StartsWith("https://", StringComparison.OrdinalIgnoreCase) + || url.StartsWith("//", StringComparison.Ordinal); + } +} diff --git a/framework/src/Volo.Abp.UI/Volo/Abp/Ui/Branding/BrandingProviderLogoExtensions.cs b/framework/src/Volo.Abp.UI/Volo/Abp/Ui/Branding/BrandingProviderLogoExtensions.cs new file mode 100644 index 0000000000..6661f17c73 --- /dev/null +++ b/framework/src/Volo.Abp.UI/Volo/Abp/Ui/Branding/BrandingProviderLogoExtensions.cs @@ -0,0 +1,20 @@ +namespace Volo.Abp.Ui.Branding; + +public static class BrandingProviderLogoExtensions +{ + /// + /// Returns the compact logo of the branding provider on white background when available; otherwise, null. + /// + public static string? GetLogoIconUrlOrNull(this IBrandingProvider brandingProvider) + { + return (brandingProvider as IBrandingLogoProvider)?.LogoIconUrl; + } + + /// + /// Returns the compact logo of the branding provider on dark background when available; otherwise, null. + /// + public static string? GetLogoIconReverseUrlOrNull(this IBrandingProvider brandingProvider) + { + return (brandingProvider as IBrandingLogoProvider)?.LogoIconReverseUrl; + } +} diff --git a/framework/src/Volo.Abp.UI/Volo/Abp/Ui/Branding/DefaultBrandingProvider.cs b/framework/src/Volo.Abp.UI/Volo/Abp/Ui/Branding/DefaultBrandingProvider.cs index fcb1a7545e..aa386c593e 100644 --- a/framework/src/Volo.Abp.UI/Volo/Abp/Ui/Branding/DefaultBrandingProvider.cs +++ b/framework/src/Volo.Abp.UI/Volo/Abp/Ui/Branding/DefaultBrandingProvider.cs @@ -2,11 +2,15 @@ namespace Volo.Abp.Ui.Branding; -public class DefaultBrandingProvider : IBrandingProvider, ITransientDependency +public class DefaultBrandingProvider : IBrandingProvider, IBrandingLogoProvider, ITransientDependency { public virtual string AppName => "MyApplication"; public virtual string? LogoUrl => null; public virtual string? LogoReverseUrl => null; + + public virtual string? LogoIconUrl => null; + + public virtual string? LogoIconReverseUrl => null; } diff --git a/framework/src/Volo.Abp.UI/Volo/Abp/Ui/Branding/IBrandingLogoProvider.cs b/framework/src/Volo.Abp.UI/Volo/Abp/Ui/Branding/IBrandingLogoProvider.cs new file mode 100644 index 0000000000..4cb38cd3a8 --- /dev/null +++ b/framework/src/Volo.Abp.UI/Volo/Abp/Ui/Branding/IBrandingLogoProvider.cs @@ -0,0 +1,18 @@ +namespace Volo.Abp.Ui.Branding; + +/// +/// Optionally implemented by an to provide a compact logo, +/// used where the full logo does not fit, like a collapsed menu. +/// +public interface IBrandingLogoProvider +{ + /// + /// Compact logo on white background + /// + string? LogoIconUrl { get; } + + /// + /// Compact logo on dark background + /// + string? LogoIconReverseUrl { get; } +} diff --git a/modules/basic-theme/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Components/Brand/Default.cshtml b/modules/basic-theme/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Components/Brand/Default.cshtml index 04a4f81c71..fb15426730 100644 --- a/modules/basic-theme/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Components/Brand/Default.cshtml +++ b/modules/basic-theme/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Components/Brand/Default.cshtml @@ -1,9 +1,10 @@ @using Volo.Abp.Ui.Branding +@using Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Branding @inject IBrandingProvider BrandingProvider @if (!BrandingProvider.LogoUrl.IsNullOrWhiteSpace()) { - @BrandingProvider.AppName + @BrandingProvider.AppName } @BrandingProvider.AppName diff --git a/modules/basic-theme/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Layouts/Account.cshtml b/modules/basic-theme/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Layouts/Account.cshtml index 5dc1619ec8..75c57ec834 100644 --- a/modules/basic-theme/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Layouts/Account.cshtml +++ b/modules/basic-theme/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Layouts/Account.cshtml @@ -12,6 +12,7 @@ @using Volo.Abp.MultiTenancy @using Volo.Abp.Localization @using Volo.Abp.Ui.Branding +@using Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Branding @using Volo.Abp.Ui.LayoutHooks @inject IBrandingProvider BrandingProvider @inject IOptions MultiTenancyOptions @@ -64,7 +65,7 @@
- +

@BrandingProvider.AppName

@if (MultiTenancyOptions.Value.IsEnabled &&