mirror of
https://gitee.com/blazorcomponent/MASA.Blazor.git
synced 2025-12-06 10:19:23 +08:00
feat(docs): add koala-chat widget (#2482)
* 🆕 feat(docs): add koala-chat widget
* add v1.10.0 notification
This commit is contained in:
@@ -57,5 +57,16 @@
|
||||
"href": "/blazor/getting-started/release-notes?v=v1.9.0",
|
||||
"upgradeGuide": "/blazor/getting-started/upgrade-guide#upgrading-from-v1-8-x-to-v1-9-0",
|
||||
"createdAt": "2025-04-07"
|
||||
},
|
||||
{
|
||||
"title": "v1.10.0",
|
||||
"content": {
|
||||
"en": "Highlights:\r\n- [Theming](/blazor/features/theme#specification) System Upgrade: To support multiple themes, the theming system has been adapted to the core color specification of Material Design 3 (MD3) and now fully utilizes CSS variables. This simplifies the process of theme customization and switching. Additionally, the default theme color has been updated to align with brand visuals, and a \"memorial mode\" toggle has been added.\r\n- **Dependency Optimization**: To reduce the main library size, mobile-only components, as well as components like Swiper, Gridstack, MarkdownIt, SyntaxHighlight, and Xgplayer, have been migrated to separate packages.\r\n- **PageStack Feature Enhancement**: Optimized the UI transition animations for page stack push and pop operations. Added the [PageStackTab](/blazor/mobiles/page-stack#ppagestacktab) component to improve tab navigation behavior, with added refresh and badge functionalities.\r\n- [Combobox](/blazor/components/combobox): An Autocomplete-like component that allows users to input and submit custom content.\r\n- [EmptyState](/blazor/components/empty-states): Used to display scenarios of an empty list or no search results.",
|
||||
"zh": "亮点:\r\n- [主题](/blazor/features/theme#specification)系统升级:为支持多主题,主题系统已适配Material Design 3 (MD3) 的核心颜色规范,并全面采用CSS变量。此举简化了主题定制与切换流程。此外,默认主题色已更新,以符合品牌视觉,并新增了“追悼模式”切换功能。\r\n- **依赖项优化**:为减小主库体积,仅用于移动端的组件以及Swiper、Gridstack、MarkdownIt、SyntaxHighlight、Xgplayer等组件均已迁移至独立的包。\r\n- **PageStack功能增强**:优化了页面堆栈的出入栈UI过渡动画。新增[PageStackTab组件](/blazor/mobiles/page-stack#ppagestacktab),用于改善标签页的导航行为,并添加了刷新和徽章功能。\r\n- [Combobox](/blazor/components/combobox):一个功能类似于Autocomplete的组件,允许用户输入并提交自定义内容。\r\n- [EmptyState](/blazor/components/empty-states):用于展示列表空状态或搜索无结果的场景。"
|
||||
},
|
||||
"type": 0,
|
||||
"href": "/blazor/getting-started/release-notes?v=v1.10.0",
|
||||
"upgradeGuide": "/blazor/getting-started/upgrade-guide#upgrading-from-v1-9-x-to-v1-10-0",
|
||||
"createdAt": "2025-07-07"
|
||||
}
|
||||
]
|
||||
@@ -113,66 +113,68 @@ The `a` tag has an unavoidable problem: continuous clicks will cause multiple tr
|
||||
|
||||
### PPageStackTab {released-on=v1.10.0}
|
||||
|
||||
**PPageStackTab** component provides two features:
|
||||
**PPageStackTab** component provides three features:
|
||||
|
||||
- The default `a` tag or component navigation behavior adds a record to the browser history, which increases the history when switching tabs.
|
||||
In a MAUI Blazor Hybrid app, it is challenging to implement the back button on the tab page to exit the application.
|
||||
Wrapping the `a` tag or component with the **PPageStackTab** component changes the default navigation behavior to replace the current page with the `replace` method, thus not increasing the history.
|
||||
1. The default `a` tag or component navigation behavior adds a record to the browser history, which increases the history when switching tabs.
|
||||
In a MAUI Blazor Hybrid app, it is challenging to implement the back button on the tab page to exit the application.
|
||||
Wrapping the `a` tag or component with the **PPageStackTab** component changes the default navigation behavior to replace the current page with the `replace` method, thus not increasing the history.
|
||||
|
||||
```razor PageStackLayout.razor
|
||||
@using Masa.Blazor.Presets.PageStack
|
||||
|
||||
<PPageStackTab href="/tab-1" TabRule="@TabRule1">
|
||||
<MButton @attributes="@context.Attrs">Stack page</MButton>
|
||||
</PPageStackTab>
|
||||
|
||||
@code {
|
||||
internal static TabRule TabRule1 = new("/tab-1$");
|
||||
}
|
||||
```
|
||||
```razor PageStackLayout.razor
|
||||
@using Masa.Blazor.Presets.PageStack
|
||||
|
||||
<PPageStackTab href="/tab-1" TabRule="@TabRule1">
|
||||
<MButton @attributes="@context.Attrs">Stack page</MButton>
|
||||
</PPageStackTab>
|
||||
|
||||
@code {
|
||||
internal static TabRule TabRule1 = new("/tab-1$");
|
||||
}
|
||||
```
|
||||
|
||||
- When the activated tab is clicked again, it will trigger the `TabRefreshRequested` event. When used with the [Pull to refresh component](/blazor/mobiles/pull-refresh), it can achieve a pull-to-refresh effect.
|
||||
2. When the activated tab is clicked again, it will trigger the `TabRefreshRequested` event. When used with the [Pull to refresh component](/blazor/mobiles/pull-refresh), it can achieve a pull-to-refresh effect.
|
||||
|
||||
```razor Tab1.razor
|
||||
@using Masa.Blazor.Presets.PageStack.NavController
|
||||
@inject PageStackNavController NavController
|
||||
@implements IDisposable
|
||||
|
||||
<MPullRefresh @ref="_pullRefresh" OnRefresh="...">
|
||||
...
|
||||
</MPullRefresh>
|
||||
|
||||
@code {
|
||||
private MPullRefresh? _pullRefresh;
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
base.OnInitialized();
|
||||
|
||||
NavController.TabRefreshRequested += NavControllerOnTabRefreshRequested;
|
||||
}
|
||||
|
||||
private async void NavControllerOnTabRefreshRequested(object? sender, PageStackTabRefreshRequestedEventArgs e)
|
||||
{
|
||||
if (_pullRefresh is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.TargetTab != PageStackLayout.TabRule1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
await _pullRefresh.SimulateRefreshAsync();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
NavController.TabRefreshRequested -= NavControllerOnTabRefreshRequested;
|
||||
}
|
||||
}
|
||||
```
|
||||
```razor Tab1.razor
|
||||
@using Masa.Blazor.Presets.PageStack.NavController
|
||||
@inject PageStackNavController NavController
|
||||
@implements IDisposable
|
||||
|
||||
<MPullRefresh @ref="_pullRefresh" OnRefresh="...">
|
||||
...
|
||||
</MPullRefresh>
|
||||
|
||||
@code {
|
||||
private MPullRefresh? _pullRefresh;
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
base.OnInitialized();
|
||||
|
||||
NavController.TabRefreshRequested += NavControllerOnTabRefreshRequested;
|
||||
}
|
||||
|
||||
private async void NavControllerOnTabRefreshRequested(object? sender, PageStackTabRefreshRequestedEventArgs e)
|
||||
{
|
||||
if (_pullRefresh is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.TargetTab != PageStackLayout.TabRule1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
await _pullRefresh.SimulateRefreshAsync();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
NavController.TabRefreshRequested -= NavControllerOnTabRefreshRequested;
|
||||
}
|
||||
}
|
||||
```
|
||||
3. The `InitialBadge` property can set the initial badge, usually used for new message notifications.
|
||||
The injected **PageStackNavController** provides `RequestTabBadgeUpdate` and `RequestTabBadgeClear` events to update or clear the badge.
|
||||
|
||||
### PStackPageBar {released-on=v1.10.0}
|
||||
|
||||
|
||||
@@ -111,66 +111,68 @@ builder.Services
|
||||
|
||||
### PPageStackTab {released-on=v1.10.0}
|
||||
|
||||
**PPageStackTab** 组件提供两个功能:
|
||||
**PPageStackTab** 组件提供三个功能:
|
||||
|
||||
- 默认的 `a` 标签或组件的导航行为会往浏览器历史记录中添加一条记录,标签页切换时会导致历史记录的增加。
|
||||
在 MAUI Blazor Hybrid app 上想实现在标签页上点击返回按钮退出应用程序就比较麻烦。
|
||||
使用 **PPageStackTab** 组件包裹 `a` 标签或组件,会将默认导航行为改为 `replace` 方法替换当前页面,从而不会增加历史记录。
|
||||
1. 默认的 `a` 标签或组件的导航行为会往浏览器历史记录中添加一条记录,标签页切换时会导致历史记录的增加。
|
||||
在 MAUI Blazor Hybrid app 上想实现在标签页上点击返回按钮退出应用程序就比较麻烦。
|
||||
使用 **PPageStackTab** 组件包裹 `a` 标签或组件,会将默认导航行为改为 `replace` 方法替换当前页面,从而不会增加历史记录。
|
||||
|
||||
```razor PageStackLayout.razor
|
||||
@using Masa.Blazor.Presets.PageStack
|
||||
|
||||
<PPageStackTab href="/tab-1" TabRule="@TabRule1">
|
||||
<MButton @attributes="@context.Attrs">Stack page</MButton>
|
||||
</PPageStackTab>
|
||||
|
||||
@code {
|
||||
internal static TabRule TabRule1 = new("/tab-1$");
|
||||
}
|
||||
```
|
||||
```razor PageStackLayout.razor
|
||||
@using Masa.Blazor.Presets.PageStack
|
||||
|
||||
<PPageStackTab href="/tab-1" TabRule="@TabRule1">
|
||||
<MButton @attributes="@context.Attrs">Stack page</MButton>
|
||||
</PPageStackTab>
|
||||
|
||||
@code {
|
||||
internal static TabRule TabRule1 = new("/tab-1$");
|
||||
}
|
||||
```
|
||||
|
||||
- 在激活标签页下再次点击导航链接时,会触发 `TabRefreshRequested` 事件,配合 [下拉刷新组件](/blazor/mobiles/pull-refresh) 使用,可以实现下拉刷新的效果。
|
||||
2. 在激活标签页下再次点击导航链接时,会触发 `TabRefreshRequested` 事件,配合 [下拉刷新组件](/blazor/mobiles/pull-refresh) 使用,可以实现下拉刷新的效果。
|
||||
|
||||
```razor Tab1.razor
|
||||
@using Masa.Blazor.Presets.PageStack.NavController
|
||||
@inject PageStackNavController NavController
|
||||
@implements IDisposable
|
||||
|
||||
<MPullRefresh @ref="_pullRefresh" OnRefresh="...">
|
||||
...
|
||||
</MPullRefresh>
|
||||
|
||||
@code {
|
||||
private MPullRefresh? _pullRefresh;
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
base.OnInitialized();
|
||||
|
||||
NavController.TabRefreshRequested += NavControllerOnTabRefreshRequested;
|
||||
}
|
||||
|
||||
private async void NavControllerOnTabRefreshRequested(object? sender, PageStackTabRefreshRequestedEventArgs e)
|
||||
{
|
||||
if (_pullRefresh is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.TargetTab != PageStackLayout.TabRule1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
await _pullRefresh.SimulateRefreshAsync();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
NavController.TabRefreshRequested -= NavControllerOnTabRefreshRequested;
|
||||
}
|
||||
}
|
||||
```
|
||||
```razor Tab1.razor
|
||||
@using Masa.Blazor.Presets.PageStack.NavController
|
||||
@inject PageStackNavController NavController
|
||||
@implements IDisposable
|
||||
|
||||
<MPullRefresh @ref="_pullRefresh" OnRefresh="...">
|
||||
...
|
||||
</MPullRefresh>
|
||||
|
||||
@code {
|
||||
private MPullRefresh? _pullRefresh;
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
base.OnInitialized();
|
||||
|
||||
NavController.TabRefreshRequested += NavControllerOnTabRefreshRequested;
|
||||
}
|
||||
|
||||
private async void NavControllerOnTabRefreshRequested(object? sender, PageStackTabRefreshRequestedEventArgs e)
|
||||
{
|
||||
if (_pullRefresh is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.TargetTab != PageStackLayout.TabRule1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
await _pullRefresh.SimulateRefreshAsync();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
NavController.TabRefreshRequested -= NavControllerOnTabRefreshRequested;
|
||||
}
|
||||
}
|
||||
```
|
||||
3. 通过 `InitialBadge` 属性可以设置初始的徽章,通常用于新消息通知。
|
||||
通过注入的 **PageStackNavController** 的 `RequestTabBadgeUpdate` 和 `RequestTabBadgeClear` 事件可以更新或清除徽章。
|
||||
|
||||
### PStackPageBar {released-on=v1.10.0}
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ public class AppService
|
||||
if (project == "blazor")
|
||||
{
|
||||
list.Add(new("getting-started", "/blazor/getting-started/installation", "/blazor/getting-started"));
|
||||
list.Add(new("ui-components", "/blazor/components/all", "/blazor/components"));
|
||||
list.Add(new("ui-components", "/blazor/components/application", "/blazor/[components|mobiles]"));
|
||||
}
|
||||
|
||||
list.Add(new("annual-service", "/annual-service", "pricing", "red"));
|
||||
|
||||
@@ -78,6 +78,21 @@
|
||||
<script src="https://cdn.masastack.com/npm/monaco-editor/0.34.1/min/vs/loader.js"></script>
|
||||
<script src="https://cdn.masastack.com/npm/monaco-editor/0.34.1/min/vs/editor/editor.main.nls.js"></script>
|
||||
<script src="https://cdn.masastack.com/npm/monaco-editor/0.34.1/min/vs/editor/editor.main.js"></script>
|
||||
<script src="https://opendeep.wiki/koala-chat-widget.js"></script>
|
||||
<script>
|
||||
KoalaChatWidget.init({
|
||||
appId: 'app_mcn5ubhc_z8w4uj',
|
||||
title: 'masa-blazor-chat',
|
||||
theme: 'light', // 或 'dark'
|
||||
// 其他可选配置...
|
||||
onError: (error) => {
|
||||
console.error('Chat widget error:', error);
|
||||
},
|
||||
onValidationFailed: (domain) => {
|
||||
console.error('Domain validation failed:', domain);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<script>
|
||||
Blazor.start().then(function () {
|
||||
Quill.register('modules/blotFormatter', QuillBlotFormatter.default);
|
||||
|
||||
@@ -17,6 +17,7 @@ public partial class BaseLayout
|
||||
|
||||
internal Action? OnAppBarNavIconClick { get; set; }
|
||||
internal Config? Config { get; set; }
|
||||
internal string? Project => _project;
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
@inherits LayoutComponentBase
|
||||
@implements IAsyncDisposable
|
||||
@using Masa.Blazor.Extensions
|
||||
@inject I18n I18n
|
||||
|
||||
<NavDrawer @bind-Value="_showDrawer"
|
||||
RTL="MasaBlazor.RTL"
|
||||
@@ -19,14 +20,29 @@
|
||||
ActiveItem="@context.ActiveTarget"/>
|
||||
</MScrollToTarget>
|
||||
|
||||
<MButton Show="@(BaseLayout.Project == "blazor")"
|
||||
Large
|
||||
Fab
|
||||
Fixed
|
||||
Bottom
|
||||
Right
|
||||
Class="transition-swing"
|
||||
Color="accent"
|
||||
OnClick="@OpenAIAssistantAsync">
|
||||
<MIcon>mdi-assistant</MIcon>
|
||||
<MTooltip Activator="parent" Left>
|
||||
<ChildContent>@I18n.T("ai-assistant")</ChildContent>
|
||||
</MTooltip>
|
||||
</MButton>
|
||||
|
||||
<FabTransition>
|
||||
<MButton Show="_showBackTop"
|
||||
Large
|
||||
Fab
|
||||
Fixed
|
||||
Bottom
|
||||
Right
|
||||
Class="transition-swing"
|
||||
Style="bottom: 96px"
|
||||
Color="primary"
|
||||
OnClick="@ToTopAsync">
|
||||
<MIcon>mdi-chevron-up</MIcon>
|
||||
@@ -84,6 +100,11 @@
|
||||
await Js.InvokeVoidAsync("backTop");
|
||||
}
|
||||
|
||||
private async Task OpenAIAssistantAsync()
|
||||
{
|
||||
await Js.InvokeVoidAsync("openAIAssistant");
|
||||
}
|
||||
|
||||
public async ValueTask DisposeAsync()
|
||||
{
|
||||
try
|
||||
|
||||
@@ -641,4 +641,8 @@ app-alert p {
|
||||
.theme--light .typed-list-header {
|
||||
background-color: rgba(var(--m-theme-surface));
|
||||
color: rgba(var(--m-theme-on-surface));
|
||||
}
|
||||
|
||||
.koala-floating-button {
|
||||
display: none !important;
|
||||
}
|
||||
@@ -126,3 +126,12 @@ window.addDocSearch = function (index, currentLanguage, placeholder) {
|
||||
window.isDarkPreferColor = function() {
|
||||
return window.matchMedia('(prefers-color-scheme: dark)').matches
|
||||
}
|
||||
|
||||
window.openAIAssistant = function() {
|
||||
const el = document.querySelector(".koala-floating-button");
|
||||
if (el) {
|
||||
el.click();
|
||||
} else {
|
||||
console.warn("Koala floating button not found.");
|
||||
}
|
||||
}
|
||||
@@ -566,6 +566,7 @@
|
||||
"misc": "Miscellaneous"
|
||||
},
|
||||
"nav-component-group-by-type": "Grouped by type",
|
||||
"nav-component-group-by-type-desc": "Group the components in the left navigation by type"
|
||||
"nav-component-group-by-type-desc": "Group the components in the left navigation by type",
|
||||
"ai-assistant": "AI Assistant"
|
||||
}
|
||||
|
||||
|
||||
@@ -655,5 +655,6 @@
|
||||
"misc": "其他"
|
||||
},
|
||||
"nav-component-group-by-type": "按类型分组",
|
||||
"nav-component-group-by-type-desc": "左侧导航的组件列表按类型分组"
|
||||
"nav-component-group-by-type-desc": "左侧导航的组件列表按类型分组",
|
||||
"ai-assistant": "AI 助手"
|
||||
}
|
||||
@@ -145,6 +145,21 @@
|
||||
<script src="https://cdn.masastack.com/npm/monaco-editor/0.34.1/min/vs/loader.js"></script>
|
||||
<script src="https://cdn.masastack.com/npm/monaco-editor/0.34.1/min/vs/editor/editor.main.nls.js"></script>
|
||||
<script src="https://cdn.masastack.com/npm/monaco-editor/0.34.1/min/vs/editor/editor.main.js"></script>
|
||||
<script src="https://opendeep.wiki/koala-chat-widget.js"></script>
|
||||
<script>
|
||||
KoalaChatWidget.init({
|
||||
appId: 'app_mcn5ubhc_z8w4uj',
|
||||
title: 'masa-blazor-chat',
|
||||
theme: 'light', // 或 'dark'
|
||||
// 其他可选配置...
|
||||
onError: (error) => {
|
||||
console.error('Chat widget error:', error);
|
||||
},
|
||||
onValidationFailed: (domain) => {
|
||||
console.error('Domain validation failed:', domain);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<script type="module">
|
||||
import { BrotliDecode } from './js/decode.min.js';
|
||||
Blazor.start({
|
||||
|
||||
Reference in New Issue
Block a user