diff --git a/src/BootstrapBlazor.Server/Components/Components/Header.razor b/src/BootstrapBlazor.Server/Components/Components/Header.razor
index baa74c34958..abf04151a31 100644
--- a/src/BootstrapBlazor.Server/Components/Components/Header.razor
+++ b/src/BootstrapBlazor.Server/Components/Components/Header.razor
@@ -20,12 +20,12 @@
@TutorialsText
- @if (CultureInfo.CurrentUICulture.Name == "zh-CN")
+ @* @if (CultureInfo.CurrentUICulture.Name == "zh-CN")
{
主题
- }
+ } *@
diff --git a/src/BootstrapBlazor.Server/Components/Layout/TutorialsNavMenu.razor.cs b/src/BootstrapBlazor.Server/Components/Layout/TutorialsNavMenu.razor.cs
index c92f1019ab0..3235e718788 100644
--- a/src/BootstrapBlazor.Server/Components/Layout/TutorialsNavMenu.razor.cs
+++ b/src/BootstrapBlazor.Server/Components/Layout/TutorialsNavMenu.razor.cs
@@ -110,6 +110,11 @@ protected override async Task OnInitializedAsync()
{
Text = Localizer["OnlineSheet"],
Url = "tutorials/online-sheet",
+ },
+ new()
+ {
+ Text = Localizer["MemorialMode"],
+ Url = "tutorials/memorial",
}
]);
}
diff --git a/src/BootstrapBlazor.Server/Components/Samples/Tutorials/Memorial.razor b/src/BootstrapBlazor.Server/Components/Samples/Tutorials/Memorial.razor
new file mode 100644
index 00000000000..1bcbf7b2dbd
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Samples/Tutorials/Memorial.razor
@@ -0,0 +1,13 @@
+@page "/tutorials/memorial"
+
+
+
+1. 加载 Utlity 工具
+var module = await JSRuntime.LoadUtility();
+
+2. 设置哀悼模式
+await module.InvokeVoidAsync("SetMemorial", true);
+
+3. 全站默认设置追悼模式方法
+更新 App.razor 文档内容如下
+<html lang="en" data-bs-theme='dark' data-bb-theme="memorial">
diff --git a/src/BootstrapBlazor.Server/Components/Samples/Tutorials/Memorial.razor.cs b/src/BootstrapBlazor.Server/Components/Samples/Tutorials/Memorial.razor.cs
new file mode 100644
index 00000000000..1481aca7faa
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Samples/Tutorials/Memorial.razor.cs
@@ -0,0 +1,27 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the Apache 2.0 License
+// See the LICENSE file in the project root for more information.
+// Maintainer: Argo Zhang(argo@live.ca) Website: https://www.blazor.zone
+
+using Microsoft.JSInterop;
+
+namespace BootstrapBlazor.Server.Components.Samples.Tutorials;
+
+///
+/// 追悼模式
+///
+public partial class Memorial
+{
+ [Inject, NotNull]
+ private IJSRuntime? JSRuntime { get; set; }
+
+ private bool _isMemorial = false;
+
+ private async Task OnToggle()
+ {
+ var module = await JSRuntime.LoadUtility();
+
+ _isMemorial = !_isMemorial;
+ await module.SetMemorialModeAsync(_isMemorial);
+ }
+}
diff --git a/src/BootstrapBlazor.Server/Locales/en-US.json b/src/BootstrapBlazor.Server/Locales/en-US.json
index 625906ea3c9..fea96186570 100644
--- a/src/BootstrapBlazor.Server/Locales/en-US.json
+++ b/src/BootstrapBlazor.Server/Locales/en-US.json
@@ -22,7 +22,8 @@
"TranslateSummary": "Translate",
"DrawingSummary": "Drawing",
"AdminSummary": "Admin",
- "OnlineSheet": "UniverSheet"
+ "OnlineSheet": "UniverSheet",
+ "MemorialMode": "Memorial"
},
"BootstrapBlazor.Server.Components.Components.Pre": {
"LoadingText": "Loading ...",
diff --git a/src/BootstrapBlazor.Server/Locales/zh-CN.json b/src/BootstrapBlazor.Server/Locales/zh-CN.json
index a812af54b4a..2959a357d90 100644
--- a/src/BootstrapBlazor.Server/Locales/zh-CN.json
+++ b/src/BootstrapBlazor.Server/Locales/zh-CN.json
@@ -22,7 +22,8 @@
"TranslateSummary": "翻译工具 Translate",
"DrawingSummary": "画图 Drawing",
"AdminSummary": "中台 Admin",
- "OnlineSheet": "在线表格 UniverSheet"
+ "OnlineSheet": "在线表格 UniverSheet",
+ "MemorialMode": "追悼模式"
},
"BootstrapBlazor.Server.Components.Components.Pre": {
"LoadingText": "正在加载 ...",
diff --git a/src/BootstrapBlazor/Extensions/JSModuleExtensions.cs b/src/BootstrapBlazor/Extensions/JSModuleExtensions.cs
index 03276489e54..97f70b823b5 100644
--- a/src/BootstrapBlazor/Extensions/JSModuleExtensions.cs
+++ b/src/BootstrapBlazor/Extensions/JSModuleExtensions.cs
@@ -11,20 +11,20 @@ namespace BootstrapBlazor.Components;
public static class JSModuleExtensions
{
///
- /// 导入 utility js 模块
+ /// Load utility js module
///
- ///
- ///
- /// A ]]> 模块加载器
+ /// The instance
+ /// The version of the module
+ /// A ]]> module loader
public static Task LoadUtility(this IJSRuntime jsRuntime, string? version = null) => LoadModuleByName(jsRuntime, "utility", version);
///
- /// 通过名称导入内置脚本模块
+ /// Load built-in script module by name
///
- ///
- ///
- ///
- /// A ]]> 模块加载器
+ /// The instance
+ /// The name of the module
+ /// The version of the module
+ /// A ]]> module loader
public static Task LoadModuleByName(this IJSRuntime jsRuntime, string moduleName, string? version = null)
{
var fileName = $"./_content/BootstrapBlazor/modules/{moduleName}.js";
@@ -32,12 +32,12 @@ public static Task LoadModuleByName(this IJSRuntime jsRuntime, string
}
///
- /// IJSRuntime 扩展方法 动态加载脚本
+ /// IJSRuntime extension method to dynamically load scripts
///
- ///
- ///
- ///
- /// A ]]> 模块加载器
+ /// The instance
+ /// The file name of the script
+ /// The version of the script
+ /// A ]]> module loader
public static async Task LoadModule(this IJSRuntime jsRuntime, string fileName, string? version = null)
{
if (!string.IsNullOrEmpty(version))
@@ -64,10 +64,10 @@ public static async Task LoadModule(this IJSRuntime jsRuntime, string
}
///
- /// 获得指定类型的加载 Module 名称
+ /// Get the module name of the specified type
///
- ///
- ///
+ /// The type
+ /// The module name
public static string GetTypeModuleName(this Type type)
{
var name = type.Name;
@@ -80,47 +80,47 @@ public static string GetTypeModuleName(this Type type)
}
///
- /// 在新标签页打开指定网址
+ /// Open the specified URL in a new tab
///
- /// 实例
- /// 打开网页地址
- /// 默认 _blank
- /// 默认 null
+ /// instance
+ /// The URL to open
+ /// The target window, default is _blank
+ /// The features of the new window, default is null
/// A that represents the asynchronous invocation operation.
public static ValueTask OpenUrl(this JSModule module, string url, string? target = "_blank", string? features = null) => module.InvokeVoidAsync("openUrl", url, target, features);
///
- /// 动态运行js代码
+ /// Dynamically run js code
///
- /// 实例
- ///
+ /// instance
+ /// The script to run
/// A that represents the asynchronous invocation operation.
public static async ValueTask Eval(this JSModule module, string script) => await module.InvokeVoidAsync("runEval", script);
///
- /// 通过 Eval 动态运行 JavaScript 代码
+ /// Dynamically run JavaScript code via Eval
///
- /// 实例
- ///
+ /// instance
+ /// The script to run
/// A that represents the asynchronous invocation operation.
public static ValueTask Eval(this JSModule module, string script) => module.InvokeAsync("runEval", script);
///
- /// 通过 Function 动态运行 JavaScript 代码
+ /// Dynamically run JavaScript code via Function
///
- /// 实例
- ///
- ///
+ /// instance
+ /// The script to run
+ /// The arguments to pass to the script
/// A that represents the asynchronous invocation operation.
public static ValueTask Function(this JSModule module, string script, params object?[]? args) => module.InvokeVoidAsync("runFunction", script, args);
///
- /// 动态运行js代码
+ /// Dynamically run js code
///
- ///
- /// 实例
- ///
- ///
+ /// The return type
+ /// instance
+ /// The script to run
+ /// The arguments to pass to the script
/// A that represents the asynchronous invocation operation.
public static async ValueTask Function(this JSModule module, string script, params object?[]? args)
{
@@ -133,14 +133,14 @@ public static string GetTypeModuleName(this Type type)
}
///
- /// 获取当前终端是否为移动设备
+ /// Check if the current terminal is a mobile device
///
- /// 实例
+ /// instance
/// A that represents the asynchronous invocation operation.
public static ValueTask IsMobile(this JSModule module) => module.InvokeAsync("isMobile");
///
- /// 获取一个页面上不重复的元素ID
+ /// Get a unique element ID on a page
///
/// An instance of
/// A prefix of type
@@ -148,26 +148,34 @@ public static string GetTypeModuleName(this Type type)
public static ValueTask GenerateId(this JSModule module, string? prefix = null) => module.InvokeAsync("getUID", prefix);
///
- /// 获取一个页面内指定元素 Html 字符串
+ /// Get the HTML string of a specified element on a page
///
/// An instance of
- ///
- ///
+ /// The ID of the element
+ /// The selector of the element
/// Returns a formatted element ID
public static ValueTask GetHtml(this JSModule module, string? id = null, string? selector = null) => module.InvokeAsync("getHtml", new { id, selector });
///
- /// 设置主题方法
+ /// Set the theme method
///
/// An instance of
- /// theme name
+ /// The name of the theme
///
public static ValueTask SetThemeAsync(this JSModule module, string themeName) => module.InvokeVoidAsync("setTheme", themeName, true);
///
- /// 设置主题方法
+ /// Get the theme method
///
/// An instance of
///
public static ValueTask GetThemeAsync(this JSModule module) => module.InvokeAsync("getTheme");
+
+ ///
+ /// Set memorial mode
+ ///
+ /// An instance of
+ /// Whether it is memorial mode
+ ///
+ public static ValueTask SetMemorialModeAsync(this JSModule module, bool isMemorial) => module.InvokeVoidAsync("setMemorialMode", isMemorial);
}
diff --git a/src/BootstrapBlazor/Options/BootstrapBlazorOptions.cs b/src/BootstrapBlazor/Options/BootstrapBlazorOptions.cs
index 139868f135e..5e736586aa4 100644
--- a/src/BootstrapBlazor/Options/BootstrapBlazorOptions.cs
+++ b/src/BootstrapBlazor/Options/BootstrapBlazorOptions.cs
@@ -9,126 +9,131 @@
namespace BootstrapBlazor.Components;
///
-/// 组件全局配置类
+/// Global configuration class for components
///
public class BootstrapBlazorOptions : IOptions
{
///
- /// 获得/设置 Toast 组件 Delay 默认值 默认为 0
+ /// Gets or sets the default delay for the Toast component, default is 0
///
public int ToastDelay { get; set; }
///
- /// 获得/设置 Message 组件 Delay 默认值 默认为 0
+ /// Gets or sets the default delay for the Message component, default is 0
///
public int MessageDelay { get; set; }
///
- /// 获得/设置 Swal 组件 Delay 默认值 默认为 0
+ /// Gets or sets the default delay for the Swal component, default is 0
///
public int SwalDelay { get; set; }
///
- /// 获得/设置 回落默认语言文化 默认为 en 英文
+ /// Gets or sets the fallback default language culture, default is "en" (English)
///
public string FallbackCulture { get; set; } = "en";
///
- /// 获得/设置 Toast 组件全局弹窗默认位置 默认为 null 当设置值后覆盖整站设置
+ /// Gets or sets the default position for the Toast component globally, default is null. When set, it overrides the site-wide setting.
///
public Placement? ToastPlacement { get; set; }
///
- /// 获得/设置 组件内置本地化语言列表 默认为 null
+ /// Gets or sets the list of built-in localization languages for components, default is null
///
public List? SupportedCultures { get; set; }
///
- /// 获得/设置 是否开启全局异常捕获功能 默认为 true
+ /// Gets or sets whether to enable global exception capture functionality, default is true
///
public bool EnableErrorLogger { get; set; } = true;
///
- /// 获得/设置 是否回落到 Fallback 文化 默认为 true
+ /// Gets or sets whether to fall back to the fallback culture, default is true
///
public bool EnableFallbackCulture { get; set; } = true;
///
- /// 获得/设置 是否忽略丢失文化日志信息 默认 null 未设置
+ /// Gets or sets whether to ignore missing culture log information, default is null (not set)
///
- /// 使用 默认值
+ /// Uses the default value of
public bool? IgnoreLocalizerMissing { get; set; }
///
- /// 获得/设置 是否禁用从服务中获取本地化资源 默认 false 未禁用
+ /// Gets or sets whether to disable fetching localization resources from the service, default is false (not disabled)
///
public bool? DisableGetLocalizerFromService { get; set; }
///
- /// 获得/设置 是否禁用获取 类型本地化资源 默认 false 未禁用
+ /// Gets or sets whether to disable fetching localization resources of type , default is false (not disabled)
///
public bool? DisableGetLocalizerFromResourceManager { get; set; }
///
- /// 获得/设置 默认文化信息
+ /// Gets or sets the default culture information
///
- /// 开启多文化时此参数无效
+ /// This parameter is invalid when multi-culture is enabled
public string? DefaultCultureInfo { get; set; }
///
- /// 获得/设置 是否禁用表单内回车自动提交功能 默认 null 未设置
+ /// Gets or sets whether to disable the automatic form submission feature by pressing Enter, default is null (not set)
///
public bool? DisableAutoSubmitFormByEnter { get; set; }
///
- /// 获得/设置 JavaScript 模块脚本版本号 默认为 null
+ /// Gets or sets the JavaScript module script version number, default is null
///
public string? JSModuleVersion { get; set; }
///
- /// 获得/设置 表格设置实例
+ /// Gets or sets the table settings instance
///
public TableSettings TableSettings { get; set; } = new();
///
- /// 获得/设置 配置实例
+ /// Gets or sets the configuration instance
///
public StepSettings StepSettings { get; set; } = new();
///
- /// 获得/设置 配置 默认不为空
+ /// Gets or sets the configuration, default is not null
///
public ConnectionHubOptions ConnectionHubOptions { get; set; } = new();
///
- /// 获得/设置 配置 默认不为空
+ /// Gets or sets the configuration, default is not null
///
public WebClientOptions WebClientOptions { get; set; } = new();
///
- /// 获得/设置 配置 默认不为空
+ /// Gets or sets the configuration, default is not null
///
public IpLocatorOptions IpLocatorOptions { get; set; } = new();
///
- /// 获得/设置 配置 默认不为空
+ /// Gets or sets the configuration, default is not null
///
public ScrollOptions ScrollOptions { get; set; } = new();
///
- /// 获得/设置 配置 默认不为空
+ /// Gets or sets the configuration, default is not null
///
public ContextMenuOptions ContextMenuOptions { get; set; } = new();
///
- /// 获得/设置 CacheManagerOptions 配置 默认不为空
+ /// Gets or sets the CacheManagerOptions configuration, default is not null
///
public CacheManagerOptions CacheManagerOptions { get; set; } = new();
+ ///
+ /// Get or sets website use memorial mode. default is false
+ ///
+ public bool IsMemorialMode { get; set; }
+
BootstrapBlazorOptions IOptions.Value => this;
///
- /// 获得支持多语言集合
+ /// Gets the collection of supported languages
///
///
public IList GetSupportedCultures() => SupportedCultures?.Select(name => new CultureInfo(name)).ToList()
diff --git a/src/BootstrapBlazor/wwwroot/modules/utility.js b/src/BootstrapBlazor/wwwroot/modules/utility.js
index 3f5472e38e7..a8cf06a0271 100644
--- a/src/BootstrapBlazor/wwwroot/modules/utility.js
+++ b/src/BootstrapBlazor/wwwroot/modules/utility.js
@@ -849,6 +849,26 @@ export function calcCenterPosition(el) {
}
}
+export function setMemorialMode(memorial) {
+ const el = document.documentElement;
+ if (memorial) {
+ const theme = el.getAttribute('data-bs-theme');
+ if (theme) {
+ el.setAttribute('data-bs-original-theme', theme);
+ }
+ el.setAttribute('data-bs-theme', 'dark');
+ el.setAttribute('data-bb-theme', 'memorial');
+ }
+ else {
+ const theme = el.getAttribute('data-bs-original-theme');
+ el.removeAttribute('data-bs-theme');
+ el.removeAttribute('data-bb-theme');
+ if (theme) {
+ el.setAttribute('data-bs-theme', theme);
+ }
+ }
+}
+
export {
autoAdd,
autoRemove,
diff --git a/src/BootstrapBlazor/wwwroot/scss/meilisearch.scss b/src/BootstrapBlazor/wwwroot/scss/meilisearch.scss
index 6bbf3337385..f8c937f451f 100644
--- a/src/BootstrapBlazor/wwwroot/scss/meilisearch.scss
+++ b/src/BootstrapBlazor/wwwroot/scss/meilisearch.scss
@@ -1,8 +1,8 @@
.bb-g-search {
--bb-global-search-input-margin-left: .5rem;
- --bb-global-search-border-color: rgba(255,255,255,.5);
- --bb-global-search-color: rgba(255,255,255,.5);
- --bb-global-search-border-hover-color: rgba(255,255,255);
+ --bb-global-search-border-color: rgba(255, 255, 255, .5);
+ --bb-global-search-color: rgba(255, 255, 255, .5);
+ --bb-global-search-border-hover-color: rgba(255, 255, 255);
--bb-global-search-padding: 0.25rem 0.75rem;
--bb-global-search-width: 168px;
display: flex;
diff --git a/src/BootstrapBlazor/wwwroot/scss/root.scss b/src/BootstrapBlazor/wwwroot/scss/root.scss
index 9b94bab5629..a71d9276647 100644
--- a/src/BootstrapBlazor/wwwroot/scss/root.scss
+++ b/src/BootstrapBlazor/wwwroot/scss/root.scss
@@ -58,13 +58,13 @@ a, a:hover, a:focus {
}
.input-group {
- @include direction(right,last);
- @include direction(left,first)
+ @include direction(right, last);
+ @include direction(left, first)
}
.btn-group {
- @include direction(right,last);
- @include direction(left,first)
+ @include direction(right, last);
+ @include direction(left, first)
}
.popover.popover-table-column-toolbox {
@@ -120,42 +120,50 @@ a, a:hover, a:focus {
}
}
+[data-bb-theme='memorial'] {
+ &:root {
+ --bs-body-bg: #000;
+ --bs-body-color: #b5b5c3;
+ filter: grayscale(100%);
+ }
+}
+
body:before {
content: "extraExtraSmall";
display: none;
}
-@media (min-width:375px) {
+@media (min-width: 375px) {
body:before {
content: "extraSmall";
}
}
-@media (min-width:576px) {
+@media (min-width: 576px) {
body:before {
content: "small";
}
}
-@media (min-width:768px) {
+@media (min-width: 768px) {
body:before {
content: "medium";
}
}
-@media (min-width:992px) {
+@media (min-width: 992px) {
body:before {
content: "large";
}
}
-@media (min-width:1200px) {
+@media (min-width: 1200px) {
body:before {
content: "extraLarge";
}
}
-@media (min-width:1400px) {
+@media (min-width: 1400px) {
body:before {
content: "extraExtraLarge";
}
diff --git a/test/UnitTest/Utils/JSModuleTest.cs b/test/UnitTest/Utils/JSModuleTest.cs
index c1588d93de1..936bf43e5f5 100644
--- a/test/UnitTest/Utils/JSModuleTest.cs
+++ b/test/UnitTest/Utils/JSModuleTest.cs
@@ -102,6 +102,14 @@ public async Task JSModule_TaskCanceledException()
await module.InvokeAsync("test");
}
+ [Fact]
+ public async Task JSModule_SetMemorial()
+ {
+ var js = new MockTaskCanceledObjectReference();
+ var module = new JSModule(js);
+ await module.SetMemorialModeAsync(true);
+ }
+
private class MockErrorJSObjectReference : MockJSObjectReference
{
protected override ValueTask DisposeAsyncCore(bool disposing)