diff --git a/src/BootstrapBlazor.Server/Components/Layout/BaseLayout.razor b/src/BootstrapBlazor.Server/Components/Layout/BaseLayout.razor
index d31966d483f..dda61a1d6c7 100644
--- a/src/BootstrapBlazor.Server/Components/Layout/BaseLayout.razor
+++ b/src/BootstrapBlazor.Server/Components/Layout/BaseLayout.razor
@@ -15,3 +15,14 @@
Reload
🗙
+
+@code {
+ RenderFragment RenderVote =>
+ @
+
我正在参加 Gitee 2025 最受欢迎的开源软件投票活动,快来给我投票吧!
+
+
;
+}
diff --git a/src/BootstrapBlazor.Server/Components/Layout/BaseLayout.razor.cs b/src/BootstrapBlazor.Server/Components/Layout/BaseLayout.razor.cs
index d089760ff06..d774d70ebfc 100644
--- a/src/BootstrapBlazor.Server/Components/Layout/BaseLayout.razor.cs
+++ b/src/BootstrapBlazor.Server/Components/Layout/BaseLayout.razor.cs
@@ -5,13 +5,14 @@
using Microsoft.Extensions.Options;
using Microsoft.JSInterop;
+using System.Globalization;
namespace BootstrapBlazor.Server.Components.Layout;
///
/// 母版页基类
///
-public partial class BaseLayout : IDisposable
+public partial class BaseLayout : IAsyncDisposable
{
[Inject]
[NotNull]
@@ -50,6 +51,8 @@ public partial class BaseLayout : IDisposable
private string? CancelText { get; set; }
private bool _init = false;
+ private JSModule? _module;
+ private DotNetObjectReference? _interop;
///
///
@@ -71,13 +74,18 @@ protected override void OnInitialized()
///
///
///
- protected override async Task OnInitializedAsync()
+ protected override async Task OnAfterRenderAsync(bool firstRender)
{
- await base.OnInitializedAsync();
+ await base.OnAfterRenderAsync(firstRender);
- var module = await JSRuntime.LoadModule($"{WebsiteOption.Value.JSModuleRootPath}Layout/BaseLayout.razor.js");
- await module.InvokeVoidAsync("initTheme");
- _init = true;
+ if (firstRender)
+ {
+ _module = await JSRuntime.LoadModule($"{WebsiteOption.Value.JSModuleRootPath}Layout/BaseLayout.razor.js");
+ _interop = DotNetObjectReference.Create(this);
+ await _module.InvokeVoidAsync("doTask", _interop);
+ _init = true;
+ StateHasChanged();
+ }
}
private async Task NotifyCommit(DispatchEntry payload)
@@ -121,25 +129,55 @@ private async Task NotifyReboot(DispatchEntry payload)
}
}
+ ///
+ /// 显示投票弹窗
+ ///
+ ///
+ [JSInvokable]
+ public async Task ShowVoteToast()
+ {
+ // 英文环境不投票
+ if(CultureInfo.CurrentUICulture.Name == "en-US")
+ {
+ return;
+ }
+
+ _option = new ToastOption()
+ {
+ Category = ToastCategory.Information,
+ Title = "Gitee 评选活动",
+ IsAutoHide = false,
+ ChildContent = RenderVote,
+ PreventDuplicates = true
+ };
+ await Toast.Show(_option);
+ }
+
///
/// 释放资源
///
///
- private void Dispose(bool disposing)
+ private async ValueTask DisposeAsync(bool disposing)
{
if (disposing)
{
CommitDispatchService.UnSubscribe(NotifyCommit);
RebootDispatchService.UnSubscribe(NotifyReboot);
+
+ if (_module != null)
+ {
+ await _module.InvokeVoidAsync("dispose");
+ await _module.DisposeAsync();
+ }
}
}
///
/// 释放资源
///
- public void Dispose()
+ public async ValueTask DisposeAsync()
{
- Dispose(true);
+ await DisposeAsync(true);
GC.SuppressFinalize(this);
}
}
diff --git a/src/BootstrapBlazor.Server/Components/Layout/BaseLayout.razor.js b/src/BootstrapBlazor.Server/Components/Layout/BaseLayout.razor.js
index 6d4599d796a..f3ec8d6636e 100644
--- a/src/BootstrapBlazor.Server/Components/Layout/BaseLayout.razor.js
+++ b/src/BootstrapBlazor.Server/Components/Layout/BaseLayout.razor.js
@@ -1,6 +1,41 @@
import { getTheme, setTheme } from "../../_content/BootstrapBlazor/modules/utility.js"
+import EventHandler from "../../_content/BootstrapBlazor/modules/event-handler.js"
-export function initTheme() {
+function initTheme() {
const currentTheme = getTheme();
setTheme(currentTheme, false);
}
+
+export function doTask(invoke) {
+ initTheme();
+
+ const v = localStorage.getItem('bb-gitee-vote');
+ if (v) {
+ try {
+ const differ = new Date().getTime() - v;
+ if (differ < 86400000) {
+ return;
+ }
+ }
+ catch {
+ localStorage.removeItem('bb-gitee-vote');
+ }
+ }
+ const handler = setTimeout(async () => {
+ clearTimeout(handler);
+ await invoke.invokeMethodAsync("ShowVoteToast");
+ }, 10000);
+
+ EventHandler.on(document, 'click', '#bb-gitee-vote', e => {
+ const toast = e.delegateTarget.closest('.toast');
+ if (toast) {
+ toast.classList.remove('show');
+
+ localStorage.setItem('bb-gitee-vote', new Date().getTime());
+ }
+ });
+}
+
+export function dispose() {
+ EventHandler.off(document, 'click', '#bb-gitee-vote');
+}