From 55957c39a981f44a70a933239bd565a5b8bd0420 Mon Sep 17 00:00:00 2001
From: Argo Zhang
Date: Fri, 17 Nov 2023 10:24:58 +0800
Subject: [PATCH] doc(Website): use web app template (#2386)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* refactor: 更新 App/Routes 组件
* chore: 更新 Program 文件
* refactor: 临时取消登录集成
* refactor: 增加 MVC 路由表
* chore: 更新路由配置
* chore: 合并工程
* refactor: 修改命名空间
* chore: 更新 nginx 配置文件
* chore: remove dist folder
* doc: 更正单词拼写错误
* chore: 更新解决方案
* refactor: 更新命名空间
* chore: 更新命名空间
* chore: 更新命名空间
* chore: 整理命名空间
* chore: 更新命名空间
* chore: 更正脚本路径
* chore: 精简依赖
* refactor: 禁用授权
* refactor: 移除渲染方式
* refactor: 更改为服务器端渲染模式
* chore: 更新字典
* doc: 重构代码
* refactor: 增加 BootstrapBlazorRoot 组件
* doc: 更新 responsive 脚本
---------
Co-authored-by: zhangpeihang <948869991@qq.com>
---
BootstrapBlazor.sln | 15 -
BootstrapBlazor.slnf | 1 -
dist/.gitattributes | 63 -
dist/.nojekyll | 0
dist/.spa | 2 -
dist/404.html | 40 -
dist/gitee-pages/404.html | 72 -
exclusion.dic | 5 +
scripts/linux/nginx.conf | 13 +
src/BootstrapBlazor.Server/AIChat/Chats.razor | 2 +-
.../BootstrapBlazor.Server.csproj | 60 +-
.../Components/AttributeTable.razor | 13 +
.../Components/AttributeTable.razor.cs | 37 +
.../Components/Components/BBLogo.razor | 1 +
.../Components/Components/BBLogo.razor.css | 8 +
.../Components/BlazorReconnector.razor | 78 +
.../Components/Components/CSS.razor | 4 +
.../Components/Components/CSS.razor.cs | 17 +
.../Components/CalendarCrewCell.razor | 12 +
.../Components/CalendarCrewCell.razor.cs | 56 +
.../Components/CalendarCrewCell.razor.css | 3 +
.../Components/CalendarCrewDialogBody.razor | 19 +
.../CalendarCrewDialogBody.razor.cs | 32 +
.../CalendarCrewDialogBody.razor.css | 35 +
.../Components/Components/CommitItem.razor | 7 +
.../Components/Components/CommitItem.razor.cs | 49 +
.../Components/Components/ComponentCard.razor | 8 +
.../Components/ComponentCard.razor.cs | 60 +
.../Components/ComponentCategory.razor | 21 +
.../Components/ComponentCategory.razor.cs | 55 +
.../Components/ComponentCategory.razor.css | 46 +
.../Components/ContextMenuList.razor | 16 +
.../Components/Components/Counter.razor | 14 +
.../Components/CultureChooser.razor | 13 +
.../Components/CultureChooser.razor.cs | 98 +
.../Components/CultureChooser.razor.css | 18 +
.../Components/CustomerFilter.razor | 50 +
.../Components/CustomerSelectDialog.razor | 8 +
.../Components/CustomerSelectDialog.razor.cs | 50 +
.../Components/DataDialogComponent.razor | 77 +
.../Components/Components/DemoBlock.razor | 29 +
.../Components/Components/DemoBlock.razor.cs | 75 +
.../Components/Components/DemoBlock.razor.css | 116 +
.../Components/Components/DemoComponent.razor | 6 +
.../Components/Components/DemoTabItem.razor | 3 +
.../Components/DemoTabItem.razor.cs | 29 +
.../Components/DemoTabItemSetText.razor | 3 +
.../Components/DemoTabItemSetText.razor.cs | 24 +
.../Components/DemoTableEditTemplate.razor | 28 +
.../Components/Components/DialogBodyFoo.razor | 1 +
.../Components/DialogBodyFoo.razor.cs | 29 +
.../Components/Components/DialogDemo.razor | 16 +
.../Components/Components/DialogDemo.razor.cs | 26 +
.../Components/DialogHeaderFoo.razor | 4 +
.../Components/DialogHeaderFoo.razor.cs | 49 +
.../Components/DialogSaveDetail.razor | 17 +
.../Components/Components/ErrorCounter.razor | 14 +
.../Components/Components/EventTable.razor | 17 +
.../Components/Components/FetchData.razor | 47 +
.../Components/Components/FooSearch.razor | 14 +
.../Components/Components/FooSearch.razor.cs | 35 +
.../Components/FormInlineSwitch.razor | 1 +
.../Components/FormInlineSwitch.razor.cs | 61 +
.../Components/Components/GlobalSearch.razor | 3 +
.../Components/GlobalSearch.razor.cs | 57 +
.../Components/Components/Header.razor | 44 +
.../Components/Components/Header.razor.cs | 48 +
.../Components/Components/Header.razor.css | 68 +
.../Components/Components/Header.razor.js | 20 +
.../Components/InstallContent.razor | 90 +
.../Components/InstallContent.razor.cs | 67 +
.../Components/Components/MethodTable.razor | 13 +
.../Components/MethodTable.razor.cs | 38 +
.../Components/Components/PackageTips.razor | 36 +
.../Components/Components/Pre.razor | 21 +
.../Components/Components/Pre.razor.cs | 191 +
.../Components/Components/Pre.razor.css | 48 +
.../Components/Components/Pre.razor.js | 88 +
.../Components/Components/QQGroup.razor | 17 +
.../Components/ResultDialogDemo.razor | 8 +
.../Components/ResultDialogDemo.razor.cs | 37 +
.../Components/ResultDialogDemo2.razor | 7 +
.../Components/ResultDialogDemo2.razor.cs | 138 +
.../Components/ShownCallbackDummy.razor | 36 +
.../Components/Components/State.razor | 18 +
.../Components/Components/State.razor.cs | 29 +
.../Components/Components/SwalFooter.razor | 1 +
.../Components/Components/ThemeChooser.razor | 18 +
.../Components/ThemeChooser.razor.cs | 74 +
.../Components/ThemeChooser.razor.css | 63 +
.../Components/ThemeChooser.razor.js | 49 +
.../Components/Components/Tips.razor | 28 +
.../Components/Components/UpdateIntro.razor | 28 +
.../Components/UpdateIntro.razor.cs | 35 +
.../Components/UpdateIntro.razor.css | 68 +
.../Components/UpdateIntro.razor.js | 56 +
.../Components/Components/Video.razor | 42 +
.../Components/WebSiteModuleComponentBase.cs | 21 +
.../Components/Components/Widget.razor | 75 +
.../Components/Components/WinButton.razor | 9 +
.../Components/Components/Wwads.razor | 4 +
.../Components/Components/Wwads.razor.cs | 25 +
.../Components/Components/Wwads.razor.js | 15 +
.../Components/Layout/BaseLayout.razor | 15 +
.../Components/Layout/BaseLayout.razor.cs | 104 +
.../Components/Layout/BaseLayout.razor.css | 49 +
.../Components/Layout/ComponentLayout.razor | 50 +
.../Layout/ComponentLayout.razor.cs | 155 +
.../Layout/ComponentLayout.razor.css | 56 +
.../Layout/ComponentLayout.razor.js | 18 +
.../Components/Layout/DockLayout.razor | 6 +
.../Components/Layout/DockLayout.razor.cs | 75 +
.../Components/Layout/DockLayout.razor.css | 9 +
.../Components/Layout/DockLayout.razor.js | 15 +
.../Components/Layout/HomeLayout.razor | 204 +
.../Components/Layout/HomeLayout.razor.css | 71 +
.../Components/Layout/MainLayout.razor | 17 +
.../Components/Layout/MainLayout.razor.cs | 75 +
.../Components/Layout/MainLayout.razor.css | 100 +
.../Components/Layout/NavMenu.razor | 23 +
.../Components/Layout/NavMenu.razor.cs | 72 +
.../Components/Layout/NavMenu.razor.css | 72 +
.../Components/Layout/NavMenu.razor.js | 53 +
.../Components/Layout/PageLayout.razor | 145 +
.../Components/Layout/PageLayout.razor.cs | 86 +
.../Components/Layout/PageLayout.razor.css | 310 +
.../Components/Layout/PracticeLayout.razor | 17 +
.../Layout/PracticeLayout.razor.css | 73 +
.../Layout/PracticeLoginLayout.razor | 22 +
.../Layout/PracticeLoginLayout.razor.css | 34 +
.../Components/Layout/PracticeNavMenu.razor | 16 +
.../Layout/PracticeNavMenu.razor.cs | 259 +
.../Layout/PracticeNavMenu.razor.css | 43 +
.../Components/Layout/PrintLayout.razor | 3 +
.../Components/Pages/App.razor | 57 +
.../Components/Pages/Breakpoints.razor | 58 +
.../Components/Pages/Breakpoints.razor.css | 4 +
.../Components/Pages/Coms.razor | 157 +
.../Components/Pages/Coms.razor.cs | 23 +
.../Components/Pages/Coms.razor.css | 26 +
.../Components/Pages/Error.razor | 16 +
.../Components/Pages/Golbalization.razor | 8 +
.../Components/Pages/Index.razor | 161 +
.../Components/Pages/Index.razor.cs | 30 +
.../Components/Pages/Index.razor.css | 196 +
.../Components/Pages/Index.razor.js | 79 +
.../Components/Pages/Install.razor | 56 +
.../Components/Pages/Install.razor.css | 28 +
.../Components/Pages/Install_Maui.razor | 226 +
.../Components/Pages/Install_Server.razor | 53 +
.../Components/Pages/Install_wasm.razor | 46 +
.../Components/Pages/Introduction.razor | 73 +
.../Components/Pages/Introduction.razor.cs | 46 +
.../Components/Pages/Layout.razor | 32 +
.../Components/Pages/Layout.razor.cs | 77 +
.../Components/Pages/Localization.razor | 362 +
.../Components/Pages/Localization.razor.css | 11 +
.../Components/Pages/Practice.razor | 10 +
.../Components/Pages/Practice.razor.css | 26 +
.../Components/Pages/Routes.razor | 7 +
.../Components/Pages/Template.razor | 51 +
.../Components/Pages/Template.razor.cs | 27 +
.../Components/Pages/Theme.razor | 24 +
.../Components/Samples/Ajaxs.razor | 34 +
.../Components/Samples/Ajaxs.razor.cs | 87 +
.../Components/Samples/Alerts.razor | 71 +
.../Components/Samples/Alerts.razor.cs | 186 +
.../Components/Samples/AnchorLinks.razor | 17 +
.../Components/Samples/AnchorLinks.razor.cs | 51 +
.../Components/Samples/Anchors.razor | 36 +
.../Components/Samples/Anchors.razor.cs | 59 +
.../Components/Samples/AutoCompletes.razor | 101 +
.../Components/Samples/AutoCompletes.razor.cs | 174 +
.../Components/Samples/AutoFills.razor | 69 +
.../Components/Samples/AutoFills.razor.cs | 157 +
.../Components/Samples/AutoRedirects.razor | 12 +
.../Components/Samples/AutoRedirects.razor.cs | 60 +
.../Components/Samples/Avatars.razor | 59 +
.../Components/Samples/Avatars.razor.cs | 98 +
.../Components/Samples/Badges.razor | 52 +
.../Components/Samples/Badges.razor.cs | 51 +
.../Components/Samples/Badges.razor.css | 21 +
.../Components/Samples/BaiduOcr.razor | 136 +
.../Components/Samples/BaiduOcr.razor.cs | 130 +
.../Components/Samples/BarcodeReaders.razor | 36 +
.../Samples/BarcodeReaders.razor.cs | 187 +
.../Components/Samples/Blocks.razor | 73 +
.../Components/Samples/Blocks.razor.cs | 108 +
.../Components/Samples/Bluetooth.razor | 76 +
.../Components/Samples/Bluetooth.razor.cs | 365 +
.../Components/Samples/Bluetooth.razor.css | 11 +
.../Components/Samples/Breadcrumbs.razor | 10 +
.../Components/Samples/Breadcrumbs.razor.cs | 28 +
.../Components/Samples/Buttons.razor | 159 +
.../Components/Samples/Buttons.razor.cs | 197 +
.../Components/Samples/Calendars.razor | 126 +
.../Components/Samples/Calendars.razor.cs | 79 +
.../Components/Samples/Calendars.razor.css | 36 +
.../Components/Samples/Cameras.razor | 53 +
.../Components/Samples/Cameras.razor.cs | 257 +
.../Components/Samples/Captchas.razor | 24 +
.../Components/Samples/Captchas.razor.cs | 170 +
.../Components/Samples/Cards.razor | 225 +
.../Components/Samples/Cards.razor.cs | 92 +
.../Components/Samples/Carousels.razor | 210 +
.../Components/Samples/Carousels.razor.cs | 91 +
.../Components/Samples/Carousels.razor.css | 28 +
.../Components/Samples/Cascaders.razor | 127 +
.../Components/Samples/Cascaders.razor.cs | 150 +
.../Components/Samples/Charts/Bar.razor | 49 +
.../Components/Samples/Charts/Bar.razor.cs | 180 +
.../Components/Samples/Charts/Bubble.razor | 25 +
.../Components/Samples/Charts/Bubble.razor.cs | 104 +
.../Components/Samples/Charts/Doughnut.razor | 27 +
.../Samples/Charts/Doughnut.razor.cs | 99 +
.../Components/Samples/Charts/Index.razor | 14 +
.../Components/Samples/Charts/Index.razor.cs | 194 +
.../Components/Samples/Charts/Line.razor | 60 +
.../Components/Samples/Charts/Line.razor.cs | 281 +
.../Components/Samples/Charts/Line.razor.js | 68 +
.../Components/Samples/Charts/Pie.razor | 31 +
.../Components/Samples/Charts/Pie.razor.cs | 105 +
.../Components/Samples/Charts/Utility.cs | 90 +
.../Components/Samples/CheckboxLists.razor | 115 +
.../Components/Samples/CheckboxLists.razor.cs | 175 +
.../Components/Samples/Checkboxs.razor | 145 +
.../Components/Samples/Checkboxs.razor.cs | 123 +
.../Components/Samples/CherryMarkdowns.razor | 37 +
.../Samples/CherryMarkdowns.razor.cs | 119 +
.../Components/Samples/Circles.razor | 60 +
.../Components/Samples/Circles.razor.cs | 76 +
.../Components/Samples/Circles.razor.css | 16 +
.../Components/Samples/Client.razor | 81 +
.../Components/Samples/Client.razor.cs | 27 +
.../Components/Samples/Clipboards.razor | 19 +
.../Components/Samples/Clipboards.razor.cs | 39 +
.../Components/Samples/CodeEditors.razor | 38 +
.../Components/Samples/CodeEditors.razor.cs | 148 +
.../Components/Samples/Collapses.razor | 143 +
.../Components/Samples/Collapses.razor.cs | 59 +
.../Components/Samples/ColorPickers.razor | 37 +
.../Components/Samples/ColorPickers.razor.cs | 41 +
.../Components/Samples/Consoles.razor | 33 +
.../Components/Samples/Consoles.razor.cs | 269 +
.../Components/Samples/ContextMenus.razor | 55 +
.../Components/Samples/ContextMenus.razor.cs | 34 +
.../Components/Samples/CountButtons.razor | 16 +
.../Components/Samples/CountButtons.razor.cs | 43 +
.../Components/Samples/CountUps.razor | 109 +
.../Components/Samples/CountUps.razor.cs | 219 +
.../Components/Samples/CountUps.razor.css | 3 +
.../Components/Samples/DateTimePickers.razor | 153 +
.../Samples/DateTimePickers.razor.cs | 168 +
.../Components/Samples/DateTimeRanges.razor | 89 +
.../Samples/DateTimeRanges.razor.cs | 231 +
.../Components/Samples/DialButtons.razor | 97 +
.../Components/Samples/DialButtons.razor.cs | 54 +
.../Components/Samples/DialButtons.razor.css | 22 +
.../Components/Samples/Dialogs.razor | 194 +
.../Components/Samples/Dialogs.razor.cs | 450 ++
.../Components/Samples/Dispatches.razor | 54 +
.../Components/Samples/Dispatches.razor.cs | 17 +
.../Components/Samples/Displays.razor | 136 +
.../Components/Samples/Displays.razor.cs | 103 +
.../Components/Samples/Dividers.razor | 72 +
.../Components/Samples/Dividers.razor.cs | 54 +
.../Samples/DockViews/BaseDockView.cs | 155 +
.../Samples/DockViews/DockViewCol.razor | 48 +
.../Samples/DockViews/DockViewComplex.razor | 53 +
.../Samples/DockViews/DockViewLayout.razor | 94 +
.../DockViews/DockViewLayout.razor.css | 14 +
.../Samples/DockViews/DockViewLock.razor | 88 +
.../Samples/DockViews/DockViewLock.razor.css | 4 +
.../Samples/DockViews/DockViewNest.razor | 62 +
.../Samples/DockViews/DockViewRow.razor | 48 +
.../Samples/DockViews/DockViewStack.razor | 48 +
.../Samples/DockViews/DockViewVisible.razor | 65 +
.../DockViews/DockViewVisible.razor.css | 4 +
.../Components/Samples/DockViews/Index.razor | 11 +
.../Samples/DockViews/_Imports.razor | 1 +
.../Components/Samples/Downloads.razor | 70 +
.../Components/Samples/Downloads.razor.cs | 77 +
.../Components/Samples/DragDrops.razor | 95 +
.../Components/Samples/DragDrops.razor.cs | 168 +
.../Components/Samples/Drawers.razor | 41 +
.../Components/Samples/Drawers.razor.cs | 123 +
.../Components/Samples/DropdownWidgets.razor | 87 +
.../Samples/DropdownWidgets.razor.cs | 87 +
.../Samples/DropdownWidgets.razor.css | 19 +
.../Components/Samples/Dropdowns.razor | 176 +
.../Components/Samples/Dropdowns.razor.cs | 262 +
.../Components/Samples/EditDialogs.razor | 28 +
.../Components/Samples/EditDialogs.razor.cs | 213 +
.../Components/Samples/EditorForms.razor | 128 +
.../Components/Samples/EditorForms.razor.cs | 191 +
.../Components/Samples/Editors.razor | 75 +
.../Components/Samples/Editors.razor.cs | 164 +
.../Components/Samples/Empties.razor | 31 +
.../Components/Samples/Empties.razor.cs | 67 +
.../Components/Samples/EyeDroppers.razor | 24 +
.../Components/Samples/EyeDroppers.razor.cs | 22 +
.../Components/Samples/FAIcons.razor | 25 +
.../Components/Samples/FAIcons.razor.cs | 45 +
.../Components/Samples/FileIcons.razor | 121 +
.../Components/Samples/FileIcons.razor.cs | 43 +
.../Components/Samples/FileIcons.razor.css | 9 +
.../Components/Samples/FileViewers.razor | 41 +
.../Components/Samples/FileViewers.razor.cs | 169 +
.../Components/Samples/FloatingLabels.razor | 82 +
.../Samples/FloatingLabels.razor.cs | 106 +
.../Components/Samples/Footers.razor | 63 +
.../Components/Samples/Footers.razor.cs | 47 +
.../Components/Samples/FullScreens.razor | 21 +
.../Components/Samples/Gantts.razor | 18 +
.../Components/Samples/Gantts.razor.cs | 198 +
.../Components/Samples/Geolocations.razor | 64 +
.../Components/Samples/Geolocations.razor.cs | 83 +
.../Components/Samples/GlobalException.razor | 71 +
.../Samples/GlobalException.razor.cs | 65 +
.../Components/Samples/GoTops.razor | 23 +
.../Components/Samples/GoTops.razor.cs | 23 +
.../Components/Samples/GroupBoxes.razor | 15 +
.../Components/Samples/GroupBoxes.razor.cs | 23 +
.../Components/Samples/Handwrittens.razor | 13 +
.../Components/Samples/Handwrittens.razor.cs | 52 +
.../Components/Samples/Html2Pdfs.razor | 83 +
.../Components/Samples/HtmlRenderers.razor | 16 +
.../Components/Samples/HtmlRenderers.razor.cs | 22 +
.../Components/Samples/ImageViewers.razor | 123 +
.../Components/Samples/ImageViewers.razor.cs | 108 +
.../Components/Samples/ImageViewers.razor.css | 42 +
.../Components/Samples/InputGroups.razor | 204 +
.../Components/Samples/InputGroups.razor.cs | 65 +
.../Components/Samples/InputNumbers.razor | 210 +
.../Components/Samples/InputNumbers.razor.cs | 105 +
.../Components/Samples/InputNumbers.razor.css | 7 +
.../Components/Samples/Inputs.razor | 212 +
.../Components/Samples/Inputs.razor.cs | 195 +
.../Components/Samples/Ips.razor | 7 +
.../Components/Samples/Ips.razor.cs | 13 +
.../Samples/JSRuntimeExtensions.razor | 62 +
.../Samples/JSRuntimeExtensions.razor.cs | 128 +
.../Samples/JSRuntimeExtensions.razor.css | 15 +
.../Components/Samples/Labels.razor | 222 +
.../Components/Samples/Labels.razor.cs | 36 +
.../Components/Samples/LayoutDemo.razor | 31 +
.../Components/Samples/LayoutPages.razor | 68 +
.../Components/Samples/LayoutPages.razor.cs | 121 +
.../Components/Samples/LayoutPages.razor.css | 24 +
.../Components/Samples/LayoutPages1.razor | 5 +
.../Components/Samples/Layouts.razor | 192 +
.../Components/Samples/Layouts.razor.cs | 179 +
.../Components/Samples/Layouts.razor.css | 68 +
.../Components/Samples/Lights.razor | 83 +
.../Components/Samples/Lights.razor.cs | 120 +
.../Components/Samples/LinkButtons.razor | 89 +
.../Components/Samples/LinkButtons.razor.cs | 91 +
.../Components/Samples/ListGroups.razor | 46 +
.../Components/Samples/ListGroups.razor.cs | 97 +
.../Components/Samples/ListGroups.razor.css | 3 +
.../Components/Samples/ListViews.razor | 111 +
.../Components/Samples/ListViews.razor.cs | 151 +
.../Components/Samples/ListViews.razor.css | 12 +
.../Components/Samples/Live2DDisplays.razor | 100 +
.../Samples/Live2DDisplays.razor.cs | 127 +
.../Components/Samples/Locators.razor | 57 +
.../Components/Samples/Locators.razor.cs | 38 +
.../Components/Samples/Logouts.razor | 66 +
.../Components/Samples/Logouts.razor.cs | 78 +
.../Components/Samples/Markdowns.razor | 104 +
.../Components/Samples/Markdowns.razor.cs | 129 +
.../Components/Samples/Marquees.razor | 39 +
.../Components/Samples/Marquees.razor.cs | 23 +
.../Components/Samples/Marquees.razor.css | 7 +
.../Components/Samples/Menus.razor | 124 +
.../Components/Samples/Menus.razor.cs | 158 +
.../Components/Samples/Menus.razor.css | 63 +
.../Components/Samples/Messages.razor | 81 +
.../Components/Samples/Messages.razor.cs | 142 +
.../Samples/MindMaps/MindMaps.razor | 36 +
.../Samples/MindMaps/MindMaps.razor.cs | 346 +
.../Samples/MindMaps/MindMapsSamples.razor.cs | 300 +
.../Components/Samples/Modals.razor | 275 +
.../Components/Samples/Modals.razor.cs | 223 +
.../Components/Samples/MouseFollowers.razor | 72 +
.../Samples/MouseFollowers.razor.cs | 58 +
.../Samples/MouseFollowers.razor.css | 14 +
.../Components/Samples/MultiSelects.razor | 219 +
.../Components/Samples/MultiSelects.razor.cs | 402 ++
.../Components/Samples/MultiSelects.razor.css | 11 +
.../Components/Samples/Navigation.razor | 89 +
.../Components/Samples/Navigation.razor.cs | 86 +
.../Components/Samples/Notifications.razor | 51 +
.../Components/Samples/Notifications.razor.cs | 119 +
.../Samples/OnScreenKeyboards.razor | 118 +
.../Samples/OnScreenKeyboards.razor.cs | 303 +
.../Samples/OnScreenKeyboards.razor.css | 10 +
.../Components/Samples/Paginations.razor | 57 +
.../Components/Samples/Paginations.razor.cs | 170 +
.../Components/Samples/PdfReaders.razor | 95 +
.../Components/Samples/PdfReaders.razor.cs | 270 +
.../Components/Samples/PopoverConfirms.razor | 146 +
.../Samples/PopoverConfirms.razor.cs | 196 +
.../Components/Samples/Popovers.razor | 65 +
.../Components/Samples/Popovers.razor.cs | 51 +
.../Components/Samples/Popovers.razor.css | 10 +
.../Samples/Practices/Dashboard.razor | 160 +
.../Samples/Practices/Dashboard.razor.cs | 104 +
.../Samples/Practices/Dashboard.razor.css | 22 +
.../Samples/Practices/DashboardData.cs | 124 +
.../LoginAndRegister/Template6.razor | 24 +
.../LoginAndRegister/Template6.razor.css | 16 +
.../LoginAndRegister/Template7.razor | 24 +
.../LoginAndRegister/Template7.razor.css | 3 +
.../LoginAndRegister/Template8.razor | 26 +
.../LoginAndRegister/Template8.razor.css | 16 +
.../LoginAndRegister/Template9.razor | 42 +
.../LoginAndRegister/Template9.razor.css | 51 +
.../Samples/Practices/Waterfall.razor | 23 +
.../Samples/Practices/Waterfall.razor.cs | 115 +
.../Samples/Practices/Waterfall.razor.css | 51 +
.../Samples/Practices/_Imports.razor | 1 +
.../Components/Samples/Print.razor | 73 +
.../Components/Samples/PrintView.razor | 20 +
.../Components/Samples/PrintView.razor.cs | 28 +
.../Components/Samples/PrintView.razor.css | 5 +
.../Components/Samples/Progress.razor | 124 +
.../Components/Samples/Progress.razor.cs | 67 +
.../Components/Samples/PulseButtons.razor | 24 +
.../Components/Samples/QRCodes.razor | 35 +
.../Components/Samples/QRCodes.razor.cs | 122 +
.../Components/Samples/QueryBuilders.razor | 56 +
.../Components/Samples/QueryBuilders.razor.cs | 17 +
.../Components/Samples/Radios.razor | 131 +
.../Components/Samples/Radios.razor.cs | 183 +
.../Components/Samples/Rates.razor | 73 +
.../Components/Samples/Rates.razor.cs | 122 +
.../Components/Samples/Reconnectors.razor | 271 +
.../Components/Samples/Reconnectors.razor.cs | 41 +
.../Components/Samples/Repeaters.razor | 69 +
.../Components/Samples/Repeaters.razor.cs | 107 +
.../Components/Samples/Responsives.razor | 14 +
.../Components/Samples/Responsives.razor.cs | 32 +
.../Components/Samples/RibbonTabs.razor | 54 +
.../Components/Samples/RibbonTabs.razor.cs | 193 +
.../Components/Samples/Rows.razor | 178 +
.../Components/Samples/Rows.razor.cs | 112 +
.../Components/Samples/Scrolls.razor | 19 +
.../Components/Samples/Scrolls.razor.cs | 35 +
.../Components/Samples/Scrolls.razor.css | 5 +
.../Components/Samples/SearchDialogs.razor | 35 +
.../Components/Samples/SearchDialogs.razor.cs | 181 +
.../Components/Samples/Searches.razor | 67 +
.../Components/Samples/Searches.razor.cs | 185 +
.../Components/Samples/Segmenteds.razor | 73 +
.../Components/Samples/Segmenteds.razor.cs | 147 +
.../Components/Samples/SelectTrees.razor | 72 +
.../Components/Samples/SelectTrees.razor.cs | 88 +
.../Components/Samples/Selects.razor | 410 ++
.../Components/Samples/Selects.razor.cs | 356 +
.../Components/Samples/Selects.razor.css | 62 +
.../Samples/SignaturePadPageResponsive.razor | 68 +
.../Components/Samples/SignaturePads.razor | 46 +
.../Components/Samples/SignaturePads.razor.cs | 239 +
.../Components/Samples/Skeletons.razor | 59 +
.../Components/Samples/Skeletons.razor.cs | 59 +
.../Components/Samples/Skeletons.razor.css | 7 +
.../Components/Samples/SlideButtons.razor | 130 +
.../Components/Samples/SlideButtons.razor.cs | 44 +
.../Components/Samples/SlideButtons.razor.css | 43 +
.../Components/Samples/Sliders.razor | 150 +
.../Components/Samples/Sliders.razor.css | 3 +
.../Components/Samples/Speeches/Index.razor | 52 +
.../Samples/Speeches/Index.razor.cs | 158 +
.../Samples/Speeches/Recognizers.razor | 24 +
.../Samples/Speeches/Recognizers.razor.cs | 60 +
.../Samples/Speeches/SpeechWaves.razor | 33 +
.../Samples/Speeches/SpeechWaves.razor.cs | 60 +
.../Samples/Speeches/Synthesizers.razor | 21 +
.../Samples/Speeches/Synthesizers.razor.cs | 48 +
.../Components/Samples/Spinners.razor | 93 +
.../Components/Samples/Spinners.razor.cs | 51 +
.../Components/Samples/Splits.razor | 75 +
.../Components/Samples/Splits.razor.cs | 51 +
.../Components/Samples/Splits.razor.css | 21 +
.../Components/Samples/Splittings.razor | 53 +
.../Components/Samples/Splittings.razor.cs | 57 +
.../Components/Samples/Splittings.razor.css | 3 +
.../Components/Samples/Stacks.razor | 76 +
.../Components/Samples/Stacks.razor.cs | 85 +
.../Components/Samples/Stacks.razor.css | 33 +
.../Components/Samples/Steps.razor | 149 +
.../Components/Samples/Steps.razor.cs | 162 +
.../Components/Samples/Steps.razor.css | 11 +
.../Components/Samples/SweetAlerts.razor | 154 +
.../Components/Samples/SweetAlerts.razor.cs | 224 +
.../Components/Samples/SwitchButtons.razor | 28 +
.../Components/Samples/SwitchButtons.razor.cs | 69 +
.../Components/Samples/Switches.razor | 124 +
.../Components/Samples/Switches.razor.cs | 176 +
.../Components/Samples/Table/Tables.razor | 99 +
.../Components/Samples/Table/Tables.razor.cs | 1281 ++++
.../Samples/Table/TablesAutoRefresh.razor | 46 +
.../Samples/Table/TablesAutoRefresh.razor.cs | 43 +
.../Components/Samples/Table/TablesCell.razor | 44 +
.../Samples/Table/TablesCell.razor.cs | 98 +
.../Samples/Table/TablesCell.razor.css | 3 +
.../Samples/Table/TablesColumn.razor | 176 +
.../Samples/Table/TablesColumn.razor.cs | 97 +
.../Samples/Table/TablesColumnDrag.razor | 28 +
.../Samples/Table/TablesColumnDrag.razor.cs | 70 +
.../Samples/Table/TablesColumnList.razor | 67 +
.../Samples/Table/TablesColumnList.razor.cs | 91 +
.../Samples/Table/TablesColumnResizing.razor | 60 +
.../Table/TablesColumnResizing.razor.cs | 85 +
.../Samples/Table/TablesColumnTemplate.razor | 91 +
.../Table/TablesColumnTemplate.razor.cs | 61 +
.../Samples/Table/TablesDetailRow.razor | 123 +
.../Samples/Table/TablesDetailRow.razor.cs | 121 +
.../Samples/Table/TablesDialog.razor | 49 +
.../Samples/Table/TablesDialog.razor.cs | 120 +
.../Samples/Table/TablesDynamic.razor | 51 +
.../Samples/Table/TablesDynamic.razor.cs | 256 +
.../Samples/Table/TablesDynamicExcel.razor | 111 +
.../Samples/Table/TablesDynamicExcel.razor.cs | 119 +
.../Samples/Table/TablesDynamicObject.razor | 43 +
.../Table/TablesDynamicObject.razor.cs | 46 +
.../Components/Samples/Table/TablesEdit.razor | 249 +
.../Samples/Table/TablesEdit.razor.cs | 140 +
.../Samples/Table/TablesExcel.razor | 120 +
.../Samples/Table/TablesExcel.razor.cs | 97 +
.../Samples/Table/TablesExport.razor | 95 +
.../Samples/Table/TablesExport.razor.cs | 176 +
.../Samples/Table/TablesFilter.razor | 192 +
.../Samples/Table/TablesFilter.razor.cs | 127 +
.../Samples/Table/TablesFixedColumn.razor | 120 +
.../Samples/Table/TablesFixedColumn.razor.cs | 28 +
.../Samples/Table/TablesFixedHeader.razor | 105 +
.../Samples/Table/TablesFixedHeader.razor.cs | 43 +
.../Samples/Table/TablesFooter.razor | 79 +
.../Samples/Table/TablesFooter.razor.cs | 75 +
.../Samples/Table/TablesFooter.razor.css | 14 +
.../Samples/Table/TablesHeader.razor | 32 +
.../Samples/Table/TablesHeader.razor.cs | 59 +
.../Samples/Table/TablesLoading.razor | 47 +
.../Samples/Table/TablesLoading.razor.cs | 152 +
.../Samples/Table/TablesLookup.razor | 24 +
.../Samples/Table/TablesLookup.razor.cs | 31 +
.../Samples/Table/TablesNameDrop.razor | 1 +
.../Samples/Table/TablesNameDrop.razor.cs | 27 +
.../Samples/Table/TablesPages.razor | 32 +
.../Samples/Table/TablesPages.razor.cs | 45 +
.../Components/Samples/Table/TablesRow.razor | 140 +
.../Samples/Table/TablesRow.razor.cs | 101 +
.../Samples/Table/TablesRow.razor.css | 4 +
.../Samples/Table/TablesSearch.razor | 148 +
.../Samples/Table/TablesSearch.razor.cs | 174 +
.../Samples/Table/TablesSelection.razor | 39 +
.../Samples/Table/TablesSelection.razor.cs | 50 +
.../Samples/Table/TablesToolbar.razor | 96 +
.../Samples/Table/TablesToolbar.razor.cs | 110 +
.../Samples/Table/TablesTracking.razor | 23 +
.../Samples/Table/TablesTracking.razor.cs | 28 +
.../Components/Samples/Table/TablesTree.razor | 90 +
.../Samples/Table/TablesTree.razor.cs | 133 +
.../Samples/Table/TablesVirtualization.razor | 43 +
.../Table/TablesVirtualization.razor.cs | 40 +
.../Table/TablesVirtualization.razor.css | 13 +
.../Components/Samples/Table/TablesWrap.razor | 100 +
.../Samples/Table/TablesWrap.razor.cs | 39 +
.../Components/Samples/Tabs.razor | 442 ++
.../Components/Samples/Tabs.razor.cs | 348 +
.../Components/Samples/Tabs.razor.css | 8 +
.../Components/Samples/Tags.razor | 92 +
.../Components/Samples/Tags.razor.cs | 83 +
.../Components/Samples/TextAreas.razor | 67 +
.../Components/Samples/TextAreas.razor.cs | 173 +
.../Components/Samples/TextAreas.razor.css | 10 +
.../Components/Samples/Timelines.razor | 47 +
.../Components/Samples/Timelines.razor.cs | 263 +
.../Components/Samples/Timers.razor | 20 +
.../Components/Samples/Timers.razor.cs | 70 +
.../Components/Samples/Titles.razor | 53 +
.../Components/Samples/Titles.razor.cs | 12 +
.../Components/Samples/Toasts.razor | 178 +
.../Components/Samples/Toasts.razor.cs | 188 +
.../Components/Samples/Toasts.razor.css | 8 +
.../Components/Samples/Toggles.razor | 109 +
.../Components/Samples/Toggles.razor.cs | 117 +
.../Components/Samples/Tooltips.razor | 91 +
.../Components/Samples/Tooltips.razor.cs | 37 +
.../Components/Samples/Tooltips.razor.css | 10 +
.../Components/Samples/Topologies.razor | 21 +
.../Components/Samples/Topologies.razor.cs | 117 +
.../Components/Samples/Topologies.razor.css | 7 +
.../Components/Samples/Topologies.razor.js | 11 +
.../Components/Samples/Transfers.razor | 100 +
.../Components/Samples/Transfers.razor.cs | 222 +
.../Components/Samples/Transitions.razor | 35 +
.../Components/Samples/Transitions.razor.cs | 89 +
.../Components/Samples/TreeViews.razor | 144 +
.../Components/Samples/TreeViews.razor.cs | 338 +
.../Components/Samples/Trees.razor | 132 +
.../Components/Samples/Trees.razor.cs | 339 +
.../Components/Samples/Uploads.razor | 189 +
.../Components/Samples/Uploads.razor.cs | 478 ++
.../Components/Samples/ValidateForms.razor | 300 +
.../Components/Samples/ValidateForms.razor.cs | 305 +
.../Components/Samples/VideoPlayers.razor | 70 +
.../Components/Samples/VideoPlayers.razor.cs | 138 +
.../Components/Samples/WebSerials.razor | 153 +
.../Components/Samples/WebSerials.razor.cs | 320 +
.../Components/Samples/WebSpeechs.razor | 132 +
.../Components/Samples/WebSpeechs.razor.cs | 251 +
.../Components/Samples/WebSpeechs.razor.css | 3 +
.../Components/Samples/_Imports.razor | 1 +
.../Controllers/Api/CodeController.cs | 2 +-
.../Controllers/Api/GiteeController.cs | 3 +-
.../Controllers/Api/LoginController.cs | 2 +-
.../Controllers/CultureController.cs | 1 +
.../Data/AttributeItem.cs | 43 +
.../Data/CalendarDemoDataHelper.cs | 62 +
.../Data/CustomDynamicColumnsObjectData.cs | 54 +
.../Data/CustomDynamicData.cs | 86 +
src/BootstrapBlazor.Server/Data/EventItem.cs | 31 +
src/BootstrapBlazor.Server/Data/Foo.cs | 206 +
.../Data/FooSearchModel.cs | 86 +
.../Data/GiteePushBody.cs | 118 +
src/BootstrapBlazor.Server/Data/LoginModel.cs | 32 +
src/BootstrapBlazor.Server/Data/Menus.cs | 301 +
.../Data/MessageItem.cs | 16 +
src/BootstrapBlazor.Server/Data/MethodItem.cs | 25 +
.../Data/TreeDataFoo.cs | 62 +
src/BootstrapBlazor.Server/Data/TreeFoo.cs | 70 +
src/BootstrapBlazor.Server/Data/User.cs | 21 +
.../Data/WeatherForecast.cs | 31 +
.../Data/WebsiteOptions.cs | 143 +
.../Extensions/CacheManagerExtensions.cs | 38 +
.../Extensions/DispatchEntryExtensions.cs | 21 +
.../Extensions/JSRuntimeExtensions.cs | 26 +
.../Extensions/MenusLocalizerExtensions.cs | 1327 ++++
.../Extensions/ServicesExtensions.cs | 43 +-
src/BootstrapBlazor.Server/Locales/en.json | 6024 +++++++++++++++++
src/BootstrapBlazor.Server/Locales/zh.json | 6024 +++++++++++++++++
src/BootstrapBlazor.Server/Pages/_Host.cshtml | 8 -
.../Pages/_Layout.cshtml | 70 -
src/BootstrapBlazor.Server/Program.cs | 27 +-
.../Services/ClearUploadFilesService.cs | 1 -
.../Services/CodeSnippetService.cs | 151 +
.../Services/DashboardService.cs | 100 +
.../Services/DemoLookupService.cs | 30 +
.../Services/FanControllerDataService.cs | 116 +
.../Services/MenuService.cs | 19 +
.../MockAuthenticationStateProvider.cs | 74 +
.../Services/MockDataTableDynamicService.cs | 187 +
.../Services/PackageVersionService.cs | 76 +
.../Services/TableDemoDataService.cs | 105 +
.../Services/WeatherForecastService.cs | 29 +
src/BootstrapBlazor.Server/_Imports.razor | 5 +-
src/BootstrapBlazor.Server/docs.json | 250 +
src/BootstrapBlazor.Server/menus.json | 33 +
src/BootstrapBlazor.Server/topology.json | 205 +
src/BootstrapBlazor.Server/versionconfig.json | 5 +
.../Shared/BaseLayout.razor | 3 +
src/BootstrapBlazor/BootstrapBlazor.csproj | 1 -
.../wwwroot/modules/responsive.js | 5 +-
666 files changed, 67662 insertions(+), 312 deletions(-)
delete mode 100644 dist/.gitattributes
delete mode 100644 dist/.nojekyll
delete mode 100644 dist/.spa
delete mode 100644 dist/404.html
delete mode 100644 dist/gitee-pages/404.html
create mode 100644 src/BootstrapBlazor.Server/Components/Components/AttributeTable.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Components/AttributeTable.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Components/BBLogo.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Components/BBLogo.razor.css
create mode 100644 src/BootstrapBlazor.Server/Components/Components/BlazorReconnector.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Components/CSS.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Components/CSS.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Components/CalendarCrewCell.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Components/CalendarCrewCell.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Components/CalendarCrewCell.razor.css
create mode 100644 src/BootstrapBlazor.Server/Components/Components/CalendarCrewDialogBody.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Components/CalendarCrewDialogBody.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Components/CalendarCrewDialogBody.razor.css
create mode 100644 src/BootstrapBlazor.Server/Components/Components/CommitItem.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Components/CommitItem.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Components/ComponentCard.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Components/ComponentCard.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Components/ComponentCategory.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Components/ComponentCategory.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Components/ComponentCategory.razor.css
create mode 100644 src/BootstrapBlazor.Server/Components/Components/ContextMenuList.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Components/Counter.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Components/CultureChooser.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Components/CultureChooser.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Components/CultureChooser.razor.css
create mode 100644 src/BootstrapBlazor.Server/Components/Components/CustomerFilter.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Components/CustomerSelectDialog.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Components/CustomerSelectDialog.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Components/DataDialogComponent.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Components/DemoBlock.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Components/DemoBlock.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Components/DemoBlock.razor.css
create mode 100644 src/BootstrapBlazor.Server/Components/Components/DemoComponent.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Components/DemoTabItem.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Components/DemoTabItem.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Components/DemoTabItemSetText.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Components/DemoTabItemSetText.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Components/DemoTableEditTemplate.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Components/DialogBodyFoo.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Components/DialogBodyFoo.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Components/DialogDemo.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Components/DialogDemo.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Components/DialogHeaderFoo.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Components/DialogHeaderFoo.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Components/DialogSaveDetail.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Components/ErrorCounter.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Components/EventTable.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Components/FetchData.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Components/FooSearch.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Components/FooSearch.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Components/FormInlineSwitch.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Components/FormInlineSwitch.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Components/GlobalSearch.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Components/GlobalSearch.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Components/Header.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Components/Header.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Components/Header.razor.css
create mode 100644 src/BootstrapBlazor.Server/Components/Components/Header.razor.js
create mode 100644 src/BootstrapBlazor.Server/Components/Components/InstallContent.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Components/InstallContent.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Components/MethodTable.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Components/MethodTable.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Components/PackageTips.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Components/Pre.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Components/Pre.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Components/Pre.razor.css
create mode 100644 src/BootstrapBlazor.Server/Components/Components/Pre.razor.js
create mode 100644 src/BootstrapBlazor.Server/Components/Components/QQGroup.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Components/ResultDialogDemo.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Components/ResultDialogDemo.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Components/ResultDialogDemo2.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Components/ResultDialogDemo2.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Components/ShownCallbackDummy.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Components/State.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Components/State.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Components/SwalFooter.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Components/ThemeChooser.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Components/ThemeChooser.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Components/ThemeChooser.razor.css
create mode 100644 src/BootstrapBlazor.Server/Components/Components/ThemeChooser.razor.js
create mode 100644 src/BootstrapBlazor.Server/Components/Components/Tips.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Components/UpdateIntro.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Components/UpdateIntro.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Components/UpdateIntro.razor.css
create mode 100644 src/BootstrapBlazor.Server/Components/Components/UpdateIntro.razor.js
create mode 100644 src/BootstrapBlazor.Server/Components/Components/Video.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Components/WebSiteModuleComponentBase.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Components/Widget.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Components/WinButton.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Components/Wwads.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Components/Wwads.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Components/Wwads.razor.js
create mode 100644 src/BootstrapBlazor.Server/Components/Layout/BaseLayout.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Layout/BaseLayout.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Layout/BaseLayout.razor.css
create mode 100644 src/BootstrapBlazor.Server/Components/Layout/ComponentLayout.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Layout/ComponentLayout.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Layout/ComponentLayout.razor.css
create mode 100644 src/BootstrapBlazor.Server/Components/Layout/ComponentLayout.razor.js
create mode 100644 src/BootstrapBlazor.Server/Components/Layout/DockLayout.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Layout/DockLayout.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Layout/DockLayout.razor.css
create mode 100644 src/BootstrapBlazor.Server/Components/Layout/DockLayout.razor.js
create mode 100644 src/BootstrapBlazor.Server/Components/Layout/HomeLayout.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Layout/HomeLayout.razor.css
create mode 100644 src/BootstrapBlazor.Server/Components/Layout/MainLayout.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Layout/MainLayout.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Layout/MainLayout.razor.css
create mode 100644 src/BootstrapBlazor.Server/Components/Layout/NavMenu.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Layout/NavMenu.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Layout/NavMenu.razor.css
create mode 100644 src/BootstrapBlazor.Server/Components/Layout/NavMenu.razor.js
create mode 100644 src/BootstrapBlazor.Server/Components/Layout/PageLayout.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Layout/PageLayout.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Layout/PageLayout.razor.css
create mode 100644 src/BootstrapBlazor.Server/Components/Layout/PracticeLayout.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Layout/PracticeLayout.razor.css
create mode 100644 src/BootstrapBlazor.Server/Components/Layout/PracticeLoginLayout.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Layout/PracticeLoginLayout.razor.css
create mode 100644 src/BootstrapBlazor.Server/Components/Layout/PracticeNavMenu.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Layout/PracticeNavMenu.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Layout/PracticeNavMenu.razor.css
create mode 100644 src/BootstrapBlazor.Server/Components/Layout/PrintLayout.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Pages/App.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Pages/Breakpoints.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Pages/Breakpoints.razor.css
create mode 100644 src/BootstrapBlazor.Server/Components/Pages/Coms.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Pages/Coms.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Pages/Coms.razor.css
create mode 100644 src/BootstrapBlazor.Server/Components/Pages/Error.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Pages/Golbalization.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Pages/Index.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Pages/Index.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Pages/Index.razor.css
create mode 100644 src/BootstrapBlazor.Server/Components/Pages/Index.razor.js
create mode 100644 src/BootstrapBlazor.Server/Components/Pages/Install.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Pages/Install.razor.css
create mode 100644 src/BootstrapBlazor.Server/Components/Pages/Install_Maui.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Pages/Install_Server.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Pages/Install_wasm.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Pages/Introduction.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Pages/Introduction.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Pages/Layout.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Pages/Layout.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Pages/Localization.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Pages/Localization.razor.css
create mode 100644 src/BootstrapBlazor.Server/Components/Pages/Practice.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Pages/Practice.razor.css
create mode 100644 src/BootstrapBlazor.Server/Components/Pages/Routes.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Pages/Template.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Pages/Template.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Pages/Theme.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Ajaxs.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Ajaxs.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Alerts.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Alerts.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/AnchorLinks.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/AnchorLinks.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Anchors.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Anchors.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/AutoCompletes.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/AutoCompletes.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/AutoFills.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/AutoFills.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/AutoRedirects.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/AutoRedirects.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Avatars.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Avatars.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Badges.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Badges.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Badges.razor.css
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/BaiduOcr.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/BaiduOcr.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/BarcodeReaders.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/BarcodeReaders.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Blocks.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Blocks.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Bluetooth.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Bluetooth.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Bluetooth.razor.css
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Breadcrumbs.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Breadcrumbs.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Buttons.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Buttons.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Calendars.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Calendars.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Calendars.razor.css
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Cameras.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Cameras.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Captchas.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Captchas.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Cards.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Cards.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Carousels.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Carousels.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Carousels.razor.css
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Cascaders.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Cascaders.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Charts/Bar.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Charts/Bar.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Charts/Bubble.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Charts/Bubble.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Charts/Doughnut.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Charts/Doughnut.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Charts/Index.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Charts/Index.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Charts/Line.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Charts/Line.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Charts/Line.razor.js
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Charts/Pie.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Charts/Pie.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Charts/Utility.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/CheckboxLists.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/CheckboxLists.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Checkboxs.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Checkboxs.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/CherryMarkdowns.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/CherryMarkdowns.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Circles.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Circles.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Circles.razor.css
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Client.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Client.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Clipboards.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Clipboards.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/CodeEditors.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/CodeEditors.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Collapses.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Collapses.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/ColorPickers.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/ColorPickers.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Consoles.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Consoles.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/ContextMenus.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/ContextMenus.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/CountButtons.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/CountButtons.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/CountUps.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/CountUps.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/CountUps.razor.css
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/DateTimePickers.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/DateTimePickers.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/DateTimeRanges.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/DateTimeRanges.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/DialButtons.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/DialButtons.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/DialButtons.razor.css
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Dialogs.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Dialogs.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Dispatches.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Dispatches.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Displays.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Displays.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Dividers.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Dividers.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/DockViews/BaseDockView.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/DockViews/DockViewCol.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/DockViews/DockViewComplex.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/DockViews/DockViewLayout.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/DockViews/DockViewLayout.razor.css
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/DockViews/DockViewLock.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/DockViews/DockViewLock.razor.css
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/DockViews/DockViewNest.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/DockViews/DockViewRow.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/DockViews/DockViewStack.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/DockViews/DockViewVisible.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/DockViews/DockViewVisible.razor.css
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/DockViews/Index.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/DockViews/_Imports.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Downloads.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Downloads.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/DragDrops.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/DragDrops.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Drawers.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Drawers.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/DropdownWidgets.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/DropdownWidgets.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/DropdownWidgets.razor.css
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Dropdowns.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Dropdowns.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/EditDialogs.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/EditDialogs.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/EditorForms.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/EditorForms.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Editors.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Editors.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Empties.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Empties.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/EyeDroppers.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/EyeDroppers.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/FAIcons.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/FAIcons.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/FileIcons.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/FileIcons.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/FileIcons.razor.css
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/FileViewers.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/FileViewers.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/FloatingLabels.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/FloatingLabels.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Footers.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Footers.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/FullScreens.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Gantts.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Gantts.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Geolocations.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Geolocations.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/GlobalException.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/GlobalException.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/GoTops.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/GoTops.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/GroupBoxes.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/GroupBoxes.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Handwrittens.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Handwrittens.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Html2Pdfs.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/HtmlRenderers.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/HtmlRenderers.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/ImageViewers.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/ImageViewers.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/ImageViewers.razor.css
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/InputGroups.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/InputGroups.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/InputNumbers.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/InputNumbers.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/InputNumbers.razor.css
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Inputs.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Inputs.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Ips.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Ips.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/JSRuntimeExtensions.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/JSRuntimeExtensions.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/JSRuntimeExtensions.razor.css
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Labels.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Labels.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/LayoutDemo.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/LayoutPages.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/LayoutPages.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/LayoutPages.razor.css
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/LayoutPages1.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Layouts.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Layouts.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Layouts.razor.css
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Lights.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Lights.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/LinkButtons.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/LinkButtons.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/ListGroups.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/ListGroups.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/ListGroups.razor.css
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/ListViews.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/ListViews.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/ListViews.razor.css
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Live2DDisplays.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Live2DDisplays.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Locators.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Locators.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Logouts.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Logouts.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Markdowns.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Markdowns.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Marquees.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Marquees.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Marquees.razor.css
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Menus.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Menus.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Menus.razor.css
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Messages.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Messages.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/MindMaps/MindMaps.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/MindMaps/MindMaps.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/MindMaps/MindMapsSamples.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Modals.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Modals.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/MouseFollowers.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/MouseFollowers.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/MouseFollowers.razor.css
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/MultiSelects.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/MultiSelects.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/MultiSelects.razor.css
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Navigation.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Navigation.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Notifications.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Notifications.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/OnScreenKeyboards.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/OnScreenKeyboards.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/OnScreenKeyboards.razor.css
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Paginations.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Paginations.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/PdfReaders.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/PdfReaders.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/PopoverConfirms.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/PopoverConfirms.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Popovers.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Popovers.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Popovers.razor.css
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Practices/Dashboard.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Practices/Dashboard.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Practices/Dashboard.razor.css
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Practices/DashboardData.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Practices/LoginAndRegister/Template6.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Practices/LoginAndRegister/Template6.razor.css
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Practices/LoginAndRegister/Template7.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Practices/LoginAndRegister/Template7.razor.css
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Practices/LoginAndRegister/Template8.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Practices/LoginAndRegister/Template8.razor.css
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Practices/LoginAndRegister/Template9.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Practices/LoginAndRegister/Template9.razor.css
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Practices/Waterfall.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Practices/Waterfall.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Practices/Waterfall.razor.css
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Practices/_Imports.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Print.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/PrintView.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/PrintView.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/PrintView.razor.css
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Progress.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Progress.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/PulseButtons.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/QRCodes.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/QRCodes.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/QueryBuilders.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/QueryBuilders.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Radios.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Radios.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Rates.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Rates.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Reconnectors.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Reconnectors.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Repeaters.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Repeaters.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Responsives.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Responsives.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/RibbonTabs.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/RibbonTabs.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Rows.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Rows.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Scrolls.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Scrolls.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Scrolls.razor.css
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/SearchDialogs.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/SearchDialogs.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Searches.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Searches.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Segmenteds.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Segmenteds.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/SelectTrees.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/SelectTrees.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Selects.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Selects.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Selects.razor.css
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/SignaturePadPageResponsive.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/SignaturePads.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/SignaturePads.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Skeletons.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Skeletons.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Skeletons.razor.css
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/SlideButtons.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/SlideButtons.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/SlideButtons.razor.css
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Sliders.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Sliders.razor.css
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Speeches/Index.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Speeches/Index.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Speeches/Recognizers.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Speeches/Recognizers.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Speeches/SpeechWaves.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Speeches/SpeechWaves.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Speeches/Synthesizers.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Speeches/Synthesizers.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Spinners.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Spinners.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Splits.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Splits.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Splits.razor.css
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Splittings.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Splittings.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Splittings.razor.css
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Stacks.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Stacks.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Stacks.razor.css
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Steps.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Steps.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Steps.razor.css
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/SweetAlerts.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/SweetAlerts.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/SwitchButtons.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/SwitchButtons.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Switches.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Switches.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Table/Tables.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Table/Tables.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Table/TablesAutoRefresh.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Table/TablesAutoRefresh.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Table/TablesCell.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Table/TablesCell.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Table/TablesCell.razor.css
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Table/TablesColumn.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Table/TablesColumn.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Table/TablesColumnDrag.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Table/TablesColumnDrag.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Table/TablesColumnList.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Table/TablesColumnList.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Table/TablesColumnResizing.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Table/TablesColumnResizing.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Table/TablesColumnTemplate.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Table/TablesColumnTemplate.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Table/TablesDetailRow.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Table/TablesDetailRow.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Table/TablesDialog.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Table/TablesDialog.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Table/TablesDynamic.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Table/TablesDynamic.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Table/TablesDynamicExcel.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Table/TablesDynamicExcel.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Table/TablesDynamicObject.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Table/TablesDynamicObject.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Table/TablesEdit.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Table/TablesEdit.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Table/TablesExcel.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Table/TablesExcel.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Table/TablesExport.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Table/TablesExport.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Table/TablesFilter.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Table/TablesFilter.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Table/TablesFixedColumn.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Table/TablesFixedColumn.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Table/TablesFixedHeader.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Table/TablesFixedHeader.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Table/TablesFooter.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Table/TablesFooter.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Table/TablesFooter.razor.css
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Table/TablesHeader.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Table/TablesHeader.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Table/TablesLoading.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Table/TablesLoading.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Table/TablesLookup.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Table/TablesLookup.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Table/TablesNameDrop.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Table/TablesNameDrop.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Table/TablesPages.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Table/TablesPages.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Table/TablesRow.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Table/TablesRow.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Table/TablesRow.razor.css
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Table/TablesSearch.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Table/TablesSearch.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Table/TablesSelection.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Table/TablesSelection.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Table/TablesToolbar.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Table/TablesToolbar.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Table/TablesTracking.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Table/TablesTracking.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Table/TablesTree.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Table/TablesTree.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Table/TablesVirtualization.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Table/TablesVirtualization.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Table/TablesVirtualization.razor.css
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Table/TablesWrap.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Table/TablesWrap.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Tabs.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Tabs.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Tabs.razor.css
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Tags.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Tags.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/TextAreas.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/TextAreas.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/TextAreas.razor.css
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Timelines.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Timelines.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Timers.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Timers.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Titles.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Titles.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Toasts.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Toasts.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Toasts.razor.css
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Toggles.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Toggles.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Tooltips.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Tooltips.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Tooltips.razor.css
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Topologies.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Topologies.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Topologies.razor.css
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Topologies.razor.js
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Transfers.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Transfers.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Transitions.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Transitions.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/TreeViews.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/TreeViews.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Trees.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Trees.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Uploads.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/Uploads.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/ValidateForms.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/ValidateForms.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/VideoPlayers.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/VideoPlayers.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/WebSerials.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/WebSerials.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/WebSpeechs.razor
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/WebSpeechs.razor.cs
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/WebSpeechs.razor.css
create mode 100644 src/BootstrapBlazor.Server/Components/Samples/_Imports.razor
create mode 100644 src/BootstrapBlazor.Server/Data/AttributeItem.cs
create mode 100644 src/BootstrapBlazor.Server/Data/CalendarDemoDataHelper.cs
create mode 100644 src/BootstrapBlazor.Server/Data/CustomDynamicColumnsObjectData.cs
create mode 100644 src/BootstrapBlazor.Server/Data/CustomDynamicData.cs
create mode 100644 src/BootstrapBlazor.Server/Data/EventItem.cs
create mode 100644 src/BootstrapBlazor.Server/Data/Foo.cs
create mode 100644 src/BootstrapBlazor.Server/Data/FooSearchModel.cs
create mode 100644 src/BootstrapBlazor.Server/Data/GiteePushBody.cs
create mode 100644 src/BootstrapBlazor.Server/Data/LoginModel.cs
create mode 100644 src/BootstrapBlazor.Server/Data/Menus.cs
create mode 100644 src/BootstrapBlazor.Server/Data/MessageItem.cs
create mode 100644 src/BootstrapBlazor.Server/Data/MethodItem.cs
create mode 100644 src/BootstrapBlazor.Server/Data/TreeDataFoo.cs
create mode 100644 src/BootstrapBlazor.Server/Data/TreeFoo.cs
create mode 100644 src/BootstrapBlazor.Server/Data/User.cs
create mode 100644 src/BootstrapBlazor.Server/Data/WeatherForecast.cs
create mode 100644 src/BootstrapBlazor.Server/Data/WebsiteOptions.cs
create mode 100644 src/BootstrapBlazor.Server/Extensions/CacheManagerExtensions.cs
create mode 100644 src/BootstrapBlazor.Server/Extensions/DispatchEntryExtensions.cs
create mode 100644 src/BootstrapBlazor.Server/Extensions/JSRuntimeExtensions.cs
create mode 100644 src/BootstrapBlazor.Server/Extensions/MenusLocalizerExtensions.cs
create mode 100644 src/BootstrapBlazor.Server/Locales/en.json
create mode 100644 src/BootstrapBlazor.Server/Locales/zh.json
delete mode 100644 src/BootstrapBlazor.Server/Pages/_Host.cshtml
delete mode 100644 src/BootstrapBlazor.Server/Pages/_Layout.cshtml
create mode 100644 src/BootstrapBlazor.Server/Services/CodeSnippetService.cs
create mode 100644 src/BootstrapBlazor.Server/Services/DashboardService.cs
create mode 100644 src/BootstrapBlazor.Server/Services/DemoLookupService.cs
create mode 100644 src/BootstrapBlazor.Server/Services/FanControllerDataService.cs
create mode 100644 src/BootstrapBlazor.Server/Services/MenuService.cs
create mode 100644 src/BootstrapBlazor.Server/Services/MockAuthenticationStateProvider.cs
create mode 100644 src/BootstrapBlazor.Server/Services/MockDataTableDynamicService.cs
create mode 100644 src/BootstrapBlazor.Server/Services/PackageVersionService.cs
create mode 100644 src/BootstrapBlazor.Server/Services/TableDemoDataService.cs
create mode 100644 src/BootstrapBlazor.Server/Services/WeatherForecastService.cs
create mode 100644 src/BootstrapBlazor.Server/docs.json
create mode 100644 src/BootstrapBlazor.Server/menus.json
create mode 100644 src/BootstrapBlazor.Server/topology.json
create mode 100644 src/BootstrapBlazor.Server/versionconfig.json
diff --git a/BootstrapBlazor.sln b/BootstrapBlazor.sln
index 025b732e5..4b923494e 100644
--- a/BootstrapBlazor.sln
+++ b/BootstrapBlazor.sln
@@ -26,14 +26,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "windows", "windows", "{4A52
scripts\windows\push.ps1 = scripts\windows\push.ps1
EndProjectSection
EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "dist", "dist", "{63E887C6-4610-4ED3-91F4-62EFDE7F442F}"
- ProjectSection(SolutionItems) = preProject
- dist\.gitattributes = dist\.gitattributes
- dist\.nojekyll = dist\.nojekyll
- dist\.spa = dist\.spa
- dist\404.html = dist\404.html
- EndProjectSection
-EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "wasm", "wasm", "{B84D315E-967D-4FBF-9B72-1F3128155CB0}"
ProjectSection(SolutionItems) = preProject
scripts\wasm\sync.cmd = scripts\wasm\sync.cmd
@@ -56,8 +48,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BootstrapBlazor.Markdown",
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BootstrapBlazor.TableExport", "src\Extensions\Components\BootstrapBlazor.TableExport\BootstrapBlazor.TableExport.csproj", "{5ED0DD16-1583-4FC3-B2E9-FE5DBA98BD47}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BootstrapBlazor.Shared", "src\BootstrapBlazor.Shared\BootstrapBlazor.Shared.csproj", "{C63F35FD-FE14-4517-9457-9DA43F0DCB9E}"
-EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BootstrapBlazor.Server", "src\BootstrapBlazor.Server\BootstrapBlazor.Server.csproj", "{1ED371F3-2B28-4B2D-91B8-0C00DA42CB65}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BootstrapBlazor.WebAssembly.ClientHost", "src\Wasm\BootstrapBlazor.WebAssembly.ClientHost\BootstrapBlazor.WebAssembly.ClientHost.csproj", "{0556D9AB-8673-4248-8817-4D99F4DCC568}"
@@ -155,10 +145,6 @@ Global
{5ED0DD16-1583-4FC3-B2E9-FE5DBA98BD47}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5ED0DD16-1583-4FC3-B2E9-FE5DBA98BD47}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5ED0DD16-1583-4FC3-B2E9-FE5DBA98BD47}.Release|Any CPU.Build.0 = Release|Any CPU
- {C63F35FD-FE14-4517-9457-9DA43F0DCB9E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {C63F35FD-FE14-4517-9457-9DA43F0DCB9E}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {C63F35FD-FE14-4517-9457-9DA43F0DCB9E}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {C63F35FD-FE14-4517-9457-9DA43F0DCB9E}.Release|Any CPU.Build.0 = Release|Any CPU
{1ED371F3-2B28-4B2D-91B8-0C00DA42CB65}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1ED371F3-2B28-4B2D-91B8-0C00DA42CB65}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1ED371F3-2B28-4B2D-91B8-0C00DA42CB65}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -296,7 +282,6 @@ Global
{337FABF3-4318-408E-8544-C0F20D0197A1} = {CD062AB6-244D-402A-8F33-C37DAC5856CC}
{EEB9751A-5C06-4725-8037-FA9C0F140018} = {CD062AB6-244D-402A-8F33-C37DAC5856CC}
{5ED0DD16-1583-4FC3-B2E9-FE5DBA98BD47} = {CD062AB6-244D-402A-8F33-C37DAC5856CC}
- {C63F35FD-FE14-4517-9457-9DA43F0DCB9E} = {A2182155-43ED-44C1-BF6F-1B70EBD2DFFE}
{1ED371F3-2B28-4B2D-91B8-0C00DA42CB65} = {A2182155-43ED-44C1-BF6F-1B70EBD2DFFE}
{0556D9AB-8673-4248-8817-4D99F4DCC568} = {C8E79F4C-8C55-4E13-96B5-3D2BD6A07B74}
{FFFD2EB7-AE88-4DAD-A825-528B2CEFB4B5} = {C8E79F4C-8C55-4E13-96B5-3D2BD6A07B74}
diff --git a/BootstrapBlazor.slnf b/BootstrapBlazor.slnf
index 8b92a0230..26850ac2c 100644
--- a/BootstrapBlazor.slnf
+++ b/BootstrapBlazor.slnf
@@ -3,7 +3,6 @@
"path": "BootstrapBlazor.sln",
"projects": [
"src\\BootstrapBlazor.Server\\BootstrapBlazor.Server.csproj",
- "src\\BootstrapBlazor.Shared\\BootstrapBlazor.Shared.csproj",
"src\\BootstrapBlazor\\BootstrapBlazor.csproj",
"test\\UniTest.Sass\\UniTest.Sass.csproj",
"test\\UnitTest\\UnitTest.csproj"
diff --git a/dist/.gitattributes b/dist/.gitattributes
deleted file mode 100644
index 305220871..000000000
--- a/dist/.gitattributes
+++ /dev/null
@@ -1,63 +0,0 @@
-###############################################################################
-# Set default behavior to automatically normalize line endings.
-###############################################################################
-* binary
-
-###############################################################################
-# Set default behavior for command prompt diff.
-#
-# This is need for earlier builds of msysgit that does not have it on by
-# default for csharp files.
-# Note: This is only used by command line
-###############################################################################
-#*.cs diff=csharp
-
-###############################################################################
-# Set the merge driver for project and solution files
-#
-# Merging from the command prompt will add diff markers to the files if there
-# are conflicts (Merging from VS is not affected by the settings below, in VS
-# the diff markers are never inserted). Diff markers may cause the following
-# file extensions to fail to load in VS. An alternative would be to treat
-# these files as binary and thus will always conflict and require user
-# intervention with every merge. To do so, just uncomment the entries below
-###############################################################################
-#*.sln merge=binary
-#*.csproj merge=binary
-#*.vbproj merge=binary
-#*.vcxproj merge=binary
-#*.vcproj merge=binary
-#*.dbproj merge=binary
-#*.fsproj merge=binary
-#*.lsproj merge=binary
-#*.wixproj merge=binary
-#*.modelproj merge=binary
-#*.sqlproj merge=binary
-#*.wwaproj merge=binary
-
-###############################################################################
-# behavior for image files
-#
-# image files are treated as binary by default.
-###############################################################################
-#*.jpg binary
-#*.png binary
-#*.gif binary
-
-###############################################################################
-# diff behavior for common document formats
-#
-# Convert binary document formats to text before diffing them. This feature
-# is only available from the command line. Turn it on by uncommenting the
-# entries below.
-###############################################################################
-#*.doc diff=astextplain
-#*.DOC diff=astextplain
-#*.docx diff=astextplain
-#*.DOCX diff=astextplain
-#*.dot diff=astextplain
-#*.DOT diff=astextplain
-#*.pdf diff=astextplain
-#*.PDF diff=astextplain
-#*.rtf diff=astextplain
-#*.RTF diff=astextplain
\ No newline at end of file
diff --git a/dist/.nojekyll b/dist/.nojekyll
deleted file mode 100644
index e69de29bb..000000000
diff --git a/dist/.spa b/dist/.spa
deleted file mode 100644
index 38de19e22..000000000
--- a/dist/.spa
+++ /dev/null
@@ -1,2 +0,0 @@
-This file is used to enable gitee pages' spa mode.
-https://gitee.com/help/articles/4237
\ No newline at end of file
diff --git a/dist/404.html b/dist/404.html
deleted file mode 100644
index 621c7d370..000000000
--- a/dist/404.html
+++ /dev/null
@@ -1,40 +0,0 @@
-
-
-
-
- Single Page Apps for GitHub Pages
-
-
-
-
-
diff --git a/dist/gitee-pages/404.html b/dist/gitee-pages/404.html
deleted file mode 100644
index 593e9e48a..000000000
--- a/dist/gitee-pages/404.html
+++ /dev/null
@@ -1,72 +0,0 @@
-
-
-
-
-
- Bootstrap Blazor 演示网站
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
精彩即将呈现
-
-
-
-
-
-
- An error has occurred. This application may no longer respond until reloaded.
-
-
- An unhandled exception has occurred. See browser dev tools for details.
-
-
Reload
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/exclusion.dic b/exclusion.dic
index cbf0820da..507738110 100644
--- a/exclusion.dic
+++ b/exclusion.dic
@@ -38,3 +38,8 @@ xmark
Func
Prev
Textarea
+rendermode
+motronic
+webassembly
+netcore
+oscs
diff --git a/scripts/linux/nginx.conf b/scripts/linux/nginx.conf
index c459cc593..f85b97078 100644
--- a/scripts/linux/nginx.conf
+++ b/scripts/linux/nginx.conf
@@ -1,3 +1,16 @@
+#user nobody;
+worker_processes 1;
+
+#error_log logs/error.log;
+#error_log logs/error.log notice;
+#error_log logs/error.log info;
+
+#pid logs/nginx.pid;
+
+events {
+ worker_connections 1024;
+}
+
http {
upstream blazor {
server localhost:50853;
diff --git a/src/BootstrapBlazor.Server/AIChat/Chats.razor b/src/BootstrapBlazor.Server/AIChat/Chats.razor
index f5114d006..f6b6f24aa 100644
--- a/src/BootstrapBlazor.Server/AIChat/Chats.razor
+++ b/src/BootstrapBlazor.Server/AIChat/Chats.razor
@@ -2,7 +2,7 @@
@using Azure.AI.OpenAI
@using BootstrapBlazor.Server.OAuth;
@inherits BootstrapModuleComponentBase
-@attribute [JSModuleAutoLoader("./AIChat/Chats.razor.js")]
+@attribute [JSModuleAutoLoader("AIChat/Chats.razor.js")]
@Localizer["ChatsTitle"]
diff --git a/src/BootstrapBlazor.Server/BootstrapBlazor.Server.csproj b/src/BootstrapBlazor.Server/BootstrapBlazor.Server.csproj
index 2bb93f190..cf63b2592 100644
--- a/src/BootstrapBlazor.Server/BootstrapBlazor.Server.csproj
+++ b/src/BootstrapBlazor.Server/BootstrapBlazor.Server.csproj
@@ -5,6 +5,27 @@
dd866c36-9a9b-4dda-bce0-44c91d3094cc
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -12,17 +33,48 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
-
-
-
+
+
+
+
+
+
diff --git a/src/BootstrapBlazor.Server/Components/Components/AttributeTable.razor b/src/BootstrapBlazor.Server/Components/Components/AttributeTable.razor
new file mode 100644
index 000000000..48f3aabc9
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Components/AttributeTable.razor
@@ -0,0 +1,13 @@
+
diff --git a/src/BootstrapBlazor.Server/Components/Components/AttributeTable.razor.cs b/src/BootstrapBlazor.Server/Components/Components/AttributeTable.razor.cs
new file mode 100644
index 000000000..74f4264e4
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Components/AttributeTable.razor.cs
@@ -0,0 +1,37 @@
+// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+// Website: https://www.blazor.zone or https://argozhang.github.io/
+
+namespace BootstrapBlazor.Server.Components.Components;
+
+///
+///
+///
+public sealed partial class AttributeTable
+{
+ [Inject]
+ [NotNull]
+ private IStringLocalizer? Localizer { get; set; }
+
+ ///
+ ///
+ ///
+ [Parameter]
+ [NotNull]
+ public string? Title { get; set; }
+
+ ///
+ ///
+ ///
+ [Parameter] public IEnumerable? Items { get; set; }
+
+ ///
+ /// OnInitialized 方法
+ ///
+ protected override void OnInitialized()
+ {
+ base.OnInitialized();
+
+ Title ??= Localizer[nameof(Title)];
+ }
+}
diff --git a/src/BootstrapBlazor.Server/Components/Components/BBLogo.razor b/src/BootstrapBlazor.Server/Components/Components/BBLogo.razor
new file mode 100644
index 000000000..fa02c2cfa
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Components/BBLogo.razor
@@ -0,0 +1 @@
+
diff --git a/src/BootstrapBlazor.Server/Components/Components/BBLogo.razor.css b/src/BootstrapBlazor.Server/Components/Components/BBLogo.razor.css
new file mode 100644
index 000000000..13147bf8b
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Components/BBLogo.razor.css
@@ -0,0 +1,8 @@
+.bb-icon {
+ width: 42px;
+ height: auto;
+ border-radius: var(--bs-border-radius);
+ background-color: var(--bs-info);
+ border: solid 1px #fff;
+ margin-right: 1rem;
+}
diff --git a/src/BootstrapBlazor.Server/Components/Components/BlazorReconnector.razor b/src/BootstrapBlazor.Server/Components/Components/BlazorReconnector.razor
new file mode 100644
index 000000000..d6beae78a
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Components/BlazorReconnector.razor
@@ -0,0 +1,78 @@
+@inject IOptionsMonitor WebsiteOption
+
+
+
+
+
+
+ @RenderBootstrapBlazor
+
+
Reconnector 组件
+
正在尝试重新连接服务器
+
服务器正在更新新版本,稍等一会儿即可提供服务,或者 F12 打开 Developer tools 查看 控制台 是否有错误输出,请扫描左侧二维码加群与管理员联系
+
+
+
+
+
+
+
+
+
+ @RenderBootstrapBlazor
+
+
Reconnector 组件
+
与服务器连接失败
+
请确认网络是否正常,或者 F12 打开 Developer tools 查看 控制台 是否有错误输出,请扫描左侧二维码加群与管理员联系
+
+
+
+
+
+
+
+
+
+ @RenderBootstrapBlazor
+
+
Reconnector 组件
+
服务器拒绝连接
+
所有的连接尝试都被拒绝了,这很有可能是由于网络问题或者服务器问题引起的,请扫描左侧二维码加群与管理员联系
+
+
+
+
+
+
+
+@code {
+ private string TemplateUrl => $"{WebsiteOption.CurrentValue.BootstrapBlazorLink}/wikis/%E9%A1%B9%E7%9B%AE%E6%A8%A1%E6%9D%BF%E4%BD%BF%E7%94%A8%E6%95%99%E7%A8%8B";
+
+ RenderFragment RenderBootstrapBlazor =>
+ @
+
Bootstrap Blazor UI 组件库
+
+
+
一套基于 Bootstrap 样式的企业级 Blazor UI 组件库,支持 Server 与 WebAssembly
+
适配移动端支持各种主流浏览器以及移动端,适配 ABP ,同时支持 NET5/NET6/NET7
+
+
+
+
+
+
+
;
+}
diff --git a/src/BootstrapBlazor.Server/Components/Components/CSS.razor b/src/BootstrapBlazor.Server/Components/Components/CSS.razor
new file mode 100644
index 000000000..49ad9818b
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Components/CSS.razor
@@ -0,0 +1,4 @@
+
+
CSS Variables
+ @ChildContent
+
diff --git a/src/BootstrapBlazor.Server/Components/Components/CSS.razor.cs b/src/BootstrapBlazor.Server/Components/Components/CSS.razor.cs
new file mode 100644
index 000000000..7a036a7ed
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Components/CSS.razor.cs
@@ -0,0 +1,17 @@
+// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+// Website: https://www.blazor.zone or https://argozhang.github.io/
+
+namespace BootstrapBlazor.Server.Components.Components;
+
+///
+/// CSS 组件
+///
+public partial class CSS
+{
+ ///
+ /// 获得/设置 子内容
+ ///
+ [Parameter]
+ public RenderFragment? ChildContent { get; set; }
+}
diff --git a/src/BootstrapBlazor.Server/Components/Components/CalendarCrewCell.razor b/src/BootstrapBlazor.Server/Components/Components/CalendarCrewCell.razor
new file mode 100644
index 000000000..e03b46cf1
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Components/CalendarCrewCell.razor
@@ -0,0 +1,12 @@
+
+
@Value.CellValue.Day
+ @if (Value.CellValue.Month == Value.CalendarValue.Month)
+ {
+
+ @foreach (var tag in Crews)
+ {
+
@tag.Name @tag.Value
+ }
+
+ }
+
diff --git a/src/BootstrapBlazor.Server/Components/Components/CalendarCrewCell.razor.cs b/src/BootstrapBlazor.Server/Components/Components/CalendarCrewCell.razor.cs
new file mode 100644
index 000000000..0d3774037
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Components/CalendarCrewCell.razor.cs
@@ -0,0 +1,56 @@
+// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+// Website: https://www.blazor.zone or https://argozhang.github.io/
+
+namespace BootstrapBlazor.Server.Components.Components;
+
+///
+///
+///
+public partial class CalendarCrewCell
+{
+ ///
+ /// 获得/设置 单元格值
+ ///
+ [Parameter]
+ [NotNull]
+ public CalendarCellValue? Value { get; set; }
+
+ ///
+ ///
+ ///
+ [Parameter]
+ public EventCallback ValueChanged { get; set; }
+
+ ///
+ ///
+ ///
+ [Parameter]
+ [EditorRequired]
+ [NotNull]
+ public List? Crews { get; set; }
+
+ [Inject]
+ [NotNull]
+ private DialogService? DialogService { get; set; }
+
+ private async Task OnClickCell()
+ {
+ await DialogService.Show(new DialogOption()
+ {
+ Title = $"明细查看 - {Value.CellValue:yyyy-MM-dd}",
+ Component = BootstrapDynamicComponent.CreateComponent(new Dictionary()
+ {
+ [nameof(Value)] = Value,
+ [nameof(Crews)] = Crews
+ }),
+ OnCloseAsync = async () =>
+ {
+ if (ValueChanged.HasDelegate)
+ {
+ await ValueChanged.InvokeAsync(Value);
+ }
+ }
+ });
+ }
+}
diff --git a/src/BootstrapBlazor.Server/Components/Components/CalendarCrewCell.razor.css b/src/BootstrapBlazor.Server/Components/Components/CalendarCrewCell.razor.css
new file mode 100644
index 000000000..b4e62c5a2
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Components/CalendarCrewCell.razor.css
@@ -0,0 +1,3 @@
+.calendar-day {
+ --bb-calendar-cell-height: 101px;
+}
diff --git a/src/BootstrapBlazor.Server/Components/Components/CalendarCrewDialogBody.razor b/src/BootstrapBlazor.Server/Components/Components/CalendarCrewDialogBody.razor
new file mode 100644
index 000000000..88d36d728
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Components/CalendarCrewDialogBody.razor
@@ -0,0 +1,19 @@
+
+ @foreach (var crew in Crews)
+ {
+
+
+ @crew.Name
+
+
+
+ OnUpdateValue(crew, 1)">
+
+
+ OnUpdateValue(crew, -1)">
+
+
+
+
+ }
+
diff --git a/src/BootstrapBlazor.Server/Components/Components/CalendarCrewDialogBody.razor.cs b/src/BootstrapBlazor.Server/Components/Components/CalendarCrewDialogBody.razor.cs
new file mode 100644
index 000000000..47e11d335
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Components/CalendarCrewDialogBody.razor.cs
@@ -0,0 +1,32 @@
+// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+// Website: https://www.blazor.zone or https://argozhang.github.io/
+
+namespace BootstrapBlazor.Server.Components.Components;
+
+///
+///
+///
+public partial class CalendarCrewDialogBody
+{
+ ///
+ /// 获得/设置 单元格值
+ ///
+ [Parameter]
+ [EditorRequired]
+ [NotNull]
+ public CalendarCellValue? Value { get; set; }
+
+ ///
+ ///
+ ///
+ [Parameter]
+ [EditorRequired]
+ [NotNull]
+ public List? Crews { get; set; }
+
+ private static void OnUpdateValue(Crew crew, int interval)
+ {
+ crew.Value += interval;
+ }
+}
diff --git a/src/BootstrapBlazor.Server/Components/Components/CalendarCrewDialogBody.razor.css b/src/BootstrapBlazor.Server/Components/Components/CalendarCrewDialogBody.razor.css
new file mode 100644
index 000000000..27b0ce090
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Components/CalendarCrewDialogBody.razor.css
@@ -0,0 +1,35 @@
+.actions {
+ border: 1px solid var(--bs-purple);
+ border-radius: var(--bs-border-radius);
+ padding: 1px 1rem;
+}
+
+ .actions > span {
+ cursor: pointer;
+ border-radius: 50%;
+ width: 20px;
+ height: 20px;
+ display: inline-flex;
+ justify-content: center;
+ align-items: center;
+ transition: background-color .3s linear;
+ }
+
+ .actions > span:hover {
+ background-color: var(--bs-purple);
+ color: #fff;
+ }
+
+ .actions > span:not(:last-child) {
+ margin-right: .5rem;
+ }
+
+.crew:not(:last-child) {
+ margin-bottom: .5rem;
+}
+
+.crew > input {
+ max-width: 2rem;
+ margin-right: 1rem;
+ border: none;
+}
diff --git a/src/BootstrapBlazor.Server/Components/Components/CommitItem.razor b/src/BootstrapBlazor.Server/Components/Components/CommitItem.razor
new file mode 100644
index 000000000..62d6b2fe0
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Components/CommitItem.razor
@@ -0,0 +1,7 @@
+
+ @Timestamp
+ 共 @TotalCount 个提交
+
+提交作者: @Author
+分支名称: @Branch
+
diff --git a/src/BootstrapBlazor.Server/Components/Components/CommitItem.razor.cs b/src/BootstrapBlazor.Server/Components/Components/CommitItem.razor.cs
new file mode 100644
index 000000000..3441a4b7b
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Components/CommitItem.razor.cs
@@ -0,0 +1,49 @@
+// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+// Website: https://www.blazor.zone or https://argozhang.github.io/
+namespace BootstrapBlazor.Server.Components.Components;
+
+///
+///
+///
+public partial class CommitItem
+{
+ ///
+ ///
+ ///
+ [Parameter]
+ [NotNull]
+ [EditorRequired]
+ public GiteePostBody? Item { get; set; }
+
+ private string? Author { get; set; }
+
+ private string? Timestamp { get; set; }
+
+ private string? Message { get; set; }
+
+ private string? Url { get; set; }
+
+ private string? Branch { get; set; }
+
+ private string? TotalCount { get; set; }
+
+ ///
+ /// OnInitialized 方法
+ ///
+ protected override void OnInitialized()
+ {
+ base.OnInitialized();
+
+ var commit = Item.HeadCommit;
+ TotalCount = Item.Commits?.Count.ToString() ?? "1";
+ if (commit != null)
+ {
+ Timestamp = commit.Timestamp.ToString("yyyy-MM-dd HH:mm:ss");
+ Author = commit.Author.Name;
+ Message = commit.Message;
+ Url = commit.Url;
+ Branch = Item.GetBranchName();
+ }
+ }
+}
diff --git a/src/BootstrapBlazor.Server/Components/Components/ComponentCard.razor b/src/BootstrapBlazor.Server/Components/Components/ComponentCard.razor
new file mode 100644
index 000000000..04463ebb2
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Components/ComponentCard.razor
@@ -0,0 +1,8 @@
+
diff --git a/src/BootstrapBlazor.Server/Components/Components/ComponentCard.razor.cs b/src/BootstrapBlazor.Server/Components/Components/ComponentCard.razor.cs
new file mode 100644
index 000000000..a84c827c6
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Components/ComponentCard.razor.cs
@@ -0,0 +1,60 @@
+// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+// Website: https://www.blazor.zone or https://argozhang.github.io/
+
+namespace BootstrapBlazor.Server.Components.Components;
+
+///
+///
+///
+public sealed partial class ComponentCard
+{
+ private string ImageUrl => $"./images/{Image}";
+
+ private string? ClassString => CssBuilder.Default("col-12 col-sm-6 col-md-4 col-lg-3")
+ .AddClass("d-none", IsHide)
+ .Build();
+
+ ///
+ /// 获得/设置 Header 文字
+ ///
+ [Parameter]
+ public string Text { get; set; } = "未设置";
+
+ ///
+ /// 获得/设置 组件图片
+ ///
+ [Parameter]
+ public string Image { get; set; } = "Divider.svg";
+
+ ///
+ /// 获得/设置 链接地址
+ ///
+ [Parameter]
+ public string? Url { get; set; }
+
+ [CascadingParameter]
+ private List? ComponentNames { get; set; }
+
+ [CascadingParameter]
+ private ComponentCategory? Parent { get; set; }
+
+ [CascadingParameter]
+ private string? SearchText { get; set; }
+
+ ///
+ /// OnInitialized 方法
+ ///
+ protected override void OnInitialized()
+ {
+ base.OnInitialized();
+
+ ComponentNames?.Add(Text);
+ Parent?.Add(this);
+ }
+
+ ///
+ ///
+ ///
+ internal bool IsHide => !string.IsNullOrEmpty(SearchText) && !Text.Contains(SearchText, StringComparison.OrdinalIgnoreCase);
+}
diff --git a/src/BootstrapBlazor.Server/Components/Components/ComponentCategory.razor b/src/BootstrapBlazor.Server/Components/Components/ComponentCategory.razor
new file mode 100644
index 000000000..d1a826ac7
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Components/ComponentCategory.razor
@@ -0,0 +1,21 @@
+
+
+ @Text
+
+ @CardCount
+
+
+
+ @if (!string.IsNullOrEmpty(Desc))
+ {
+
@Desc
+ }
+
+
+
+
+ @ChildContent
+
+
+
+
diff --git a/src/BootstrapBlazor.Server/Components/Components/ComponentCategory.razor.cs b/src/BootstrapBlazor.Server/Components/Components/ComponentCategory.razor.cs
new file mode 100644
index 000000000..8756e7b9d
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Components/ComponentCategory.razor.cs
@@ -0,0 +1,55 @@
+// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+// Website: https://www.blazor.zone or https://argozhang.github.io/
+
+namespace BootstrapBlazor.Server.Components.Components;
+
+///
+///
+///
+public sealed partial class ComponentCategory
+{
+ ///
+ ///
+ ///
+ [Parameter]
+ public RenderFragment? ChildContent { get; set; }
+
+ ///
+ ///
+ ///
+ [Parameter]
+ public string? Text { get; set; }
+
+ ///
+ ///
+ ///
+ [Parameter]
+ public string? Desc { get; set; }
+
+ private List Cards { get; } = new List();
+
+ internal void Add(ComponentCard card) => Cards.Add(card);
+
+ private int CardCount => Cards.Where(c => !c.IsHide).Count();
+
+ private bool IsRendered { get; set; }
+
+ private string? ClassString => CssBuilder.Default("coms-cate")
+ .AddClass("d-none", IsRendered && CardCount == 0)
+ .Build();
+
+ ///
+ ///
+ ///
+ ///
+ protected override void OnAfterRender(bool firstRender)
+ {
+ base.OnAfterRender(firstRender);
+
+ if (firstRender)
+ {
+ IsRendered = true;
+ }
+ }
+}
diff --git a/src/BootstrapBlazor.Server/Components/Components/ComponentCategory.razor.css b/src/BootstrapBlazor.Server/Components/Components/ComponentCategory.razor.css
new file mode 100644
index 000000000..5b5d02a15
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Components/ComponentCategory.razor.css
@@ -0,0 +1,46 @@
+.coms-cate {
+ position: relative;
+}
+
+ .coms-cate:not(:first-child) {
+ margin-top: 1rem;
+ }
+
+ .coms-cate ::deep .badge {
+ position: absolute;
+ top: 0;
+ margin-left: 1rem;
+ font-size: .65rem;
+ }
+
+.coms-demo {
+ margin-top: 1rem;
+}
+
+ .coms-demo ::deep .card {
+ width: 100%;
+ height: 100%;
+ transition: box-shadow .3s linear;
+ }
+
+ .coms-demo ::deep .card img {
+ max-width: calc(100%);
+ }
+
+ .coms-demo ::deep .card .card-header {
+ overflow: hidden;
+ white-space: nowrap;
+ }
+
+ .coms-demo ::deep .card .card-body {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ min-height: 200px;
+ }
+
+ .coms-demo ::deep a {
+ width: calc(100%);
+ height: calc(100%);
+ color: inherit;
+ }
diff --git a/src/BootstrapBlazor.Server/Components/Components/ContextMenuList.razor b/src/BootstrapBlazor.Server/Components/Components/ContextMenuList.razor
new file mode 100644
index 000000000..1818bf99f
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Components/ContextMenuList.razor
@@ -0,0 +1,16 @@
+
+ @foreach (var item in Items)
+ {
+
+ @item
+
+ }
+
+
+@code {
+ private List Items { get; } = new List() { "Test1", "Test2", "Test3" };
+
+ [CascadingParameter]
+ [NotNull]
+ private ContextMenuZone? Zone { get; set; }
+}
diff --git a/src/BootstrapBlazor.Server/Components/Components/Counter.razor b/src/BootstrapBlazor.Server/Components/Components/Counter.razor
new file mode 100644
index 000000000..598c4e4c0
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Components/Counter.razor
@@ -0,0 +1,14 @@
+Counter
+
+Current count: @currentCount
+
+Click me
+
+@code {
+ private int currentCount = 0;
+
+ private void IncrementCount()
+ {
+ currentCount++;
+ }
+}
diff --git a/src/BootstrapBlazor.Server/Components/Components/CultureChooser.razor b/src/BootstrapBlazor.Server/Components/Components/CultureChooser.razor
new file mode 100644
index 000000000..13e0ddfe2
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Components/CultureChooser.razor
@@ -0,0 +1,13 @@
+@inherits BootstrapComponentBase
+
+
+ @Label
+
+
+ @foreach (var kv in BootstrapOptions.CurrentValue.GetSupportedCultures())
+ {
+
+ }
+
+
+
diff --git a/src/BootstrapBlazor.Server/Components/Components/CultureChooser.razor.cs b/src/BootstrapBlazor.Server/Components/Components/CultureChooser.razor.cs
new file mode 100644
index 000000000..9569f95ff
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Components/CultureChooser.razor.cs
@@ -0,0 +1,98 @@
+// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+// Website: https://www.blazor.zone or https://argozhang.github.io/
+
+using Microsoft.Extensions.Options;
+using System.Globalization;
+
+namespace BootstrapBlazor.Server.Components.Components;
+
+///
+///
+///
+public partial class CultureChooser
+{
+ [Inject]
+ [NotNull]
+ private IOptionsMonitor? BootstrapOptions { get; set; }
+
+ [Inject]
+ [NotNull]
+ private IOptionsMonitor? WebsiteOption { get; set; }
+
+ [Inject]
+ [NotNull]
+ private IStringLocalizer? Localizer { get; set; }
+
+ [Inject]
+ [NotNull]
+ private NavigationManager? NavigationManager { get; set; }
+
+ private string? ClassString => CssBuilder.Default("culture-selector")
+ .AddClassFromAttributes(AdditionalAttributes)
+ .Build();
+
+ private string SelectedCulture { get; set; } = CultureInfo.CurrentUICulture.Name;
+
+ [NotNull]
+ private string? Label { get; set; }
+
+ ///
+ /// OnInitialized 方法
+ ///
+ protected override void OnInitialized()
+ {
+ base.OnInitialized();
+
+ Label ??= Localizer[nameof(Label)];
+ }
+
+ private async Task SetCulture(SelectedItem item)
+ {
+ if (OperatingSystem.IsBrowser())
+ {
+ var cultureName = item.Value;
+ if (cultureName != CultureInfo.CurrentCulture.Name)
+ {
+ await JSRuntime.SetCulture(cultureName);
+ var culture = new CultureInfo(cultureName);
+ CultureInfo.CurrentCulture = culture;
+ CultureInfo.CurrentUICulture = culture;
+
+ NavigationManager.NavigateTo(NavigationManager.Uri, forceLoad: true);
+ }
+ }
+ else
+ {
+ // 使用 api 方式 适用于 Server-Side 模式
+ if (SelectedCulture != item.Value)
+ {
+ var culture = item.Value;
+ var uri = new Uri(NavigationManager.Uri).GetComponents(UriComponents.PathAndQuery, UriFormat.Unescaped);
+ var query = $"?culture={Uri.EscapeDataString(culture)}&redirectUri={Uri.EscapeDataString(uri)}";
+
+ // use a path that matches your culture redirect controller from the previous steps
+ NavigationManager.NavigateTo("/Culture/SetCulture" + query, forceLoad: true);
+ }
+ }
+ }
+
+ private static string GetDisplayName(CultureInfo culture)
+ {
+ string? ret;
+ if (OperatingSystem.IsBrowser())
+ {
+ ret = culture.Name switch
+ {
+ "zh-CN" => "中文(中国)",
+ "en-US" => "English (United States)",
+ _ => ""
+ };
+ }
+ else
+ {
+ ret = culture.NativeName;
+ }
+ return ret;
+ }
+}
diff --git a/src/BootstrapBlazor.Server/Components/Components/CultureChooser.razor.css b/src/BootstrapBlazor.Server/Components/Components/CultureChooser.razor.css
new file mode 100644
index 000000000..764961680
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Components/CultureChooser.razor.css
@@ -0,0 +1,18 @@
+.culture-selector {
+ display: flex;
+ align-items: center;
+}
+
+ .culture-selector span {
+ margin: 0;
+ color: var(--bs-navbar-color);
+ opacity: 0.85;
+ }
+
+ .culture-selector ::deep .select {
+ width: 210px;
+ }
+
+ .culture-selector ::deep .dropdown-menu {
+ --bs-dropdown-link-active-bg: #7532f9;
+ }
diff --git a/src/BootstrapBlazor.Server/Components/Components/CustomerFilter.razor b/src/BootstrapBlazor.Server/Components/Components/CustomerFilter.razor
new file mode 100644
index 000000000..7542f14d1
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Components/CustomerFilter.razor
@@ -0,0 +1,50 @@
+@inherits FilterBase
+
+
+
+@code {
+ private int Value = 10;
+
+ ///
+ /// OnInitialized 方法
+ ///
+ protected override void OnInitialized()
+ {
+ base.OnInitialized();
+
+ if (TableFilter != null) TableFilter.ShowMoreButton = false;
+
+ Items = new SelectedItem[]
+ {
+ new SelectedItem { Value = "10", Text = "大于 10" },
+ new SelectedItem { Value = "50", Text = "大于 50" },
+ new SelectedItem { Value = "100", Text = "大于 100" }
+ };
+ }
+
+ ///
+ /// 重置过滤条件方法
+ ///
+ public override void Reset()
+ {
+ Value = 10;
+
+ StateHasChanged();
+ }
+
+ ///
+ /// 生成过滤条件方法
+ ///
+ ///
+ public override FilterKeyValueAction GetFilterConditions()
+ {
+ var filter = new FilterKeyValueAction() { Filters = new() };
+ filter.Filters.Add(new FilterKeyValueAction()
+ {
+ FieldKey = FieldKey,
+ FieldValue = Value,
+ FilterAction = FilterAction.GreaterThan
+ });
+ return filter;
+ }
+}
diff --git a/src/BootstrapBlazor.Server/Components/Components/CustomerSelectDialog.razor b/src/BootstrapBlazor.Server/Components/Components/CustomerSelectDialog.razor
new file mode 100644
index 000000000..2e99dfcb6
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Components/CustomerSelectDialog.razor
@@ -0,0 +1,8 @@
+
diff --git a/src/BootstrapBlazor.Server/Components/Components/CustomerSelectDialog.razor.cs b/src/BootstrapBlazor.Server/Components/Components/CustomerSelectDialog.razor.cs
new file mode 100644
index 000000000..807100458
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Components/CustomerSelectDialog.razor.cs
@@ -0,0 +1,50 @@
+// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+// Website: https://www.blazor.zone or https://argozhang.github.io/
+
+namespace BootstrapBlazor.Server.Components.Components;
+
+///
+///
+///
+public partial class CustomerSelectDialog
+{
+ private IEnumerable? Items2;
+ private readonly IEnumerable Items3 = new SelectedItem[]
+ {
+ new SelectedItem ("", "请选择 ..."),
+ new SelectedItem ("Beijing", "北京"),
+ new SelectedItem ("Shanghai", "上海")
+ };
+
+ ///
+ /// 级联绑定菜单
+ ///
+ ///
+ private async Task OnCascadeBindSelectClick(SelectedItem item)
+ {
+ // 模拟异步通讯获取数据
+ await Task.Delay(100);
+ if (item.Value == "Beijing")
+ {
+ Items2 = new SelectedItem[]
+ {
+ new SelectedItem("1","朝阳区"),
+ new SelectedItem("2","海淀区"),
+ };
+ }
+ else if (item.Value == "Shanghai")
+ {
+ Items2 = new SelectedItem[]
+ {
+ new SelectedItem("1","静安区"),
+ new SelectedItem("2","黄浦区"),
+ };
+ }
+ else
+ {
+ Items2 = Enumerable.Empty();
+ }
+ StateHasChanged();
+ }
+}
diff --git a/src/BootstrapBlazor.Server/Components/Components/DataDialogComponent.razor b/src/BootstrapBlazor.Server/Components/Components/DataDialogComponent.razor
new file mode 100644
index 000000000..534f3eaa9
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Components/DataDialogComponent.razor
@@ -0,0 +1,77 @@
+@inject ToastService Toast
+
+同时通过传递数据主键获取数据后再显示的例子组件
+
+传递的参数主键为:@DataPrimaryId
+
+通过传递参数获取的数据为:
+
+@if (Model != null)
+{
+
+
+
+
+
+
+
+
+
+}
+
+@code {
+ [Inject]
+ [NotNull]
+ private IStringLocalizer? Localizer { get; set; }
+
+ [CascadingParameter(Name = "BodyContext")]
+ private object? DataPrimaryId { get; set; }
+
+ [CascadingParameter]
+ [NotNull]
+ private Modal? Dialog { get; set; }
+
+ private Foo? Model { get; set; }
+
+ [NotNull]
+ private List? Items { get; set; }
+
+ [NotNull]
+ private IEnumerable? Hobbys { get; set; }
+
+ ///
+ ///
+ ///
+ protected override void OnInitialized()
+ {
+ base.OnInitialized();
+
+ Items = Foo.GenerateFoo(Localizer);
+ Hobbys = Foo.GenerateHobbies(Localizer);
+ }
+
+ protected override void OnParametersSet()
+ {
+ base.OnParametersSet();
+
+ if (DataPrimaryId is int primaryId)
+ {
+ Model = Items.FirstOrDefault(i => i.Id == primaryId);
+ }
+ }
+
+ private async Task OnValidSubmit(EditContext model)
+ {
+ // do someting like save model into db
+
+ // 关闭弹窗
+ // close Dialog
+ await Dialog.Close();
+
+ // 显示 Toast 提示弹窗
+ await Toast.Show(new ToastOption() { Title = "保存数据", Content = "保存成功,4 秒后自动关闭" });
+ }
+}
diff --git a/src/BootstrapBlazor.Server/Components/Components/DemoBlock.razor b/src/BootstrapBlazor.Server/Components/Components/DemoBlock.razor
new file mode 100644
index 000000000..a0f682521
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Components/DemoBlock.razor
@@ -0,0 +1,29 @@
+@inherits IdComponentBase
+
+
+
+
+ @(new MarkupString(Introduction))
+
+ @Localizer["SubTitle"]
+
+
+
+ @ChildContent
+
+ @if (ShowCode)
+ {
+
+ }
+
+
diff --git a/src/BootstrapBlazor.Server/Components/Components/DemoBlock.razor.cs b/src/BootstrapBlazor.Server/Components/Components/DemoBlock.razor.cs
new file mode 100644
index 000000000..497fd7a88
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Components/DemoBlock.razor.cs
@@ -0,0 +1,75 @@
+// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+// Website: https://www.blazor.zone or https://argozhang.github.io/
+
+namespace BootstrapBlazor.Server.Components.Components;
+
+///
+///
+///
+public sealed partial class DemoBlock
+{
+ ///
+ /// 获得/设置 组件 Title 属性
+ ///
+ [Parameter]
+ [NotNull]
+ public string? Title { get; set; }
+
+ ///
+ /// 获得/设置 组件说明信息
+ ///
+ [Parameter]
+ public string Introduction { get; set; } = "未设置";
+
+ ///
+ /// 获得/设置 组件内容
+ ///
+ [Parameter]
+ public RenderFragment? ChildContent { get; set; }
+
+ ///
+ /// 获得/设置 是否显示代码块 默认 true 显示
+ ///
+ [Parameter]
+ public bool ShowCode { get; set; } = true;
+
+ ///
+ /// 获得/设置 Tooltip 提示信息文本
+ ///
+ [Parameter]
+ public string? TooltipText { get; set; }
+
+ ///
+ /// 获得/设置 友好链接锚点名称
+ ///
+ [Parameter]
+ public string? Name { get; set; }
+
+ [CascadingParameter(Name = "RazorFileName")]
+ private string? CodeFile { get; set; }
+
+ [Inject]
+ [NotNull]
+ private IStringLocalizer? Localizer { get; set; }
+
+ ///
+ ///
+ ///
+ protected override void OnParametersSet()
+ {
+ base.OnParametersSet();
+
+ Title ??= Localizer[nameof(Title)];
+ TooltipText ??= Localizer[nameof(TooltipText)];
+ }
+
+ private bool _showPreCode;
+
+ private void ShowPreCode()
+ {
+ _showPreCode = true;
+ }
+
+ private Task OnLoadConditionCheckAsync() => Task.FromResult(_showPreCode);
+}
diff --git a/src/BootstrapBlazor.Server/Components/Components/DemoBlock.razor.css b/src/BootstrapBlazor.Server/Components/Components/DemoBlock.razor.css
new file mode 100644
index 000000000..5f9412795
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Components/DemoBlock.razor.css
@@ -0,0 +1,116 @@
+.card {
+ transition: all .3s linear;
+}
+
+ .card:hover {
+ box-shadow: 0 0 8px 0 rgba(232,237,250,.6), 0 2px 4px 0 rgba(232,237,250,.5);
+ }
+
+ .card:hover .card-footer-control i {
+ margin-left: -1.5rem;
+ margin-left: -72px;
+ }
+
+ .card:hover .card-footer-control .card-text {
+ margin-left: 1rem;
+ }
+
+ .card:hover .card-footer-control .card-text:before {
+ opacity: 1;
+ }
+
+
+.card-footer {
+ background-color: transparent;
+}
+
+.card-footer-code {
+ margin: -.5rem -1rem 0 -1rem;
+ border-bottom: 1px solid rgba(0, 0, 0, 0.125);
+}
+
+ .card-footer-code.show + a {
+ margin-top: .5rem;
+ }
+
+ .card-footer-code .loading {
+ padding: .5rem;
+ }
+
+ .card-footer-code ::deep code {
+ border: none;
+ }
+
+ .card-footer-code ::deep .pre-code {
+ margin: .5rem;
+ }
+
+.card-footer-control {
+ text-align: center;
+ color: #d3dce6;
+ display: block;
+}
+
+ .card-footer-control:hover {
+ color: #409eff;
+ }
+
+ .card-footer-control i {
+ transition: .3s linear;
+ }
+
+ .card-footer-control.collapsed i {
+ transform: rotate(180deg);
+ }
+
+ .card-footer-control .card-text {
+ margin-left: 1.5rem;
+ position: absolute;
+ transition: all .3s linear;
+ }
+
+ .card-footer-control .card-text:before {
+ content: "Hide Code";
+ opacity: 0;
+ transition: opacity .3s linear;
+ }
+
+ .card-footer-control.collapsed .card-text:before {
+ content: "Show Code";
+ }
+
+.demo-block > ::deep .anchor-link {
+ font-weight: var(--bb-font-weight);
+ color: var(--bb-title-color);
+ font-size: var(--bb-sub-font-size);
+ margin-top: 1rem;
+ margin-bottom: .5rem;
+}
+
+::deep .table-cell .progress {
+ height: 6px;
+ margin-top: 9px;
+ margin-bottom: 10px;
+}
+
+::deep .chart .btn i + span {
+ display: none;
+}
+
+::deep .ul-demo {
+ margin-bottom: 0;
+}
+
+ ::deep .ul-demo li:not(:last-child) {
+ margin-bottom: 0.25rem;
+ }
+
+@media (min-width: 768px) {
+ ::deep .chart {
+ max-width: 740px;
+ }
+
+ ::deep .chart .btn i + span {
+ display: inline;
+ }
+}
diff --git a/src/BootstrapBlazor.Server/Components/Components/DemoComponent.razor b/src/BootstrapBlazor.Server/Components/Components/DemoComponent.razor
new file mode 100644
index 000000000..742b3fa62
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Components/DemoComponent.razor
@@ -0,0 +1,6 @@
+@Parameter
+
+@code {
+ [CascadingParameter(Name = "BodyContext")]
+ private object? Parameter { get; set; }
+}
diff --git a/src/BootstrapBlazor.Server/Components/Components/DemoTabItem.razor b/src/BootstrapBlazor.Server/Components/Components/DemoTabItem.razor
new file mode 100644
index 000000000..71f0cc709
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Components/DemoTabItem.razor
@@ -0,0 +1,3 @@
+@((MarkupString)Localizer["Info"].Value)
+
+
diff --git a/src/BootstrapBlazor.Server/Components/Components/DemoTabItem.razor.cs b/src/BootstrapBlazor.Server/Components/Components/DemoTabItem.razor.cs
new file mode 100644
index 000000000..bf999ce5a
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Components/DemoTabItem.razor.cs
@@ -0,0 +1,29 @@
+// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+// Website: https://www.blazor.zone or https://argozhang.github.io/
+
+namespace BootstrapBlazor.Server.Components.Components;
+
+///
+/// DemoTabItem 组件
+///
+public partial class DemoTabItem
+{
+ [Inject]
+ [NotNull]
+ private IStringLocalizer? Localizer { get; set; }
+
+ ///
+ /// OnSetTitle 回调方法
+ ///
+ [Parameter]
+ public Func? OnSetTitle { get; set; }
+
+ private async Task OnClick()
+ {
+ if (OnSetTitle != null)
+ {
+ await OnSetTitle(DateTime.Now.ToString("mm:ss"));
+ }
+ }
+}
diff --git a/src/BootstrapBlazor.Server/Components/Components/DemoTabItemSetText.razor b/src/BootstrapBlazor.Server/Components/Components/DemoTabItemSetText.razor
new file mode 100644
index 000000000..71f0cc709
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Components/DemoTabItemSetText.razor
@@ -0,0 +1,3 @@
+@((MarkupString)Localizer["Info"].Value)
+
+
diff --git a/src/BootstrapBlazor.Server/Components/Components/DemoTabItemSetText.razor.cs b/src/BootstrapBlazor.Server/Components/Components/DemoTabItemSetText.razor.cs
new file mode 100644
index 000000000..d63e189fa
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Components/DemoTabItemSetText.razor.cs
@@ -0,0 +1,24 @@
+// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+// Website: https://www.blazor.zone or https://argozhang.github.io/
+
+namespace BootstrapBlazor.Server.Components.Components;
+
+///
+/// DemoTabItem 组件
+///
+public partial class DemoTabItemSetText
+{
+ [CascadingParameter]
+ [NotNull]
+ private TabItem? TabItem { get; set; }
+
+ [Inject]
+ [NotNull]
+ private IStringLocalizer? Localizer { get; set; }
+
+ private void OnClick()
+ {
+ TabItem.SetHeader(DateTime.Now.ToString("mm:ss"));
+ }
+}
diff --git a/src/BootstrapBlazor.Server/Components/Components/DemoTableEditTemplate.razor b/src/BootstrapBlazor.Server/Components/Components/DemoTableEditTemplate.razor
new file mode 100644
index 000000000..15aaf9028
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Components/DemoTableEditTemplate.razor
@@ -0,0 +1,28 @@
+@using BootstrapBlazor.Server.Components.Samples.Table
+
+
+
+@code {
+ [Parameter]
+ [NotNull]
+ public Foo? Model { get; set; }
+
+ [Inject]
+ [NotNull]
+ private IStringLocalizer? Localizer { get; set; }
+
+ private string? EducationDesc => Model.Education == EnumEducation.Primary ? Localizer["TablesEditTemplateDisplayDetail1"] : Localizer["TablesEditTemplateDisplayDetail2"];
+}
diff --git a/src/BootstrapBlazor.Server/Components/Components/DialogBodyFoo.razor b/src/BootstrapBlazor.Server/Components/Components/DialogBodyFoo.razor
new file mode 100644
index 000000000..569dbdd22
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Components/DialogBodyFoo.razor
@@ -0,0 +1 @@
+标题栏下拉框选中值:@Value
diff --git a/src/BootstrapBlazor.Server/Components/Components/DialogBodyFoo.razor.cs b/src/BootstrapBlazor.Server/Components/Components/DialogBodyFoo.razor.cs
new file mode 100644
index 000000000..56a072c03
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Components/DialogBodyFoo.razor.cs
@@ -0,0 +1,29 @@
+// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+// Website: https://www.blazor.zone or https://argozhang.github.io/
+
+namespace BootstrapBlazor.Server.Components.Components;
+
+///
+///
+///
+public partial class DialogBodyFoo
+{
+ private string? Value { get; set; }
+
+ private List Items { get; } = new(new[]
+ {
+ new SelectedItem("beijing", "北京"),
+ new SelectedItem("shanghai", "上海")
+ });
+
+ ///
+ ///
+ ///
+ public Task UpdateAsync(string val)
+ {
+ Value = Items.First(i => i.Value == val).Text;
+ StateHasChanged();
+ return Task.CompletedTask;
+ }
+}
diff --git a/src/BootstrapBlazor.Server/Components/Components/DialogDemo.razor b/src/BootstrapBlazor.Server/Components/Components/DialogDemo.razor
new file mode 100644
index 000000000..bfd908eb0
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Components/DialogDemo.razor
@@ -0,0 +1,16 @@
+无限弹窗示例 @Title
+
+
+
+ 我是用户管理
+
+
+
+ 我是菜单管理
+
+
+
+ 我是角色管理
+
+
+
diff --git a/src/BootstrapBlazor.Server/Components/Components/DialogDemo.razor.cs b/src/BootstrapBlazor.Server/Components/Components/DialogDemo.razor.cs
new file mode 100644
index 000000000..cca2fe6ea
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Components/DialogDemo.razor.cs
@@ -0,0 +1,26 @@
+// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+// Website: https://www.blazor.zone or https://argozhang.github.io/
+
+namespace BootstrapBlazor.Server.Components.Components;
+
+///
+///
+///
+public partial class DialogDemo
+{
+ [Inject]
+ [NotNull]
+ private DialogService? DialogService { get; set; }
+
+ private string Title { get; } = DateTime.Now.ToString();
+
+ private Task OnClickButton() => DialogService.Show(new DialogOption()
+ {
+ Title = "Pop-up",
+ IsDraggable = true,
+ IsKeyboard = true,
+ IsBackdrop = true,
+ Component = BootstrapDynamicComponent.CreateComponent()
+ });
+}
diff --git a/src/BootstrapBlazor.Server/Components/Components/DialogHeaderFoo.razor b/src/BootstrapBlazor.Server/Components/Components/DialogHeaderFoo.razor
new file mode 100644
index 000000000..5c45573cf
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Components/DialogHeaderFoo.razor
@@ -0,0 +1,4 @@
+自定义 Header
+
+
+
diff --git a/src/BootstrapBlazor.Server/Components/Components/DialogHeaderFoo.razor.cs b/src/BootstrapBlazor.Server/Components/Components/DialogHeaderFoo.razor.cs
new file mode 100644
index 000000000..0e6ffaf1d
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Components/DialogHeaderFoo.razor.cs
@@ -0,0 +1,49 @@
+// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+// Website: https://www.blazor.zone or https://argozhang.github.io/
+
+namespace BootstrapBlazor.Server.Components.Components;
+
+///
+///
+///
+public partial class DialogHeaderFoo
+{
+ [NotNull]
+ private IEnumerable? Items { get; set; }
+
+ ///
+ ///
+ ///
+ [Parameter]
+ public string? Value { get; set; }
+
+ ///
+ ///
+ ///
+ [Parameter]
+ public Func? OnValueChanged { get; set; }
+
+ ///
+ ///
+ ///
+ protected override void OnInitialized()
+ {
+ base.OnInitialized();
+
+ Items = new[]
+ {
+ new SelectedItem("beijing", "北京"),
+ new SelectedItem("shanghai", "上海")
+ };
+ }
+
+ private async Task OnSelectedItemChanged(SelectedItem item)
+ {
+ Value = item.Value;
+ if (OnValueChanged != null)
+ {
+ await OnValueChanged(Value);
+ }
+ }
+}
diff --git a/src/BootstrapBlazor.Server/Components/Components/DialogSaveDetail.razor b/src/BootstrapBlazor.Server/Components/Components/DialogSaveDetail.razor
new file mode 100644
index 000000000..3d4f373a5
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Components/DialogSaveDetail.razor
@@ -0,0 +1,17 @@
+
+
+@code {
+ ///
+ ///
+ ///
+ [Parameter]
+ [NotNull]
+ public Foo? Value { get; set; }
+}
diff --git a/src/BootstrapBlazor.Server/Components/Components/ErrorCounter.razor b/src/BootstrapBlazor.Server/Components/Components/ErrorCounter.razor
new file mode 100644
index 000000000..cb988dd0e
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Components/ErrorCounter.razor
@@ -0,0 +1,14 @@
+Counter
+
+Current count: @currentCount
+
+Click me
+
+@code {
+ private int currentCount = 0;
+
+ private void IncrementCount()
+ {
+ throw new Exception("Custom Exception");
+ }
+}
diff --git a/src/BootstrapBlazor.Server/Components/Components/EventTable.razor b/src/BootstrapBlazor.Server/Components/Components/EventTable.razor
new file mode 100644
index 000000000..99cf2ba1c
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Components/EventTable.razor
@@ -0,0 +1,17 @@
+@inject IStringLocalizer Localizer
+
+
+
@Localizer["Title"]
+
+
+
+
+@code {
+ [Parameter] public IEnumerable? Items { get; set; }
+}
diff --git a/src/BootstrapBlazor.Server/Components/Components/FetchData.razor b/src/BootstrapBlazor.Server/Components/Components/FetchData.razor
new file mode 100644
index 000000000..2cae05a6e
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Components/FetchData.razor
@@ -0,0 +1,47 @@
+@inject WeatherForecastService ForecastService
+
+Weather forecast
+
+This component demonstrates fetching data from a service.
+
+@if (forecasts == null)
+{
+ Loading...
+}
+else
+{
+
+
+
+ Date
+ Temp. (C)
+ Temp. (F)
+ Summary
+
+
+
+ @foreach (var forecast in forecasts)
+ {
+
+ @forecast.Date.ToShortDateString()
+ @forecast.TemperatureC
+ @forecast.TemperatureF
+ @forecast.Summary
+
+ }
+
+
+}
+
+@code {
+ private WeatherForecast[] forecasts = new WeatherForecast[0];
+
+ ///
+ ///
+ ///
+ ///
+ protected override async Task OnInitializedAsync()
+ {
+ forecasts = await ForecastService.GetForecastAsync(DateTime.Now);
+ }
+}
diff --git a/src/BootstrapBlazor.Server/Components/Components/FooSearch.razor b/src/BootstrapBlazor.Server/Components/Components/FooSearch.razor
new file mode 100644
index 000000000..365c651ba
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Components/FooSearch.razor
@@ -0,0 +1,14 @@
+
diff --git a/src/BootstrapBlazor.Server/Components/Components/FooSearch.razor.cs b/src/BootstrapBlazor.Server/Components/Components/FooSearch.razor.cs
new file mode 100644
index 000000000..5618fe715
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Components/FooSearch.razor.cs
@@ -0,0 +1,35 @@
+// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+// Website: https://www.blazor.zone or https://argozhang.github.io/
+
+namespace BootstrapBlazor.Server.Components.Components;
+
+///
+///
+///
+public partial class FooSearch
+{
+ ///
+ ///
+ ///
+ [Parameter]
+ [NotNull]
+ public FooSearchModel? Value { get; set; }
+
+ ///
+ ///
+ ///
+ [Parameter]
+ public EventCallback ValueChanged { get; set; }
+
+ ///
+ ///
+ ///
+ public List CountItems { get; } = new List()
+ {
+ new SelectedItem("", "全部"),
+ new SelectedItem("1", "小于 30"),
+ new SelectedItem("2", "大于等于 30 小于 70"),
+ new SelectedItem("3", "大于等于 70 小于 100")
+ };
+}
diff --git a/src/BootstrapBlazor.Server/Components/Components/FormInlineSwitch.razor b/src/BootstrapBlazor.Server/Components/Components/FormInlineSwitch.razor
new file mode 100644
index 000000000..7f1ebbd64
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Components/FormInlineSwitch.razor
@@ -0,0 +1 @@
+
diff --git a/src/BootstrapBlazor.Server/Components/Components/FormInlineSwitch.razor.cs b/src/BootstrapBlazor.Server/Components/Components/FormInlineSwitch.razor.cs
new file mode 100644
index 000000000..0f389f870
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Components/FormInlineSwitch.razor.cs
@@ -0,0 +1,61 @@
+// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+// Website: https://www.blazor.zone or https://argozhang.github.io/
+
+using BootstrapBlazor.Server.Components.Samples;
+
+namespace BootstrapBlazor.Server.Components.Components;
+
+///
+/// 内部组件
+///
+public partial class FormInlineSwitch
+{
+ ///
+ /// 获得/设置 用户自定义属性
+ ///
+ [Parameter(CaptureUnmatchedValues = true)]
+ public IDictionary? AdditionalAttributes { get; set; }
+
+ [Inject]
+ [NotNull]
+ private IStringLocalizer? LocalizerRows { get; set; }
+
+ ///
+ ///
+ ///
+ [Parameter]
+ public RowType Value { get; set; }
+
+ ///
+ ///
+ ///
+ [Parameter]
+ public EventCallback ValueChanged { get; set; }
+
+ [NotNull]
+ private IEnumerable? Items { get; set; }
+
+ private RowType FormRowType
+ {
+ get => Value; set
+ {
+ if (Value != value)
+ {
+ Value = value;
+ if (ValueChanged.HasDelegate)
+ {
+ ValueChanged.InvokeAsync(Value);
+ }
+ }
+ }
+ }
+
+ ///
+ /// OnInitialized 方法
+ ///
+ protected override void OnInitialized()
+ {
+ Items = Enum.GetNames().Select(i => new SelectedItem(i, LocalizerRows[i]));
+ }
+}
diff --git a/src/BootstrapBlazor.Server/Components/Components/GlobalSearch.razor b/src/BootstrapBlazor.Server/Components/Components/GlobalSearch.razor
new file mode 100644
index 000000000..871e7a705
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Components/GlobalSearch.razor
@@ -0,0 +1,3 @@
+
+
+
diff --git a/src/BootstrapBlazor.Server/Components/Components/GlobalSearch.razor.cs b/src/BootstrapBlazor.Server/Components/Components/GlobalSearch.razor.cs
new file mode 100644
index 000000000..31f9769c9
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Components/GlobalSearch.razor.cs
@@ -0,0 +1,57 @@
+// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+// Website: https://www.blazor.zone or https://argozhang.github.io/
+
+using Microsoft.Extensions.Options;
+
+namespace BootstrapBlazor.Server.Components.Components;
+
+///
+/// Pre 组件
+///
+public partial class GlobalSearch
+{
+ [Inject]
+ [NotNull]
+ private IStringLocalizer? Localizer { get; set; }
+
+ [Inject]
+ [NotNull]
+ private IOptionsMonitor? WebsiteOption { get; set; }
+
+ [Inject]
+ [NotNull]
+ private NavigationManager? NavigationManager { get; set; }
+
+ [Inject]
+ [NotNull]
+ private MenuService? MenuService { get; set; }
+
+ [NotNull]
+ private List? ComponentItems { get; set; }
+
+ private IEnumerable Menus => MenuService.GetMenus().SelectMany(i => i.Items).Where(i => !string.IsNullOrEmpty(i.Url));
+
+ ///
+ ///
+ ///
+ protected override void OnInitialized()
+ {
+ ComponentItems = Menus.Select(i => i.Text!).ToList();
+ }
+
+ private Task OnSearch(string searchText)
+ {
+ if (!string.IsNullOrEmpty(searchText))
+ {
+ var item = Menus.FirstOrDefault(i => i.Text!.Contains(searchText, StringComparison.OrdinalIgnoreCase));
+ if (item != null && !string.IsNullOrEmpty(item.Url))
+ {
+ NavigationManager.NavigateTo(item.Url);
+ }
+ }
+ return Task.CompletedTask;
+ }
+
+ private Task OnSelectedItemChanged(string searchText) => OnSearch(searchText);
+}
diff --git a/src/BootstrapBlazor.Server/Components/Components/Header.razor b/src/BootstrapBlazor.Server/Components/Components/Header.razor
new file mode 100644
index 000000000..3ff5b6b9c
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Components/Header.razor
@@ -0,0 +1,44 @@
+@inherits WebSiteModuleComponentBase
+@attribute [JSModuleAutoLoader("Components/Header.razor.js")]
+
+
+
diff --git a/src/BootstrapBlazor.Server/Components/Components/Header.razor.cs b/src/BootstrapBlazor.Server/Components/Components/Header.razor.cs
new file mode 100644
index 000000000..f8105585a
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Components/Header.razor.cs
@@ -0,0 +1,48 @@
+// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+// Website: https://www.blazor.zone or https://argozhang.github.io/
+
+using Microsoft.Extensions.Options;
+
+namespace BootstrapBlazor.Server.Components.Components;
+
+///
+/// Header 组件
+///
+public partial class Header
+{
+ [Inject]
+ [NotNull]
+ private IOptionsMonitor? WebsiteOption { get; set; }
+
+ [Inject]
+ [NotNull]
+ private IStringLocalizer? Localizer { get; set; }
+
+ [NotNull]
+ private string? HomeText { get; set; }
+
+ [NotNull]
+ private string? IntroductionText { get; set; }
+
+ [NotNull]
+ private string? ComponentsText { get; set; }
+
+ [NotNull]
+ private string? DownloadText { get; set; }
+
+ private string DownloadUrl => $"{WebsiteOption.CurrentValue.BootstrapBlazorLink}/repository/archive/main.zip";
+
+ ///
+ ///
+ ///
+ protected override void OnInitialized()
+ {
+ base.OnInitialized();
+
+ DownloadText ??= Localizer[nameof(DownloadText)];
+ HomeText ??= Localizer[nameof(HomeText)];
+ IntroductionText ??= Localizer[nameof(IntroductionText)];
+ ComponentsText ??= Localizer[nameof(ComponentsText)];
+ }
+}
diff --git a/src/BootstrapBlazor.Server/Components/Components/Header.razor.css b/src/BootstrapBlazor.Server/Components/Components/Header.razor.css
new file mode 100644
index 000000000..f5db29414
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Components/Header.razor.css
@@ -0,0 +1,68 @@
+header {
+ --bb-violet-rgb: 112.520718,44.062154,249.437846;
+ background-color: transparent;
+ background-image: linear-gradient(to bottom, rgba(var(--bb-violet-rgb), 1), rgba(var(--bb-violet-rgb), 0.95));
+ box-shadow: 0 0.5rem 1rem rgba(0,0,0,.05), inset 0 -1px 0 rgba(0,0,0,.1);
+ font-size: 1rem;
+ transition: transform .3s ease;
+}
+
+.header-img {
+ display: flex;
+ align-items: center;
+ padding: 0;
+ margin-right: 0;
+}
+
+::deep .btn-search .btn {
+ --bs-btn-bg: #8759ff;
+ --bs-btn-color: #fff;
+ --bs-btn-hover-bg: #7d53eb;
+ --bs-btn-hover-color: var(--bs-btn-color);
+ --bs-btn-hover-border-color: var(--bs-btn-hover-bg);
+ --bs-btn-active-bg: var(--bs-btn-hover-bg);
+ --bs-btn-active-color: var(--bs-btn-hover-color);
+ --bs-btn-active-border-color: var(--bs-btn-hover-border-color);
+}
+
+::deep .btn-search .form-control {
+ --bs-border-color: #fff;
+ --bb-border-focus-color: var(--bs-border-color);
+ --bb-border-hover-color: var(--bs-border-color);
+ z-index: 6;
+}
+
+::deep .btn-fs {
+ margin-top: 2px;
+}
+
+.btn-bd-download {
+ font-weight: 600;
+ color: #ffe484;
+ border-color: #ffe484;
+}
+
+ .btn-bd-download:active,
+ .btn-bd-download:hover {
+ color: #2a2730;
+ background-color: #ffe484;
+ border-color: #ffe484;
+ }
+
+.nav-link img {
+ height: 24px;
+ width: auto;
+}
+
+@media (min-width: 768px) {
+ .navbar-header {
+ position: sticky;
+ top: 0;
+ z-index: 1050;
+ height: var(--bs-header-height);
+ }
+
+ .modal-open .navbar-header {
+ z-index: 1040;
+ }
+}
diff --git a/src/BootstrapBlazor.Server/Components/Components/Header.razor.js b/src/BootstrapBlazor.Server/Components/Components/Header.razor.js
new file mode 100644
index 000000000..27316e531
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Components/Header.razor.js
@@ -0,0 +1,20 @@
+import EventHandler from "../../_content/BootstrapBlazor/modules/event-handler.js?v=$version"
+
+export function init() {
+ const scrollTop = () => (document.documentElement && document.documentElement.scrollTop) || document.body.scrollTop
+ let prevScrollTop = 0;
+ EventHandler.on(document, 'scroll', () => {
+ const items = document.querySelectorAll('.navbar-header, .coms-search')
+ const currentScrollTop = scrollTop()
+ if (currentScrollTop > prevScrollTop) {
+ items.forEach(item => item.classList.add('hide'))
+ } else {
+ items.forEach(item => item.classList.remove('hide'))
+ }
+ prevScrollTop = currentScrollTop
+ })
+}
+
+export function dispose() {
+ EventHandler.off(document, 'scroll')
+}
diff --git a/src/BootstrapBlazor.Server/Components/Components/InstallContent.razor b/src/BootstrapBlazor.Server/Components/Components/InstallContent.razor
new file mode 100644
index 000000000..6059dda93
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Components/InstallContent.razor
@@ -0,0 +1,90 @@
+@using Microsoft.Extensions.DependencyInjection
+@inject PackageVersionService VersionManager
+@inject IStringLocalizer Localizer
+
+@Title
+
+@Localizer["Heading"]
+
+@Localizer["P1"]
+
+ visual studio 2019
@Localizer["P2"] visual studio 2022
+ net5
@Localizer["P3"] net6
+
+BootstrapBlazor
@Localizer["P4"] net5/net6
+
+@Localizer["P5"]
+
+@Localizer["P6"] [@Localizer["P7"]] @Localizer["P8"]
+
+@Localizer["P9"]
+
+@Localizer["P10"]
+1. @Localizer["P11"]
+2. @Localizer["P12"]
+3. @Localizer["P13"] Blazor App @Localizer["P14"] @Localizer["P15"] , @Localizer["P16"] Create
+
+@ChooseTemplate
+@Localizer["P17"]
+1. @Localizer["P18"] nuget.org @Localizer["P19"] BootstrapBlazor
+@Localizer["P20"] Manage Nuget Packages
+dotnet add package BootstrapBlazor --version @Version
+
+2. @Localizer["P21"]
+
+3. @Localizer["P22"]
+@Localizer["P23"]
+@SheetTemplate
+
+ @((MarkupString)Localizer["Tips2"].Value)
+
+<head>
+ ...
+
+ <!-- @Localizer["P24"] !-->
+ <link href="_content/BootstrapBlazor.FontAwesome/css/font-awesome.min.css" rel="stylesheet">
+ <link href="_content/BootstrapBlazor/css/bootstrap.blazor.bundle.min.css" rel="stylesheet">
+
+ ...
+ <link href="css/site.css" rel="stylesheet">
+ <link href="BlazorApp1.styles.css" rel="stylesheet">
+</head>
+4. @Localizer["P25"]
+@ScriptsTemplate
+<body>
+ ...
+ <!-- @Localizer["P26"] !-->
+ <script src="_content/BootstrapBlazor/js/bootstrap.blazor.bundle.min.js"></script>
+ ...
+ <script src="_framework/blazor.server.js"></script>
+</body>
+5. @Localizer["P27"]
+@ServicesTemplate
+
+6. @Localizer["P28"]
+@Localizer["P29"] ~/_Imports.razor
@Localizer["P30"] Razor
@Localizer["P31"]
+@@using BootstrapBlazor.Components
+
+7. @Localizer["P32"] BootstrapBlazorRoot
@Localizer["P33"] ~/App.razor
@Localizer["P34"]
+<BootstrapBlazorRoot>
+ <Router AppAssembly="@@typeof(App).Assembly">
+ <Found Context="routeData">
+ <PageTitle>Title</PageTitle>
+ <RouteView RouteData="@@routeData" DefaultLayout="@@typeof(MainLayout)" />
+ <FocusOnNavigate RouteData="@@routeData" Selector="h1" />
+ </Found>
+ <NotFound>
+ <PageTitle>Not found</PageTitle>
+ <LayoutView Layout="@@typeof(MainLayout)">
+ <p> @Localizer["P35"] ...</p>
+ </LayoutView>
+ </NotFound>
+ </Router>
+</BootstrapBlazorRoot>
+
+@Localizer["P36"]
+@Localizer["P37"] BootstrapBlazor
@Localizer["P38"]:
+1. @Localizer["P39"] Button
@Localizer["P40"]
+<Button Color="Color.Primary" Icon="fa-solid fa-font-awesome" Text="@Localizer["P41"]" />
+2. @Localizer["P42"] Visual studio 2022 @Localizer["P43"] F5 @Localizer["P44"]
+
diff --git a/src/BootstrapBlazor.Server/Components/Components/InstallContent.razor.cs b/src/BootstrapBlazor.Server/Components/Components/InstallContent.razor.cs
new file mode 100644
index 000000000..d7c7efa60
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Components/InstallContent.razor.cs
@@ -0,0 +1,67 @@
+// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+// Website: https://www.blazor.zone or https://argozhang.github.io/
+
+namespace BootstrapBlazor.Server.Components.Components;
+
+///
+///
+///
+public sealed partial class InstallContent
+{
+ ///
+ /// 获得/设置 版本号字符串
+ ///
+ private string Version { get; set; } = "latest";
+
+ ///
+ ///
+ ///
+ [Parameter]
+ public string Title { get; set; } = "服务器端 Blazor 安装教程";
+
+ ///
+ ///
+ ///
+ [Parameter]
+ public string HostFile { get; set; } = "Pages/_Host.cshtml";
+
+ ///
+ ///
+ ///
+ [Parameter]
+ public RenderFragment? ChooseTemplate { get; set; }
+
+ ///
+ ///
+ ///
+ [Parameter]
+ public RenderFragment? SheetTemplate { get; set; }
+
+ ///
+ ///
+ ///
+ [Parameter]
+ public RenderFragment? ScriptsTemplate { get; set; }
+
+ ///
+ ///
+ ///
+ [Parameter]
+ public RenderFragment? ServicesTemplate { get; set; }
+
+ ///
+ ///
+ ///
+ [Parameter]
+ public RenderFragment? ChildContent { get; set; }
+
+ ///
+ /// OnInitializedAsync 方法
+ ///
+ ///
+ protected override async Task OnInitializedAsync()
+ {
+ Version = await VersionManager.GetVersionAsync();
+ }
+}
diff --git a/src/BootstrapBlazor.Server/Components/Components/MethodTable.razor b/src/BootstrapBlazor.Server/Components/Components/MethodTable.razor
new file mode 100644
index 000000000..3056cd682
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Components/MethodTable.razor
@@ -0,0 +1,13 @@
+
+
diff --git a/src/BootstrapBlazor.Server/Components/Components/MethodTable.razor.cs b/src/BootstrapBlazor.Server/Components/Components/MethodTable.razor.cs
new file mode 100644
index 000000000..1febf4bd4
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Components/MethodTable.razor.cs
@@ -0,0 +1,38 @@
+// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+// Website: https://www.blazor.zone or https://argozhang.github.io/
+
+namespace BootstrapBlazor.Server.Components.Components;
+
+///
+///
+///
+public sealed partial class MethodTable
+{
+ [Inject]
+ [NotNull]
+ private IStringLocalizer? Localizer { get; set; }
+
+ ///
+ ///
+ ///
+ [Parameter]
+ [NotNull]
+ public string? Title { get; set; }
+
+ ///
+ ///
+ ///
+ [Parameter] public IEnumerable? Items { get; set; }
+
+ ///
+ /// OnInitialized 方法
+ ///
+ protected override void OnInitialized()
+ {
+ base.OnInitialized();
+
+ Title ??= Localizer[nameof(Title)];
+
+ }
+}
diff --git a/src/BootstrapBlazor.Server/Components/Components/PackageTips.razor b/src/BootstrapBlazor.Server/Components/Components/PackageTips.razor
new file mode 100644
index 000000000..b19cb506c
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Components/PackageTips.razor
@@ -0,0 +1,36 @@
+@inject IStringLocalizer Localizer
+
+@((MarkupString)Localizer["Tips", Name].Value)
+
+.NET CLI
+dotnet add package @Name
+
+PackageReference
+<PackageReference Include="@Name" Version="@Version" />
+
+Package Manager
+Install-Package @Name
+
+@code {
+ [Inject]
+ [NotNull]
+ private PackageVersionService? VersionManager { get; set; }
+
+ private string Version { get; set; } = "fetching";
+
+ ///
+ /// 获得/设置 Package 名称
+ ///
+ [Parameter]
+ [NotNull]
+ [EditorRequired]
+ public string? Name { get; set; }
+
+ ///
+ ///
+ ///
+ protected override async Task OnInitializedAsync()
+ {
+ Version = await VersionManager.GetVersionAsync(Name.ToLower());
+ }
+}
diff --git a/src/BootstrapBlazor.Server/Components/Components/Pre.razor b/src/BootstrapBlazor.Server/Components/Components/Pre.razor
new file mode 100644
index 000000000..bab9cb60d
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Components/Pre.razor
@@ -0,0 +1,21 @@
+@inherits WebSiteModuleComponentBase
+@attribute [JSModuleAutoLoader("Components/Pre.razor.js")]
+
+
+
@LoadingText
+ @if (Loaded)
+ {
+
@ChildContent
+ @if (CanCopy)
+ {
+ @if (ShowToolbar)
+ {
+
+
+
+
+ }
+
Copy
+ }
+ }
+
diff --git a/src/BootstrapBlazor.Server/Components/Components/Pre.razor.cs b/src/BootstrapBlazor.Server/Components/Components/Pre.razor.cs
new file mode 100644
index 000000000..205f45ea4
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Components/Pre.razor.cs
@@ -0,0 +1,191 @@
+// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+// Website: https://www.blazor.zone or https://argozhang.github.io/
+
+using System.Text.RegularExpressions;
+
+namespace BootstrapBlazor.Server.Components.Components;
+
+///
+/// Pre 组件
+///
+public partial class Pre
+{
+ private bool Loaded { get; set; }
+
+ private bool CanCopy { get; set; }
+
+ ///
+ /// 获得 样式集合
+ ///
+ ///
+ private string? ClassString => CssBuilder.Default("pre-code")
+ .AddClass("loaded", Loaded)
+ .AddClassFromAttributes(AdditionalAttributes)
+ .Build();
+
+ [Inject]
+ [NotNull]
+ private CodeSnippetService? CodeSnippetService { get; set; }
+
+ ///
+ /// 获得/设置 子组件 CodeFile 为空时生效
+ ///
+ [Parameter]
+ public RenderFragment? ChildContent { get; set; }
+
+ ///
+ /// 获得/设置 代码段的标题
+ ///
+ [Parameter]
+ public string? BlockName { get; set; }
+
+ ///
+ /// 获得/设置 示例代码片段 默认 null 未设置
+ ///
+ [Parameter]
+ public string? CodeFile { get; set; }
+
+ ///
+ /// 获得/设置 是否显示工具按钮组
+ ///
+ [Parameter]
+ public bool ShowToolbar { get; set; }
+
+ [Inject]
+ [NotNull]
+ private IStringLocalizer? Localizer { get; set; }
+
+ private string? LoadingText { get; set; }
+
+ private string? TooltipTitle { get; set; }
+
+ private string? PlusTooltipTitle { get; set; }
+
+ private string? MinusTooltipTitle { get; set; }
+
+ private string? CopiedText { get; set; }
+
+ ///
+ ///
+ ///
+ protected override void OnParametersSet()
+ {
+ LoadingText ??= Localizer[nameof(LoadingText)];
+ TooltipTitle ??= Localizer[nameof(TooltipTitle)];
+ PlusTooltipTitle ??= Localizer[nameof(PlusTooltipTitle)];
+ MinusTooltipTitle ??= Localizer[nameof(MinusTooltipTitle)];
+ CopiedText ??= Localizer[nameof(CopiedText)];
+ }
+
+ ///
+ ///
+ ///
+ ///
+ protected override async Task OnParametersSetAsync()
+ {
+ if (ChildContent == null)
+ {
+ await GetCodeAsync();
+ }
+ else
+ {
+ Loaded = true;
+ CanCopy = true;
+ }
+ }
+
+ ///
+ /// OnAfterRender 方法
+ ///
+ ///
+ protected override async Task OnAfterRenderAsync(bool firstRender)
+ {
+ await base.OnAfterRenderAsync(firstRender);
+
+ if (Loaded)
+ {
+ await InvokeVoidAsync("highlight", Id);
+ }
+ }
+
+ ///
+ ///
+ ///
+ ///
+ protected override Task InvokeInitAsync() => InvokeVoidAsync("init", Id, CopiedText);
+
+ private async Task GetCodeAsync()
+ {
+ if (!string.IsNullOrEmpty(CodeFile))
+ {
+ var code = await CodeSnippetService.GetCodeAsync(CodeFile);
+ if (!string.IsNullOrEmpty(code))
+ {
+ code = FindCodeSnippetByName(code);
+ ChildContent = builder =>
+ {
+ builder.AddContent(0, code);
+ };
+ }
+ CanCopy = !string.IsNullOrEmpty(code) && !code.StartsWith("Error: ");
+ }
+ else
+ {
+ ChildContent = builder =>
+ {
+ builder.AddContent(0, "网站改版中 ... Refactoring website. Coming soon ...");
+ };
+ CanCopy = false;
+ }
+ Loaded = true;
+ }
+
+ private string FindCodeSnippetByName(string code)
+ {
+ var content = code;
+ if (!string.IsNullOrEmpty(BlockName))
+ {
+ var regex = new Regex($"([\\s\\S]*?) ");
+ var match = regex.Match(content);
+ if (match.Success && match.Groups.Count == 2)
+ {
+ content = match.Groups[1].Value.Replace("\r\n", "\n").Replace("\n ", "\n").TrimStart('\n');
+ }
+
+ // 移除 ignore 节点
+ regex = IgnoreRegex();
+ var matchCollection = regex.Matches(content);
+ matchCollection.ToList().ForEach(m =>
+ {
+ content = content.Replace(m.Value, "").TrimStart('\n');
+ });
+
+ // 移除 ConsoleLogger
+ regex = ConsoleLoggerRegex();
+ match = regex.Match(content);
+ if (match.Success)
+ {
+ content = content.Replace(match.Value, "").TrimStart('\n');
+ }
+
+ // 移除 Tips
+ regex = TipsRegex();
+ match = regex.Match(content);
+ if (match.Success)
+ {
+ content = content.Replace(match.Value, "").TrimStart('\n');
+ }
+ }
+ return content.TrimEnd('\n');
+ }
+
+ [GeneratedRegex("")]
+ private static partial Regex IgnoreRegex();
+
+ [GeneratedRegex(" ")]
+ private static partial Regex ConsoleLoggerRegex();
+
+ [GeneratedRegex("[\\s\\S]*? ")]
+ private static partial Regex TipsRegex();
+}
diff --git a/src/BootstrapBlazor.Server/Components/Components/Pre.razor.css b/src/BootstrapBlazor.Server/Components/Components/Pre.razor.css
new file mode 100644
index 000000000..6eea0ccf4
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Components/Pre.razor.css
@@ -0,0 +1,48 @@
+.pre-code {
+ position: relative;
+ border: 1px solid var(--bs-border-color);
+ border-radius: var(--bs-border-radius);
+ overflow: hidden;
+}
+
+ .pre-code .loading {
+ padding: .5rem 1rem;
+ }
+
+ .pre-code.loaded > pre > code {
+ display: none;
+ }
+
+::deep .btn-primary {
+ position: absolute;
+ top: .65rem;
+ right: 1.5rem;
+ font-size: 65%;
+ --bs-btn-color: var(--bs-primary);
+ --bs-btn-bg: #fff;
+ --bs-btn-padding-y: .25rem;
+ --bs-btn-padding-x: .5rem;
+}
+
+::deep .btn-group {
+ position: absolute;
+ top: 0;
+ right: 3rem;
+}
+
+ ::deep .btn-group .btn-primary {
+ position: relative;
+ }
+
+code {
+ line-height: 1.8;
+ font-size: 0.75rem;
+ padding: 10px 65px 10px 16px;
+ display: block;
+ white-space: pre-wrap;
+ -webkit-font-smoothing: auto;
+}
+
+.no-highlight code {
+ color: var(--bs-code-color);
+}
diff --git a/src/BootstrapBlazor.Server/Components/Components/Pre.razor.js b/src/BootstrapBlazor.Server/Components/Components/Pre.razor.js
new file mode 100644
index 000000000..d7cf6ae69
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Components/Pre.razor.js
@@ -0,0 +1,88 @@
+import { copy, getDescribedElement, addLink, addScript, getHeight } from "../../_content/BootstrapBlazor/modules/utility.js?v=$version"
+import EventHandler from "../../_content/BootstrapBlazor/modules/event-handler.js?v=$version"
+
+export async function init(id, title) {
+ const el = document.getElementById(id);
+ if (el === null) {
+ return
+ }
+
+ await addScript('./lib/highlight/highlight.min.js')
+ await addScript('./lib/highlight/cshtml-razor.min.js')
+ await addLink('./lib/highlight/vs.min.css')
+
+ const preElement = el.querySelector('pre')
+ const code = el.querySelector('pre > code')
+
+ if (preElement) {
+ EventHandler.on(el, 'click', '.btn-copy', e => {
+ const text = code.textContent;
+ copy(text)
+
+ const tooltip = getDescribedElement(e.delegateTarget)
+ if (tooltip) {
+ tooltip.querySelector('.tooltip-inner').innerHTML = title
+ }
+ })
+
+ EventHandler.on(el, 'click', '.btn-plus', e => {
+ e.preventDefault()
+ e.stopPropagation();
+
+ let preHeight = getHeight(preElement)
+ const codeHeight = getHeight(code)
+ if (preHeight < codeHeight) {
+ preHeight = Math.min(codeHeight, preHeight + 100)
+ }
+ preElement.style.maxHeight = `${preHeight}px`
+ })
+
+ EventHandler.on(el, 'click', '.btn-minus', e => {
+ e.preventDefault()
+ e.stopPropagation();
+
+ let preHeight = getHeight(preElement)
+ if (preHeight > 260) {
+ preHeight = Math.max(260, preHeight - 100)
+ }
+ preElement.style.maxHeight = `${preHeight}px`
+ })
+ }
+}
+
+export async function highlight(id) {
+ const el = document.getElementById(id);
+
+ if (el) {
+ const invoke = () => {
+ hljs.highlightElement(el.querySelector('code'))
+ el.querySelector('.loading').classList.add('d-none')
+ el.classList.remove('loaded')
+ }
+
+ const check = () => new Promise((resolve, reject) => {
+ const handler = setInterval(() => {
+ const done = window.hljs !== void 0;
+ if (done) {
+ clearInterval(handler)
+ resolve()
+ }
+ }, 20)
+ })
+
+ await check();
+ invoke();
+ }
+}
+
+export function dispose(id) {
+ const el = document.getElementById(id);
+
+ if (el === null) {
+ return
+ }
+
+ EventHandler.off(el, 'click', '.btn-copy')
+ EventHandler.off(el, 'click', '.btn-plus')
+ EventHandler.off(el, 'click', '.btn-minus')
+}
diff --git a/src/BootstrapBlazor.Server/Components/Components/QQGroup.razor b/src/BootstrapBlazor.Server/Components/Components/QQGroup.razor
new file mode 100644
index 000000000..b07a6483a
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Components/QQGroup.razor
@@ -0,0 +1,17 @@
+@inject IOptionsMonitor WebsiteOption
+@inject IStringLocalizer Localzier
+
+
diff --git a/src/BootstrapBlazor.Server/Components/Components/ResultDialogDemo.razor b/src/BootstrapBlazor.Server/Components/Components/ResultDialogDemo.razor
new file mode 100644
index 000000000..ea71d60bd
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Components/ResultDialogDemo.razor
@@ -0,0 +1,8 @@
+
+ 更改数值后,点击 确认
返回主页面并 更新 数值
+ 点击其余按钮时关闭弹窗 不更新 数值
+
+
+
+
+
diff --git a/src/BootstrapBlazor.Server/Components/Components/ResultDialogDemo.razor.cs b/src/BootstrapBlazor.Server/Components/Components/ResultDialogDemo.razor.cs
new file mode 100644
index 000000000..87d6a338d
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Components/ResultDialogDemo.razor.cs
@@ -0,0 +1,37 @@
+// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+// Website: https://www.blazor.zone or https://argozhang.github.io/
+
+namespace BootstrapBlazor.Server.Components.Components;
+
+///
+///
+///
+public partial class ResultDialogDemo : ComponentBase, IResultDialog
+{
+ ///
+ ///
+ ///
+ [Parameter]
+ public int Value { get; set; } = 1;
+
+ ///
+ ///
+ ///
+ [Parameter]
+ public EventCallback ValueChanged { get; set; }
+
+ ///
+ ///
+ ///
+ public async Task OnClose(DialogResult result)
+ {
+ if (result == DialogResult.Yes)
+ {
+ if (ValueChanged.HasDelegate)
+ {
+ await ValueChanged.InvokeAsync(Value);
+ }
+ }
+ }
+}
diff --git a/src/BootstrapBlazor.Server/Components/Components/ResultDialogDemo2.razor b/src/BootstrapBlazor.Server/Components/Components/ResultDialogDemo2.razor
new file mode 100644
index 000000000..ebddc0c71
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Components/ResultDialogDemo2.razor
@@ -0,0 +1,7 @@
+
diff --git a/src/BootstrapBlazor.Server/Components/Components/ResultDialogDemo2.razor.cs b/src/BootstrapBlazor.Server/Components/Components/ResultDialogDemo2.razor.cs
new file mode 100644
index 000000000..923402073
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Components/ResultDialogDemo2.razor.cs
@@ -0,0 +1,138 @@
+// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+// Website: https://www.blazor.zone or https://argozhang.github.io/
+
+using System.ComponentModel;
+
+namespace BootstrapBlazor.Server.Components.Components;
+
+///
+///
+///
+public partial class ResultDialogDemo2 : ComponentBase, IResultDialog
+{
+ private List SelectedRows { get; set; } = new List();
+
+ [NotNull]
+ private List? Items { get; set; }
+
+ ///
+ ///
+ ///
+ [Parameter]
+
+ public IEnumerable? Emails { get; set; }
+
+ ///
+ ///
+ ///
+ [Parameter]
+ public EventCallback> EmailsChanged { get; set; }
+
+ [CascadingParameter(Name = "BodyContext")]
+ private object? BodyContext { get; set; }
+
+ [Inject]
+ [NotNull]
+ private MessageService? MessageService { get; set; }
+
+ private Task> OnQueryAsync(QueryPageOptions option)
+ {
+ // 模拟查询数据
+ var context = BodyContext as FooContext;
+ Items = GenerateItems(context?.Count ?? 10);
+ var data = new QueryData()
+ {
+ TotalCount = Items.Count,
+ Items = Items
+ };
+
+ // 处理选中行
+ Emails = context?.Emails?.Split(";") ?? Array.Empty();
+ SelectedRows.AddRange(Items.Where(i => Emails.Any(mail => mail == i.Email)));
+ return Task.FromResult(data);
+ }
+
+ ///
+ ///
+ ///
+ ///
+ public async Task OnClosing(DialogResult result)
+ {
+ var ret = true;
+ if (result == DialogResult.Yes && !SelectedRows.Any())
+ {
+ await MessageService.Show(new MessageOption()
+ {
+ Content = "请至少选择一位用户!"
+ });
+ ret = false;
+ }
+ return ret;
+ }
+
+ ///
+ ///
+ ///
+ public async Task OnClose(DialogResult result)
+ {
+ if (result == DialogResult.Yes)
+ {
+ if (EmailsChanged.HasDelegate)
+ {
+ Emails = SelectedRows.Where(r => !string.IsNullOrEmpty(r.Email)).Select(r => r.Email!).ToList();
+ await EmailsChanged.InvokeAsync(Emails);
+ }
+ }
+ }
+
+ ///
+ ///
+ ///
+ ///
+ private static List GenerateItems(int startId) => new(Enumerable.Range(startId, 10).Select(i => new Foo()
+ {
+ Id = i,
+ Name = $"张三 {i:d4}",
+ Email = $"zhangsan{i:d4}@163.com"
+ }));
+
+ ///
+ ///
+ ///
+ public class FooContext
+ {
+ ///
+ ///
+ ///
+ public int Count { get; set; }
+
+ ///
+ ///
+ ///
+ public string? Emails { get; set; }
+ }
+
+ ///
+ ///
+ ///
+ private class Foo
+ {
+ ///
+ ///
+ ///
+ [DisplayName("员工ID")]
+ public int? Id { get; set; }
+
+ ///
+ ///
+ ///
+ [DisplayName("员工姓名")]
+ public string? Name { get; set; }
+ ///
+ ///
+ ///
+ [DisplayName("员工邮箱")]
+ public string? Email { get; set; }
+ }
+}
diff --git a/src/BootstrapBlazor.Server/Components/Components/ShownCallbackDummy.razor b/src/BootstrapBlazor.Server/Components/Components/ShownCallbackDummy.razor
new file mode 100644
index 000000000..92096ad66
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Components/ShownCallbackDummy.razor
@@ -0,0 +1,36 @@
+窗口加载后回调示例
+
+在实战应用中,有些脚本比如画图类,必须窗体显示后,由具体高度或者宽度后才能正确工作,此时需要先显示此窗体,然后再调用其方法,本示例中下面数字是通过窗体加载并且显示后,由回调方法触发后,延时 2秒 后显示当前时间
+
+@_text
+
+@code {
+ [Parameter]
+ public Action>? ShownTodo { get; set; }
+
+ private string? _text;
+
+ protected override void OnAfterRender(bool firstRender)
+ {
+ base.OnAfterRender(firstRender);
+
+ if (firstRender)
+ {
+ // 首次加载时回调 ShowTodo 方法
+ if (ShownTodo != null)
+ {
+ ShownTodo(DoJob);
+ }
+ }
+ }
+
+ private async Task DoJob()
+ {
+ _text = "回调成功,开始延时 2 秒";
+ await InvokeAsync(StateHasChanged);
+
+ await Task.Delay(2000);
+ _text = $"当前时间: {DateTime.Now}";
+ await InvokeAsync(StateHasChanged);
+ }
+}
diff --git a/src/BootstrapBlazor.Server/Components/Components/State.razor b/src/BootstrapBlazor.Server/Components/Components/State.razor
new file mode 100644
index 000000000..fb4154a2f
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Components/State.razor
@@ -0,0 +1,18 @@
+@if (IsNew)
+{
+
+ NEW
+
+}
+@if (IsUpdate)
+{
+
+ Upd
+
+}
+@if (Count > 0)
+{
+
+ @Count
+
+}
diff --git a/src/BootstrapBlazor.Server/Components/Components/State.razor.cs b/src/BootstrapBlazor.Server/Components/Components/State.razor.cs
new file mode 100644
index 000000000..269bbbfbc
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Components/State.razor.cs
@@ -0,0 +1,29 @@
+// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+// Website: https://www.blazor.zone or https://argozhang.github.io/
+
+namespace BootstrapBlazor.Server.Components.Components;
+
+///
+///
+///
+public sealed partial class State
+{
+ ///
+ /// 获得/设置 是否为新组件 默认为 false
+ ///
+ [Parameter]
+ public bool IsNew { get; set; }
+
+ ///
+ /// 获得/设置 是否为更新功能 默认为 false
+ ///
+ [Parameter]
+ public bool IsUpdate { get; set; }
+
+ ///
+ /// 获得/设置 组件数量
+ ///
+ [Parameter]
+ public int Count { get; set; }
+}
diff --git a/src/BootstrapBlazor.Server/Components/Components/SwalFooter.razor b/src/BootstrapBlazor.Server/Components/Components/SwalFooter.razor
new file mode 100644
index 000000000..e52ab271c
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Components/SwalFooter.razor
@@ -0,0 +1 @@
+Why do I have this issue?
diff --git a/src/BootstrapBlazor.Server/Components/Components/ThemeChooser.razor b/src/BootstrapBlazor.Server/Components/Components/ThemeChooser.razor
new file mode 100644
index 000000000..60c0ee26b
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Components/ThemeChooser.razor
@@ -0,0 +1,18 @@
+@inherits WebSiteModuleComponentBase
+@attribute [JSModuleAutoLoader("Components/ThemeChooser.razor.js")]
+
+
+
+
+
+ @foreach (var item in Themes)
+ {
+
OnClickTheme(item))">
+ @item.Text
+
+ }
+
+
diff --git a/src/BootstrapBlazor.Server/Components/Components/ThemeChooser.razor.cs b/src/BootstrapBlazor.Server/Components/Components/ThemeChooser.razor.cs
new file mode 100644
index 000000000..6e8572933
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Components/ThemeChooser.razor.cs
@@ -0,0 +1,74 @@
+// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+// Website: https://www.blazor.zone or https://argozhang.github.io/
+
+using Microsoft.Extensions.Options;
+
+namespace BootstrapBlazor.Server.Components.Components;
+
+///
+///
+///
+public partial class ThemeChooser
+{
+ [NotNull]
+ private IEnumerable? Themes { get; set; }
+
+ [NotNull]
+ private string? Title { get; set; }
+
+ [NotNull]
+ private string? HeaderText { get; set; }
+
+ [Inject]
+ [NotNull]
+ private IStringLocalizer? Localizer { get; set; }
+
+ [Inject]
+ [NotNull]
+ private IOptionsMonitor? BootstrapOptions { get; set; }
+
+ [Inject]
+ [NotNull]
+ private IOptionsMonitor? SiteOptions { get; set; }
+
+ ///
+ /// OnInitialized 方法
+ ///
+ protected override void OnInitialized()
+ {
+ base.OnInitialized();
+
+ Title ??= Localizer[nameof(Title)];
+ HeaderText ??= Localizer[nameof(HeaderText)];
+ Themes = BootstrapOptions.CurrentValue.Themes.Select(kv => new SelectedItem(kv.Value, kv.Key));
+ SiteOptions.CurrentValue.CurrentTheme = Themes.FirstOrDefault(i => i.Text == "Motronic")?.Value ?? "";
+ }
+
+ private async Task OnClickTheme(SelectedItem item)
+ {
+ SiteOptions.CurrentValue.CurrentTheme = item.Value;
+
+ await InvokeVoidAsync("addScript", LinksCache[item.Value]);
+ }
+
+ private string? GetThemeItemClass(SelectedItem item) => CssBuilder.Default("theme-item")
+ .AddClass("active", SiteOptions.CurrentValue.CurrentTheme == item.Value)
+ .Build();
+
+ private Dictionary> LinksCache { get; } = new(new KeyValuePair>[]
+ {
+ new("bootstrap.blazor.bundle.min.css", new List()),
+ new("motronic.min.css", new string[]
+ {
+ "./_content/BootstrapBlazor/css/motronic.min.css",
+ "./css/motronic.css"
+ }),
+ new("ant", new List()),
+ new("layui", new List()),
+ new("devui", new string[]
+ {
+ "./css/devui.css"
+ })
+ });
+}
diff --git a/src/BootstrapBlazor.Server/Components/Components/ThemeChooser.razor.css b/src/BootstrapBlazor.Server/Components/Components/ThemeChooser.razor.css
new file mode 100644
index 000000000..b28028bdd
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Components/ThemeChooser.razor.css
@@ -0,0 +1,63 @@
+.theme-list {
+ position: fixed;
+ z-index: 10;
+ bottom: 12rem;
+ right: 1rem;
+ background: #FFFFFF;
+ box-shadow: 0 5px 24px 0 rgba(0, 0, 0, 0.2);
+ border-radius: var(--bs-border-radius);
+ width: 260px;
+ box-shadow: 0 0 12px #211b50;
+ height: 0;
+ overflow: hidden;
+ transition: height .3s ease-in-out;
+}
+
+ .theme-list.is-open {
+ height: 306px;
+ }
+
+.theme-header {
+ padding: 0.75rem 1rem;
+ background-color: #8759ff;
+ color: #fff;
+ border-top-left-radius: 5px;
+ border-top-right-radius: 5px;
+ display: flex;
+ margin-bottom: 1rem;
+}
+
+.btn-close {
+ transition: opacity .3s linear;
+}
+
+ .btn-close:hover {
+ opacity: 1;
+ }
+
+.theme-item {
+ cursor: pointer;
+ border-radius: 100px;
+ padding: 6px 15px;
+ background-color: #f6f6f6;
+ color: #005980;
+ transition: background-color .3s linear;
+ margin: 0 1rem 1rem 1rem;
+}
+
+ .theme-item:hover,
+ .theme-item.active {
+ background-color: #ab8aff;
+ }
+
+::deep .btn-theme {
+ --bs-btn-bg: #034995;
+ --bs-btn-hover-bg: #034995;
+ --bs-btn-active-bg: #034995;
+ right: 1rem;
+ bottom: 9rem;
+}
+
+ ::deep .btn-theme img {
+ width: 20px;
+ }
diff --git a/src/BootstrapBlazor.Server/Components/Components/ThemeChooser.razor.js b/src/BootstrapBlazor.Server/Components/Components/ThemeChooser.razor.js
new file mode 100644
index 000000000..99d5c2ccb
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Components/ThemeChooser.razor.js
@@ -0,0 +1,49 @@
+import { insertAfter } from "../../_content/BootstrapBlazor/modules/utility.js?v=$version"
+import Data from "../../_content/BootstrapBlazor/modules/data.js?v=$version"
+import EventHandler from "../../_content/BootstrapBlazor/modules/event-handler.js?v=$version"
+
+export function init(id) {
+ const el = document.getElementById(id)
+ if (el === null) {
+ return
+ }
+ const themeList = el.querySelector('.theme-list')
+
+ const chooser = { el, themeList }
+ Data.set(id, chooser);
+
+ EventHandler.on(el, 'click', () => {
+ themeList.classList.toggle('is-open')
+ })
+}
+
+export function addScript(args) {
+ const links = document.querySelectorAll('link')
+ if (links) {
+ const link = [].slice.call(links).filter(function (item) {
+ const href = item.getAttribute('href')
+ return href.indexOf('/css/site.css') > -1
+ });
+ const original = link[0]
+ while (original.nextElementSibling && original.nextElementSibling.nodeName === 'LINK') {
+ original.nextElementSibling.remove()
+ }
+
+ args.forEach(function (c) {
+ const link = document.createElement('link')
+ link.setAttribute('rel', 'stylesheet')
+ link.setAttribute('href', c)
+
+ insertAfter(original, link)
+ });
+ }
+}
+
+export function dispose(id) {
+ const chooser = Data.get(id)
+ Data.remove(id)
+
+ if (chooser) {
+ EventHandler.off(chooser.el, 'click')
+ }
+}
diff --git a/src/BootstrapBlazor.Server/Components/Components/Tips.razor b/src/BootstrapBlazor.Server/Components/Components/Tips.razor
new file mode 100644
index 000000000..f6996b6c1
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Components/Tips.razor
@@ -0,0 +1,28 @@
+@inherits BootstrapComponentBase
+@inject IStringLocalizer Localizer
+
+
+ @Localizer["Title"]
+ @ChildContent
+
+
+@code {
+
+ ///
+ /// 获得/设置 图标
+ ///
+ [Parameter]
+ public string Icon { get; set; } = "fa-regular fa-lightbulb";
+
+ ///
+ /// 获得/设置 颜色 默认为 Info
+ ///
+ [Parameter]
+ public Color Color { get; set; } = Color.Info;
+
+ ///
+ /// 获得/设置 子组件内容
+ ///
+ [Parameter]
+ public RenderFragment? ChildContent { get; set; }
+}
diff --git a/src/BootstrapBlazor.Server/Components/Components/UpdateIntro.razor b/src/BootstrapBlazor.Server/Components/Components/UpdateIntro.razor
new file mode 100644
index 000000000..f13e632d6
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Components/UpdateIntro.razor
@@ -0,0 +1,28 @@
+@inherits WebSiteModuleComponentBase
+@inject IStringLocalizer Localizer
+@attribute [JSModuleAutoLoader("Components/UpdateIntro.razor.js")]
+
+
+
Bootstrap Blazor @Localizer["H1"] @PackageVersionService.Version
+
+
+
@Localizer["B1"] Bootstrap Blazor @Localizer["B2"] @Localizer["B3"] @Localizer["B4"]。Bootstrap Blazor @((MarkupString)Localizer["B5"].Value)
+
+ @Localizer["P1"] @PackageVersionService.Version @Localizer["P2"] [@Localizer["P3"]] @Localizer["P4"] Star
+
+
+
+
+
+
+
+
+
+
+
QQ 795206915
+
+
+
+
diff --git a/src/BootstrapBlazor.Server/Components/Components/UpdateIntro.razor.cs b/src/BootstrapBlazor.Server/Components/Components/UpdateIntro.razor.cs
new file mode 100644
index 000000000..539016eaa
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Components/UpdateIntro.razor.cs
@@ -0,0 +1,35 @@
+// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+// Website: https://www.blazor.zone or https://argozhang.github.io/
+
+using Microsoft.Extensions.Options;
+
+namespace BootstrapBlazor.Server.Components.Components;
+
+///
+/// 更新日志介绍组件
+///
+public partial class UpdateIntro
+{
+ [Inject]
+ [NotNull]
+ private IOptionsMonitor? WebsiteOption { get; set; }
+
+ [Inject]
+ [NotNull]
+ private PackageVersionService? PackageVersionService { get; set; }
+
+ private string UpdateLogUrl => $"{WebsiteOption.CurrentValue.BootstrapBlazorLink}/wikis/%E6%9B%B4%E6%96%B0%E6%97%A5%E5%BF%97?sort_id=4062034";
+
+ ///
+ ///
+ ///
+ protected override async Task InvokeInitAsync()
+ {
+#if DEBUG
+ await InvokeVoidAsync("init", "");
+#else
+ await InvokeVoidAsync("init", Id, PackageVersionService.Version);
+#endif
+ }
+}
diff --git a/src/BootstrapBlazor.Server/Components/Components/UpdateIntro.razor.css b/src/BootstrapBlazor.Server/Components/Components/UpdateIntro.razor.css
new file mode 100644
index 000000000..92cb0e4be
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Components/UpdateIntro.razor.css
@@ -0,0 +1,68 @@
+.blazor-intro {
+ position: fixed;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ z-index: 1900;
+ color: #ffffff;
+ background: linear-gradient(54.4deg,#771f89 -28.5%,#834cef 30.36%,#636cea 99.19%);
+ padding: 1rem;
+ height: 224px;
+ transform: translateY(100%);
+ transition: transform .3s ease-in-out;
+}
+
+ .blazor-intro.show {
+ transform: translateY(0);
+ }
+
+ .blazor-intro .blazor-intro-body {
+ flex: 1 1 auto;
+ }
+
+ .blazor-intro .blazor-intro-body a {
+ color: #fff;
+ cursor: pointer;
+ text-decoration: underline;
+ }
+
+ .blazor-intro .blazor-intro-body img {
+ width: 44px;
+ }
+
+ .blazor-intro .blazor-intro-barcode {
+ text-align: center;
+ margin: 1rem 1rem 0 2rem;
+ }
+
+ .blazor-intro .blazor-intro-barcode img {
+ width: 110px;
+ }
+
+.blazor-intro-button {
+ position: absolute;
+ top: 12px;
+ right: 12px;
+ color: #fff;
+ background-color: #4b4df6;
+ cursor: pointer;
+ border-radius: 50%;
+ padding: 6px;
+ transition: background-color .3s linear;
+}
+
+ .blazor-intro-button:hover {
+ background-color: #3c3de2;
+ }
+
+ .blazor-intro-button svg {
+ width: 24px;
+ height: 24px;
+ fill: currentcolor;
+ }
+
+@media print {
+ .blazor-intro {
+ display: none;
+ }
+}
diff --git a/src/BootstrapBlazor.Server/Components/Components/UpdateIntro.razor.js b/src/BootstrapBlazor.Server/Components/Components/UpdateIntro.razor.js
new file mode 100644
index 000000000..1f0d841dd
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Components/UpdateIntro.razor.js
@@ -0,0 +1,56 @@
+import Data from "../../_content/BootstrapBlazor/modules/data.js?v=$version"
+import EventHandler from "../../_content/BootstrapBlazor/modules/event-handler.js?v=$version"
+
+export function init(id, version) {
+ const el = document.getElementById(id)
+ if (el === null) {
+ return
+ }
+
+ const update = {
+ el,
+ key: `bb_intro_popup:${version}`,
+ }
+ Data.set(id, update)
+
+ check(update.key, update.el);
+ EventHandler.on(el, 'click', '.blazor-intro-button', () => {
+ close(update.key, el)
+ })
+}
+
+export function dispose(id) {
+ Data.remove(id)
+
+ const data = Data.get(id)
+ if (data) {
+ EventHandler.off(data.el, 'click', '.blazor-intro-button');
+ }
+}
+
+const check = (key, el) => {
+ const width = window.innerWidth
+ if (width >= 768) {
+ const isShown = localStorage.getItem(key)
+ if (!isShown) {
+ slideToggle(el)
+
+ // clean
+ for (let index = localStorage.length; index > 0; index--) {
+ const k = localStorage.key(index - 1);
+ if (k.indexOf('bb_intro_popup:') > -1) {
+ localStorage.removeItem(k);
+ }
+ }
+ }
+ }
+}
+
+const slideToggle = el => {
+ el.classList.toggle('show')
+}
+
+const close = (key, el) => {
+ localStorage.setItem(key, 'false')
+ slideToggle(el)
+}
diff --git a/src/BootstrapBlazor.Server/Components/Components/Video.razor b/src/BootstrapBlazor.Server/Components/Components/Video.razor
new file mode 100644
index 000000000..7e51b2bd1
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Components/Video.razor
@@ -0,0 +1,42 @@
+@inject IOptionsMonitor Options
+@inject IStringLocalizer Localizer
+
+@Localizer["H1"]
+
+@if (VideoUrl.Any())
+{
+ foreach (var url in VideoUrl)
+ {
+
+ }
+}
+else
+{
+ @Localizer["L2"]
+}
+
+@code {
+ [NotNull]
+ private List VideoUrl { get; } = new List();
+
+ [Parameter]
+ public string? Name { get; set; }
+
+ ///
+ ///
+ ///
+ protected override void OnInitialized()
+ {
+ base.OnInitialized();
+
+ if (!string.IsNullOrEmpty(Name) && Options.CurrentValue.Videos.TryGetValue(Name, out var url))
+ {
+ if (!string.IsNullOrEmpty(url))
+ {
+ VideoUrl.AddRange(url.Split(';').Select(a => $"{Options.CurrentValue.VideoUrl}{a}"));
+ }
+ }
+ }
+}
diff --git a/src/BootstrapBlazor.Server/Components/Components/WebSiteModuleComponentBase.cs b/src/BootstrapBlazor.Server/Components/Components/WebSiteModuleComponentBase.cs
new file mode 100644
index 000000000..a03633c82
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Components/WebSiteModuleComponentBase.cs
@@ -0,0 +1,21 @@
+// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+// Website: https://www.blazor.zone or https://argozhang.github.io/
+
+namespace BootstrapBlazor.Server.Components.Components;
+
+///
+/// WebSiteModuleComponentBase 组件
+///
+public abstract class WebSiteModuleComponentBase : BootstrapModuleComponentBase
+{
+ ///
+ ///
+ ///
+ protected override void OnLoadJSModule()
+ {
+ base.OnLoadJSModule();
+
+ ModulePath = $"./Components/{ModulePath}";
+ }
+}
diff --git a/src/BootstrapBlazor.Server/Components/Components/Widget.razor b/src/BootstrapBlazor.Server/Components/Components/Widget.razor
new file mode 100644
index 000000000..63591cf3c
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Components/Widget.razor
@@ -0,0 +1,75 @@
+
+
+
+ 您有 4 个未读消息
+
+
+ @for (var index = 0; index < 4; index++)
+ {
+
+
+
+
+
Argo Zhang
+ @(4 + index) mins
+
+
Why not buy a new awesome theme?
+
+
+ }
+
+
+ 查看所有消息
+
+
+
+
+ 您有 10 个未读通知
+
+
+ @for (var index = 0; index < 10; index++)
+ {
+
+
+ 5 new members joined
+
+ }
+
+
+ 查看所有通知
+
+
+
+
+ 您有 3 个任务
+
+
+
+
+ Design some buttons
+ 20%
+
+
+
+
+
+ Create a nice theme
+ 40%
+
+
+
+
+
+ Some task I need to do
+ 60%
+
+
+
+
+
+ 查看所有任务
+
+
+
diff --git a/src/BootstrapBlazor.Server/Components/Components/WinButton.razor b/src/BootstrapBlazor.Server/Components/Components/WinButton.razor
new file mode 100644
index 000000000..3f984881d
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Components/WinButton.razor
@@ -0,0 +1,9 @@
+
+
+@code {
+ [Parameter]
+ public string Text { get; set; } = "Test";
+
+ [Parameter]
+ public Func OnClick { get; set; } = _ => Task.CompletedTask;
+}
diff --git a/src/BootstrapBlazor.Server/Components/Components/Wwads.razor b/src/BootstrapBlazor.Server/Components/Components/Wwads.razor
new file mode 100644
index 000000000..7314d6bbb
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Components/Wwads.razor
@@ -0,0 +1,4 @@
+@inherits WebSiteModuleComponentBase
+@attribute [JSModuleAutoLoader("/Components/Wwads.razor.js", AutoInvokeDispose = false)]
+
+
diff --git a/src/BootstrapBlazor.Server/Components/Components/Wwads.razor.cs b/src/BootstrapBlazor.Server/Components/Components/Wwads.razor.cs
new file mode 100644
index 000000000..3b61d0661
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Components/Wwads.razor.cs
@@ -0,0 +1,25 @@
+// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+// Website: https://www.blazor.zone or https://argozhang.github.io/
+
+namespace BootstrapBlazor.Server.Components.Components;
+
+///
+/// 广告组件
+///
+public partial class Wwads
+{
+ private string? DebugString { get; set; }
+
+ ///
+ ///
+ ///
+ protected override void OnInitialized()
+ {
+ base.OnInitialized();
+
+#if DEBUG
+ DebugString = "true";
+#endif
+ }
+}
diff --git a/src/BootstrapBlazor.Server/Components/Components/Wwads.razor.js b/src/BootstrapBlazor.Server/Components/Components/Wwads.razor.js
new file mode 100644
index 000000000..944eb92c7
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Components/Wwads.razor.js
@@ -0,0 +1,15 @@
+export function init(id) {
+ const ad = document.createElement('div')
+ ad.setAttribute("data-id", 72)
+ ad.classList.add("wwads-cn")
+ ad.classList.add("wwads-horizontal")
+ var el = document.getElementById(id)
+ if (el) {
+ if (el.getAttribute('data-bb-debug') === 'true') {
+ ad.classList.add('debug')
+ }
+
+ const parent = el.parentNode
+ parent.insertBefore(ad, el.nextSibling)
+ }
+}
diff --git a/src/BootstrapBlazor.Server/Components/Layout/BaseLayout.razor b/src/BootstrapBlazor.Server/Components/Layout/BaseLayout.razor
new file mode 100644
index 000000000..23d037532
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Layout/BaseLayout.razor
@@ -0,0 +1,15 @@
+@inherits LayoutComponentBase
+
+
+
+
+
+ @Body
+
+
+
+
+
+
+
+
diff --git a/src/BootstrapBlazor.Server/Components/Layout/BaseLayout.razor.cs b/src/BootstrapBlazor.Server/Components/Layout/BaseLayout.razor.cs
new file mode 100644
index 000000000..3ba662837
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Layout/BaseLayout.razor.cs
@@ -0,0 +1,104 @@
+// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+// Website: https://www.blazor.zone or https://argozhang.github.io/
+
+using Microsoft.Extensions.Options;
+
+namespace BootstrapBlazor.Server.Components.Layout;
+
+///
+/// 母版页基类
+///
+public partial class BaseLayout : IDisposable
+{
+ [Inject]
+ [NotNull]
+ private IStringLocalizer? Localizer { get; set; }
+
+ [Inject]
+ [NotNull]
+ private ToastService? Toast { get; set; }
+
+ [Inject]
+ [NotNull]
+ private IOptionsMonitor? WebsiteOption { get; set; }
+
+ [Inject]
+ [NotNull]
+ private IDispatchService? DispatchService { get; set; }
+
+ [NotNull]
+ private string? FlowText { get; set; }
+
+ [NotNull]
+ private string? InstallAppText { get; set; }
+
+ [NotNull]
+ private string? InstallText { get; set; }
+
+ [NotNull]
+ private string? CancelText { get; set; }
+
+ [NotNull]
+ private string? Title { get; set; }
+
+ [NotNull]
+ private string? ChatTooltip { get; set; }
+
+ ///
+ ///
+ ///
+ protected override void OnInitialized()
+ {
+ base.OnInitialized();
+
+ FlowText ??= Localizer[nameof(FlowText)];
+ InstallAppText ??= Localizer[nameof(InstallAppText)];
+ InstallText ??= Localizer[nameof(InstallText)];
+ CancelText ??= Localizer[nameof(CancelText)];
+ Title ??= Localizer[nameof(Title)];
+ ChatTooltip ??= Localizer[nameof(ChatTooltip)];
+
+ DispatchService.Subscribe(Notify);
+ }
+
+ private async Task Notify(DispatchEntry payload)
+ {
+ if (payload.CanDispatch())
+ {
+ var option = new ToastOption()
+ {
+ Category = ToastCategory.Information,
+ Title = "代码提交推送通知",
+ Delay = 120 * 1000,
+ ForceDelay = true,
+ ChildContent = BootstrapDynamicComponent.CreateComponent(new Dictionary
+ {
+ [nameof(CommitItem.Item)] = payload.Entry
+ }).Render()
+ };
+ await Toast.Show(option);
+ }
+ }
+
+ ///
+ /// 释放资源
+ ///
+ ///
+ private void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ DispatchService.UnSubscribe(Notify);
+ }
+ }
+
+ ///
+ /// 释放资源
+ ///
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+}
diff --git a/src/BootstrapBlazor.Server/Components/Layout/BaseLayout.razor.css b/src/BootstrapBlazor.Server/Components/Layout/BaseLayout.razor.css
new file mode 100644
index 000000000..6087c1fbe
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Layout/BaseLayout.razor.css
@@ -0,0 +1,49 @@
+::deep .btn-fade {
+ --bb-button-circle-width: 40px;
+ --bb-button-circle-height: 40px;
+ opacity: 0.7;
+ box-shadow: 0 0 8px #211b50;
+ transition: opacity .3s linear;
+ position: fixed;
+ z-index: 10;
+}
+
+ ::deep .btn-fade:hover {
+ opacity: 1;
+ }
+
+::deep .btn-update {
+ --bs-btn-bg: #8759ff;
+ --bs-btn-hover-bg: var(--bs-btn-bg);
+ --bs-btn-active-bg: var(--bs-btn-bg);
+ bottom: 5rem;
+ right: 1rem;
+ overflow: hidden;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+}
+
+ ::deep .btn-update img {
+ width: 55%;
+ margin-left: 2px;
+ }
+
+::deep .btn-chat {
+ --bs-btn-bg: #562fff;
+ --bs-btn-hover-bg: #562fff;
+ --bs-btn-active-bg: #562fff;
+ box-shadow: 0 0 8px #6143e2;
+ right: 1rem;
+ bottom: 13rem;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ color: #ddd;
+}
+
+::deep pre {
+ color: #e83e8c;
+ margin-bottom: 0;
+ max-height: 260px;
+}
diff --git a/src/BootstrapBlazor.Server/Components/Layout/ComponentLayout.razor b/src/BootstrapBlazor.Server/Components/Layout/ComponentLayout.razor
new file mode 100644
index 000000000..1a125cbfc
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Layout/ComponentLayout.razor
@@ -0,0 +1,50 @@
+@inherits LayoutComponentBase
+@layout MainLayout
+@inject IOptionsMonitor WebsiteOption
+
+
+
+ @Title
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@Localizer["IconTheme"]
+
+
+
+
+
+
+
+
+
+ @Body
+
+
+
+
+
+
+
+
+
+
+ 交流群
+
+
+
+
diff --git a/src/BootstrapBlazor.Server/Components/Layout/ComponentLayout.razor.cs b/src/BootstrapBlazor.Server/Components/Layout/ComponentLayout.razor.cs
new file mode 100644
index 000000000..ac3fa3f29
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Layout/ComponentLayout.razor.cs
@@ -0,0 +1,155 @@
+// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+// Website: https://www.blazor.zone or https://argozhang.github.io/
+
+using Microsoft.Extensions.Options;
+using Microsoft.JSInterop;
+
+namespace BootstrapBlazor.Server.Components.Layout;
+
+///
+///
+///
+public partial class ComponentLayout : IAsyncDisposable
+{
+ [NotNull]
+ private string? RazorFileName { get; set; }
+
+ [NotNull]
+ private string? CSharpFileName { get; set; }
+
+ [NotNull]
+ private string? VideoFileName { get; set; }
+
+ [NotNull]
+ private string? Title { get; set; }
+
+ [NotNull]
+ private string? Video { get; set; }
+
+ [Inject]
+ [NotNull]
+ private IStringLocalizer? Localizer { get; set; }
+
+ [Inject]
+ [NotNull]
+ private NavigationManager? Navigator { get; set; }
+
+ [Inject]
+ [NotNull]
+ private IJSRuntime? JSRuntime { get; set; }
+
+ [NotNull]
+ private Tab? Tab { get; set; }
+
+ ///
+ /// Instance of
+ ///
+ private JSModule? Module { get; set; }
+
+ ///
+ /// 获得 IVersionService 服务实例
+ ///
+ [Inject]
+ [NotNull]
+ private IVersionService? JSVersionService { get; set; }
+
+ [Inject]
+ [NotNull]
+ private IOptions? IconThemeOptions { get; set; }
+
+ private string GVPUrl => $"{WebsiteOption.CurrentValue.BootstrapBlazorLink}/badge/star.svg?theme=gvp";
+
+ private List IconThemes { get; } = new();
+
+ [NotNull]
+ private string? IconThemeKey { get; set; }
+
+ ///
+ /// OnInitialized 方法
+ ///
+ protected override void OnInitialized()
+ {
+ base.OnInitialized();
+
+ IconThemes.AddRange(new SelectedItem[]
+ {
+ new("fa", "Font Awesome"),
+ new("mdi", "Material Design")
+ });
+ IconThemeKey = IconThemeOptions.Value.ThemeKey;
+
+ Title ??= Localizer[nameof(Title)];
+ Video ??= Localizer[nameof(Video)];
+ }
+
+ ///
+ /// OnParametersSet 方法
+ ///
+ protected override void OnParametersSet()
+ {
+ base.OnParametersSet();
+
+ var url = Navigator.ToBaseRelativePath(Navigator.Uri);
+ var comNameWithHash = url.Split('#').First();
+ var comName = comNameWithHash.Split('?').First();
+ RazorFileName = $"{comName}.razor";
+ CSharpFileName = $"{comName}.razor.cs";
+ VideoFileName = comName;
+
+ Tab?.ActiveTab(0);
+ }
+
+ ///
+ ///
+ ///
+ ///
+ ///
+ protected override async Task OnAfterRenderAsync(bool firstRender)
+ {
+ if (firstRender)
+ {
+ Module = await JSRuntime.LoadModule("./Components/Layout/ComponentLayout.razor.js", JSVersionService.GetVersion());
+ }
+ if (Module != null)
+ {
+ await Module.InvokeVoidAsync("init");
+ }
+ }
+
+ private Task OnIconThemeChanged(string key)
+ {
+ IconThemeOptions.Value.ThemeKey = key;
+
+ Navigator.NavigateTo(Navigator.Uri, true);
+ return Task.CompletedTask;
+ }
+
+ ///
+ ///
+ ///
+ ///
+ ///
+ protected virtual async ValueTask DisposeAsync(bool disposing)
+ {
+ if (disposing)
+ {
+ // 销毁 JSModule
+ if (Module != null)
+ {
+ await Module.DisposeAsync();
+ Module = null;
+ }
+ }
+ }
+
+ ///
+ ///
+ ///
+ ///
+ public async ValueTask DisposeAsync()
+ {
+ await DisposeAsync(true);
+ GC.SuppressFinalize(this);
+ }
+}
diff --git a/src/BootstrapBlazor.Server/Components/Layout/ComponentLayout.razor.css b/src/BootstrapBlazor.Server/Components/Layout/ComponentLayout.razor.css
new file mode 100644
index 000000000..2db04b253
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Layout/ComponentLayout.razor.css
@@ -0,0 +1,56 @@
+.bb-title {
+ font-size: 1.1rem;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ margin-bottom: 0.5rem;
+}
+
+.tab-navigators {
+ position: fixed;
+ right: 1rem;
+ bottom: 13rem;
+ display: flex;
+ flex-direction: column;
+}
+
+ .tab-navigators ::deep .btn {
+ width: 40px;
+ height: 40px;
+ position: relative;
+ font-size: 1.1rem;
+ }
+
+ .tab-navigators ::deep .btn:not(:first-child) {
+ margin-top: 1.5rem;
+ }
+
+.tabs-coms ::deep > .tabs > .tabs-header {
+ position: sticky;
+ top: 0;
+ z-index: 2;
+}
+
+::deep :is(.code-razor, .code-cs) pre {
+ max-height: unset;
+}
+
+::deep .bb-icon {
+ display: none;
+}
+
+::deep .bb-img {
+ display: inline-block;
+ height: 21px;
+ margin-bottom: 0.75rem;
+}
+
+@media (min-width: 576px) {
+ .bb-title {
+ font-size: 1.2rem;
+ }
+
+ ::deep .bb-icon {
+ display: inline-block;
+ }
+}
diff --git a/src/BootstrapBlazor.Server/Components/Layout/ComponentLayout.razor.js b/src/BootstrapBlazor.Server/Components/Layout/ComponentLayout.razor.js
new file mode 100644
index 000000000..ad47be0ad
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Layout/ComponentLayout.razor.js
@@ -0,0 +1,18 @@
+export function init() {
+ const hash = decodeURI(location.hash)
+ if (hash) {
+ const anchor = hash.split('-')[0]
+ try {
+ const el = document.querySelector(anchor)
+ if (el) {
+ const handler = setTimeout(() => {
+ el.scrollIntoView({ behavior: 'smooth', block: 'center' })
+ clearTimeout(handler)
+ }, 1000)
+ }
+ }
+ catch (e) {
+ console.log(e)
+ }
+ }
+}
diff --git a/src/BootstrapBlazor.Server/Components/Layout/DockLayout.razor b/src/BootstrapBlazor.Server/Components/Layout/DockLayout.razor
new file mode 100644
index 000000000..9186cc25b
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Layout/DockLayout.razor
@@ -0,0 +1,6 @@
+@inherits LayoutComponentBase
+@layout ComponentLayout
+
+
+ @Body
+
diff --git a/src/BootstrapBlazor.Server/Components/Layout/DockLayout.razor.cs b/src/BootstrapBlazor.Server/Components/Layout/DockLayout.razor.cs
new file mode 100644
index 000000000..13a21056c
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Layout/DockLayout.razor.cs
@@ -0,0 +1,75 @@
+// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+// Website: https://www.blazor.zone or https://argozhang.github.io/
+
+using Microsoft.JSInterop;
+
+namespace BootstrapBlazor.Server.Components.Layout;
+
+///
+/// DockLayout 布局组件
+///
+public partial class DockLayout : IAsyncDisposable
+{
+ ///
+ /// Instance of
+ ///
+ private JSModule? Module { get; set; }
+
+ ///
+ /// 获得/设置 IJSRuntime 实例
+ ///
+ [Inject]
+ [NotNull]
+ private IJSRuntime? JSRuntime { get; set; }
+
+ ///
+ /// 获得 IVersionService 服务实例
+ ///
+ [Inject]
+ [NotNull]
+ private IVersionService? JSVersionService { get; set; }
+
+ ///
+ ///
+ ///
+ ///
+ ///
+ protected override async Task OnAfterRenderAsync(bool firstRender)
+ {
+ if (firstRender)
+ {
+ Module = await JSRuntime.LoadModule("./Components/Layout/DockLayout.razor.js", JSVersionService.GetVersion());
+ await Module.InvokeVoidAsync("init");
+ }
+ }
+
+ ///
+ ///
+ ///
+ ///
+ ///
+ protected virtual async ValueTask DisposeAsync(bool disposing)
+ {
+ if (disposing)
+ {
+ // 销毁 JSModule
+ if (Module != null)
+ {
+ await Module.InvokeVoidAsync("dispose");
+ await Module.DisposeAsync();
+ Module = null;
+ }
+ }
+ }
+
+ ///
+ ///
+ ///
+ ///
+ public async ValueTask DisposeAsync()
+ {
+ await DisposeAsync(true);
+ GC.SuppressFinalize(this);
+ }
+}
diff --git a/src/BootstrapBlazor.Server/Components/Layout/DockLayout.razor.css b/src/BootstrapBlazor.Server/Components/Layout/DockLayout.razor.css
new file mode 100644
index 000000000..a34c29056
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Layout/DockLayout.razor.css
@@ -0,0 +1,9 @@
+.dock-tabs-body {
+ overflow: hidden;
+ margin: -0.5rem;
+ height: calc(100vh - 134px);
+}
+
+ .dock-tabs-body ::deep .bb-dock {
+ height: 100%;
+ }
diff --git a/src/BootstrapBlazor.Server/Components/Layout/DockLayout.razor.js b/src/BootstrapBlazor.Server/Components/Layout/DockLayout.razor.js
new file mode 100644
index 000000000..f3e8eedac
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Layout/DockLayout.razor.js
@@ -0,0 +1,15 @@
+export function init() {
+ document.body.classList.add("overflow-hidden")
+ const main = document.querySelector('.main')
+ if (main) {
+ main.classList.add('dock-layout')
+ }
+}
+
+export function dispose() {
+ document.body.classList.remove("overflow-hidden")
+ const main = document.querySelector('.main')
+ if (main) {
+ main.classList.remove('dock-layout')
+ }
+}
diff --git a/src/BootstrapBlazor.Server/Components/Layout/HomeLayout.razor b/src/BootstrapBlazor.Server/Components/Layout/HomeLayout.razor
new file mode 100644
index 000000000..f50db40ff
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Layout/HomeLayout.razor
@@ -0,0 +1,204 @@
+@inherits LayoutComponentBase
+@implements IDisposable
+@layout BaseLayout
+@inject NavigationManager NavigationManager
+@inject IJSRuntime JSRuntime
+@inject IOptionsMonitor WebsiteOption
+@inject IStringLocalizer Localizer
+@inject PackageVersionService VersionService
+@inject ICacheManager Cache
+
+@Body
+
+
+
+
+
@Localizer["FooterH1"]
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@Localizer["FriendLink"]
+
+ @foreach (var link in WebsiteOption.CurrentValue.Links)
+ {
+
+
+
+ }
+
+
+
+
@Localizer["Community"]
+
+
+
+
@Localizer["SpecialAcknowledgements"]
+
+
+
+
+
+
+@code {
+ private string Version => Environment.Version.ToString();
+
+ [NotNull]
+ private string? OS { get; set; }
+
+ private string? Runtime { get; set; }
+
+ private string SelectedCulture { get; set; } = CultureInfo.CurrentUICulture.Name;
+
+ private CancellationTokenSource DisposeTokenSource { get; } = new();
+
+ protected override void OnInitialized()
+ {
+ if (System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform(System.Runtime.InteropServices.OSPlatform.Windows))
+ {
+ OS = "Windows";
+ }
+ else if (System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform(System.Runtime.InteropServices.OSPlatform.OSX))
+ {
+ OS = "OSX";
+ }
+ else if (System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform(System.Runtime.InteropServices.OSPlatform.Linux))
+ {
+ OS = "Linux";
+ }
+ else
+ {
+ OS = "Unknown";
+ }
+
+ UpdateRuntime();
+ }
+
+ ///
+ /// OnAfterRenderAsync 方法
+ ///
+ ///
+ ///
+ protected override void OnAfterRender(bool firstRender)
+ {
+ if (firstRender)
+ {
+ _ = Task.Run(async () =>
+ {
+ while (!DisposeTokenSource.IsCancellationRequested)
+ {
+ try
+ {
+ await Task.Delay(1000, DisposeTokenSource.Token);
+ }
+ catch (TaskCanceledException)
+ {
+
+ }
+ if (!DisposeTokenSource.IsCancellationRequested)
+ {
+ UpdateRuntime();
+ await InvokeAsync(StateHasChanged);
+ }
+ }
+ });
+ }
+ }
+
+ private void UpdateRuntime()
+ {
+ var ts = DateTimeOffset.Now - Cache.GetStartTime();
+ Runtime = ts.ToString("dd\\.hh\\:mm\\:ss");
+ }
+
+ private Task SetLang(string cultureName)
+ {
+ //if (OperatingSystem.IsBrowser())
+ //{
+ // if (cultureName != CultureInfo.CurrentCulture.Name)
+ // {
+ // await JSRuntime.SetCulture(cultureName);
+ // var culture = new CultureInfo(cultureName);
+ // CultureInfo.CurrentCulture = culture;
+ // CultureInfo.CurrentUICulture = culture;
+
+ // NavigationManager.NavigateTo(NavigationManager.Uri, forceLoad: true);
+ // }
+ //}
+ //else
+ //{
+ // // 使用 api 方式 适用于 Server-Side 模式
+ // if (SelectedCulture != cultureName)
+ // {
+ // var culture = cultureName;
+ // var uri = new Uri(NavigationManager.Uri).GetComponents(UriComponents.PathAndQuery, UriFormat.Unescaped);
+ // var query = $"?culture={Uri.EscapeDataString(culture)}&redirectUri={Uri.EscapeDataString(uri)}";
+
+ // // use a path that matches your culture redirect controller from the previous steps
+ // NavigationManager.NavigateTo("/Culture/SetCulture" + query, forceLoad: true);
+ // }
+ //}
+
+ return Task.CompletedTask;
+ }
+
+ private void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ DisposeTokenSource.Cancel();
+ DisposeTokenSource.Dispose();
+ }
+ }
+
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+}
diff --git a/src/BootstrapBlazor.Server/Components/Layout/HomeLayout.razor.css b/src/BootstrapBlazor.Server/Components/Layout/HomeLayout.razor.css
new file mode 100644
index 000000000..d73e26bf3
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Layout/HomeLayout.razor.css
@@ -0,0 +1,71 @@
+.footer-body {
+ padding: 1rem;
+ color: #fff;
+ background-color: #5b6e84;
+ margin: 0;
+ display: flex;
+ flex-direction: column;
+ justify-content: space-around;
+}
+
+ .footer-body h4 {
+ margin: 1rem 0;
+ }
+
+ .footer-body ul {
+ list-style: none;
+ padding: 0;
+ margin: 0;
+ }
+
+ .footer-body .footer-link {
+ transition: all .3s linear;
+ color: rgba(255,255,255,.9);
+ text-decoration: none;
+ font-size: 0.875rem;
+ line-height: 2;
+ display: block;
+ cursor: pointer;
+ }
+
+ .footer-body .footer-link:hover,
+ .footer-body .footer-link a:hover {
+ color: #40a9ff;
+ }
+
+ .footer-body .footer-link:not(:last-child) {
+ margin-top: 1rem;
+ }
+
+ .footer-body .footer-link a {
+ transition: all .3s linear;
+ color: #fff;
+ }
+
+.footer-info {
+ background-color: #222;
+ padding: 0 20px;
+ line-height: 42px;
+ color: #9d9d9d;
+}
+
+ .footer-info a {
+ color: #9d9d9d;
+ }
+
+ .footer-info .footer-logo {
+ width: 21px;
+ height: 18px;
+ }
+
+ .footer-info .footer-lang {
+ width: 15px;
+ margin-right: 6px;
+ }
+
+@media (min-width: 768px) {
+ .footer-body {
+ padding: 3rem;
+ flex-direction: row;
+ }
+}
diff --git a/src/BootstrapBlazor.Server/Components/Layout/MainLayout.razor b/src/BootstrapBlazor.Server/Components/Layout/MainLayout.razor
new file mode 100644
index 000000000..141befc33
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Layout/MainLayout.razor
@@ -0,0 +1,17 @@
+@inherits LayoutComponentBase
+@layout BaseLayout
+
+
diff --git a/src/BootstrapBlazor.Server/Components/Layout/MainLayout.razor.cs b/src/BootstrapBlazor.Server/Components/Layout/MainLayout.razor.cs
new file mode 100644
index 000000000..bc8910149
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Layout/MainLayout.razor.cs
@@ -0,0 +1,75 @@
+// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+// Website: https://www.blazor.zone or https://argozhang.github.io/
+
+namespace BootstrapBlazor.Server.Components.Layout;
+
+///
+///
+///
+public partial class MainLayout : IDisposable
+{
+ [Inject]
+ [NotNull]
+ private IDispatchService? DispatchService { get; set; }
+
+ [Inject]
+ [NotNull]
+ private ToastService? Toast { get; set; }
+
+ [Inject]
+ [NotNull]
+ private WebClientService? ClientService { get; set; }
+
+ [Inject]
+ [NotNull]
+ private IIPLocatorProvider? IPLocator { get; set; }
+
+ ///
+ ///
+ ///
+ protected override void OnInitialized()
+ {
+ base.OnInitialized();
+
+ DispatchService.Subscribe(Dispatch);
+ }
+
+ private async Task Dispatch(DispatchEntry entry)
+ {
+ if (entry.Entry != null)
+ {
+ // 获得当前用户 IP 地址
+ var clientInfo = await ClientService.GetClientInfo();
+ if (clientInfo.Ip != null)
+ {
+ var location = await IPLocator.Locate(clientInfo.Ip);
+ await Toast.Show(new ToastOption()
+ {
+ Title = "Dispatch 服务测试",
+ Content = $"{entry.Entry.Message} 来自 {location}",
+ Category = ToastCategory.Information,
+ Delay = 30 * 1000,
+ ForceDelay = true
+ });
+ }
+ }
+ }
+
+ private void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ DispatchService.UnSubscribe(Dispatch);
+ }
+ }
+
+ ///
+ ///
+ ///
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+}
diff --git a/src/BootstrapBlazor.Server/Components/Layout/MainLayout.razor.css b/src/BootstrapBlazor.Server/Components/Layout/MainLayout.razor.css
new file mode 100644
index 000000000..aea3b9b5a
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Layout/MainLayout.razor.css
@@ -0,0 +1,100 @@
+.main {
+ padding: 1rem;
+}
+
+.section {
+ --bb-sidebar-width: 0;
+}
+
+.sidebar-title {
+ height: 50px;
+ align-items: center;
+ padding: 1rem;
+ border-bottom: solid 1px #c0c4cc;
+ display: none;
+}
+
+.sidebar-text {
+ font-weight: 700;
+}
+
+::deep p {
+ line-height: 2;
+}
+
+ ::deep p:last-child {
+ margin-bottom: 0;
+ }
+
+ ::deep p code,
+ ::deep li code {
+ display: inline-block;
+ padding: 0px 8px;
+ background-color: #e9ecef;
+ margin: 0;
+ border-radius: var(--bs-border-radius);
+ }
+
+::deep .code-label {
+ font-weight: bold;
+ color: #333;
+ margin-bottom: 8px;
+}
+
+::deep h4 {
+ margin-top: 1rem;
+ font-size: var(--bb-sub-font-size);
+}
+
+::deep .alert:last-child {
+ margin-bottom: 0;
+}
+
+::deep .alert h4 {
+ margin-top: 0;
+}
+
+::deep .alert-info .fa-lightbulb-o {
+ color: #17a2b8
+}
+
+::deep .wwads-cn {
+ --ad-min-height: 120px;
+ --ad-margin-bottom: 1rem;
+ min-height: var(--ad-min-height);
+ margin-bottom: var(--ad-margin-bottom);
+ overflow: hidden;
+}
+
+ ::deep .wwads-cn.debug {
+ --ad-min-height: 0;
+ --ad-margin-bottom: 0;
+ }
+
+@media (min-width: 768px) {
+ .section {
+ --bb-sidebar-width: 300px;
+ display: flex;
+ flex-direction: row;
+ -webkit-font-smoothing: antialiased;
+ }
+
+ .sidebar-title {
+ display: flex;
+ }
+
+ .sidebar {
+ width: var(--bb-sidebar-width);
+ height: calc(100vh);
+ position: sticky;
+ top: 0;
+ border-right: solid 1px #c0c4cc;
+ background-color: #f0f0f0;
+ margin-top: calc(var(--bs-header-height)*-1);
+ }
+
+ .main {
+ height: 100%;
+ width: calc(100% - var(--bb-sidebar-width));
+ }
+}
diff --git a/src/BootstrapBlazor.Server/Components/Layout/NavMenu.razor b/src/BootstrapBlazor.Server/Components/Layout/NavMenu.razor
new file mode 100644
index 000000000..6cdb7f1b4
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Layout/NavMenu.razor
@@ -0,0 +1,23 @@
+@inherits WebSiteModuleComponentBase
+@attribute [JSModuleAutoLoader("Layout/NavMenu.razor.js")]
+
+
+ Bootstrap Blazor
+
+
+
+
+
+
diff --git a/src/BootstrapBlazor.Server/Components/Layout/NavMenu.razor.cs b/src/BootstrapBlazor.Server/Components/Layout/NavMenu.razor.cs
new file mode 100644
index 000000000..72291c7a4
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Layout/NavMenu.razor.cs
@@ -0,0 +1,72 @@
+// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+// Website: https://www.blazor.zone or https://argozhang.github.io/
+
+using BootstrapBlazor.Server.Components.Pages;
+
+namespace BootstrapBlazor.Server.Components.Layout;
+
+///
+///
+///
+public partial class NavMenu
+{
+ private bool IsAccordion { get; set; }
+
+ private bool IsExpandAll { get; set; }
+
+ [NotNull]
+ private string? AccordionText { get; set; }
+
+ [NotNull]
+ private string? ExpandAllText { get; set; }
+
+ [Inject]
+ [NotNull]
+ private IStringLocalizer? AppLocalizer { get; set; }
+
+ [Inject]
+ [NotNull]
+ private TitleService? TitleService { get; set; }
+
+ [Inject]
+ [NotNull]
+ private IStringLocalizer? Localizer { get; set; }
+
+ [Inject]
+ [NotNull]
+ private MenuService? MenuService { get; set; }
+
+ [NotNull]
+ private List? Menus { get; set; }
+
+ ///
+ ///
+ ///
+ protected override void OnInitialized()
+ {
+ base.OnInitialized();
+
+ Menus = MenuService.GetMenus();
+ Menus.ForEach(m => m.IsCollapsed = true);
+ AccordionText ??= Localizer["MenuAccordion"];
+ ExpandAllText ??= Localizer["MenuExpandAll"];
+ }
+
+ private Task OnValueChanged(bool accordion)
+ {
+ if (accordion)
+ {
+ IsExpandAll = false;
+ }
+ return Task.CompletedTask;
+ }
+
+ private async Task OnClickMenu(MenuItem item)
+ {
+ if (!item.Items.Any() && !string.IsNullOrEmpty(item.Text))
+ {
+ await TitleService.SetTitle($"{item.Text} - {AppLocalizer["Title"]}");
+ }
+ }
+}
diff --git a/src/BootstrapBlazor.Server/Components/Layout/NavMenu.razor.css b/src/BootstrapBlazor.Server/Components/Layout/NavMenu.razor.css
new file mode 100644
index 000000000..62a474e15
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Layout/NavMenu.razor.css
@@ -0,0 +1,72 @@
+.sidebar-switch {
+ display: flex;
+ border-bottom: solid 1px #c0c4cc;
+ justify-content: center;
+ align-items: center;
+}
+
+ .sidebar-switch ::deep .form-label {
+ margin: 0 0.5rem 0 0;
+ }
+
+ .sidebar-switch ::deep .switch {
+ width: auto;
+ }
+
+.navbar {
+ background-color: #8548ff;
+}
+
+.navbar-toggler {
+ background-color: var(--bs-indigo);
+}
+
+.sidebar-content {
+ position: relative;
+}
+
+.sidebar-bar {
+ width: 1px;
+ position: absolute;
+ top: 0;
+ right: 0;
+ bottom: 0;
+ background-color: rgb(208, 215, 222);
+}
+
+ .sidebar-bar .sidebar-body {
+ position: absolute;
+ inset: 0px -2px;
+ cursor: col-resize;
+ background-color: transparent;
+ }
+
+ .sidebar-bar .sidebar-body:hover {
+ background-color: rgba(175, 184, 193, 0.2);
+ }
+
+ .sidebar-bar .sidebar-body.drag,
+ .sidebar-bar .sidebar-body.drag:hover {
+ background-color: rgb(9, 105, 218);
+ }
+
+@media (min-width: 768px) {
+ .sidebar-content {
+ height: calc(100vh - var(--bs-header-height));
+ }
+
+ .sidebar-content.collapse {
+ display: flex;
+ flex-direction: column;
+ }
+
+ ::deep .scroll {
+ overflow-x: hidden;
+ max-height: calc(100% - 36px);
+ padding: 5px 0;
+ }
+
+ ::deep .scroll .menu {
+ width: var(--bb-sidebar-width);
+ }
+}
diff --git a/src/BootstrapBlazor.Server/Components/Layout/NavMenu.razor.js b/src/BootstrapBlazor.Server/Components/Layout/NavMenu.razor.js
new file mode 100644
index 000000000..e88c9c4d8
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Layout/NavMenu.razor.js
@@ -0,0 +1,53 @@
+import Data from "../../_content/BootstrapBlazor/modules/data.js?v=$version"
+import Drag from "../../_content/BootstrapBlazor/modules/drag.js?v=$version"
+import EventHandler from "../../_content/BootstrapBlazor/modules/event-handler.js?v=$version"
+
+export function init(id) {
+ const navmenu = {
+ navbar: document.querySelector('.navbar-toggler'),
+ menu: document.querySelector('.sidebar-content'),
+ bar: document.querySelector('.sidebar-body')
+ }
+ Data.set(id, navmenu)
+
+ EventHandler.on(navmenu.navbar, 'click', () => {
+ navmenu.menu.classList.toggle('show')
+ })
+ EventHandler.on(navmenu.menu, 'click', '.nav-link', e => {
+ const link = e.delegateTarget
+ const url = link.getAttribute('href');
+ if (url !== '#') {
+ navmenu.menu.classList.remove('show')
+ }
+ })
+ let originX = 0
+ let section = document.querySelector('section');
+ let width = 0
+ Drag.drag(navmenu.bar,
+ e => {
+ navmenu.bar.classList.add('drag')
+ width = parseInt(getComputedStyle(section).getPropertyValue('--bb-sidebar-width'))
+ originX = e.clientX || e.touches[0].clientX
+ },
+ e => {
+ const eventX = e.clientX || (e.touches.length > 0 && e.touches[0].clientX)
+ const moveX = eventX - originX
+ const newWidth = width + moveX
+ if (newWidth >= 250 && newWidth <= 380) {
+ section.style.setProperty('--bb-sidebar-width', `${newWidth}px`)
+ }
+ },
+ e => {
+ navmenu.bar.classList.remove('drag')
+ }
+ )
+}
+
+export function dispose(id) {
+ const data = Data.get(id);
+ Data.remove(id);
+
+ EventHandler.off(data.navbar, 'click');
+ EventHandler.off(data.menu, 'click', '.nav-link');
+ Drag.dispose(data.bar)
+}
diff --git a/src/BootstrapBlazor.Server/Components/Layout/PageLayout.razor b/src/BootstrapBlazor.Server/Components/Layout/PageLayout.razor
new file mode 100644
index 000000000..e1caa4023
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Layout/PageLayout.razor
@@ -0,0 +1,145 @@
+@inherits LayoutComponentBase
+@inject IOptionsMonitor WebsiteOption
+
+
+
+
+ Bootstrap of Blazor
+
+
+ 超级管理员
+
+
+
+
+
+
+ 后台管理
+
+
+
+
+
+ 管理员
+
+
+
+
+
+ @Body
+
+
+
+
+
+
+
IsOpen = false)">点击关闭
+
+
布局调整
+
+
+
+ IsFullSide = true)">
+
+
+
+
+
+
+
+ IsFullSide = false)">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
主题配色
+
+
+ Theme = "color1")">
+
+
+ Theme = "color2")">
+
+
+ Theme = "color3")">
+
+
+ Theme = "color4")">
+
+
+ Theme = "color5")">
+
+
+ Theme = "color6")">
+
+
+
+
+
+
更多设置
+
+
+
+
+
+ @(UseTabSet ? "多标签" : "单页")
+
+
+
+
+
+
diff --git a/src/BootstrapBlazor.Server/Components/Layout/PageLayout.razor.cs b/src/BootstrapBlazor.Server/Components/Layout/PageLayout.razor.cs
new file mode 100644
index 000000000..0202c644b
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Layout/PageLayout.razor.cs
@@ -0,0 +1,86 @@
+// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+// Website: https://www.blazor.zone or https://argozhang.github.io/
+
+namespace BootstrapBlazor.Server.Components.Layout;
+
+///
+///
+///
+public sealed partial class PageLayout
+{
+ private bool IsOpen { get; set; }
+
+ private string? Theme { get; set; }
+
+ private string? LayoutClassString => CssBuilder.Default()
+ .AddClass(Theme)
+ .AddClass("is-fixed-tab", IsFixedTab)
+ .Build();
+
+ private IEnumerable? Menus { get; set; }
+
+ ///
+ /// 获得/设置 是否固定 TabHeader
+ ///
+ [Parameter]
+ public bool IsFixedTab { get; set; }
+
+ ///
+ /// 获得/设置 是否固定页头
+ ///
+ [Parameter]
+ public bool IsFixedHeader { get; set; } = true;
+
+ ///
+ /// 获得/设置 是否固定页脚
+ ///
+ [Parameter]
+ public bool IsFixedFooter { get; set; } = true;
+
+ ///
+ /// 获得/设置 侧边栏是否外置
+ ///
+ [Parameter]
+ public bool IsFullSide { get; set; } = true;
+
+ ///
+ /// 获得/设置 是否显示页脚
+ ///
+ [Parameter]
+ public bool ShowFooter { get; set; } = true;
+
+ ///
+ /// 获得/设置 是否开启多标签模式
+ ///
+ [Parameter]
+ public bool UseTabSet { get; set; } = true;
+
+ ///
+ /// OnInitializedAsync 方法
+ ///
+ ///
+ protected override async Task OnInitializedAsync()
+ {
+ await base.OnInitializedAsync();
+
+ // 模拟异步获取菜单数据
+ await Task.Delay(500);
+ Menus = new List
+ {
+ new() { Text = "返回组件库", Icon = "fa-fw fa-solid fa-house", Url = "components" },
+ new() { Text = "后台模拟器", Icon = "fa-fw fa-solid fa-desktop", Url = "layout-page" },
+ new() { Text = "示例网页", Icon = "fa-fw fa-solid fa-laptop", Url = "layout-demo/text=Parameter1" }
+ };
+ }
+
+ ///
+ /// 更新组件方法
+ ///
+ public void Update() => StateHasChanged();
+
+ private void ToggleDrawer()
+ {
+ IsOpen = !IsOpen;
+ }
+}
diff --git a/src/BootstrapBlazor.Server/Components/Layout/PageLayout.razor.css b/src/BootstrapBlazor.Server/Components/Layout/PageLayout.razor.css
new file mode 100644
index 000000000..1a4adbaf6
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Layout/PageLayout.razor.css
@@ -0,0 +1,310 @@
+.layout-logo {
+ border: solid 1px #fff;
+}
+
+.color {
+ width: 1.5rem;
+ height: 1.5rem;
+ display: block;
+ cursor: pointer;
+ border: 2px solid #e9ecef;
+ border-radius: var(--bs-border-radius);
+ transition: border .3s linear;
+}
+
+ .color:hover {
+ border: 2px solid #28a745;
+ }
+
+.color1 {
+ background-color: #409eff;
+}
+
+.color2 {
+ background-color: #28a745;
+}
+
+.color3 {
+ background-color: #e83e8c;
+}
+
+.color4 {
+ background-color: #ffe484;
+}
+
+.color5 {
+ background-color: #17a2b8;
+}
+
+.color6 {
+ background-color: #4a3275;
+}
+
+.color1,
+.layout.is-page.color1 .layout-header {
+ background-color: #409eff;
+}
+
+.layout.is-page.color1 .layout-side .layout-banner {
+ background-color: #3e84d0
+}
+
+.layout.is-page.color1 .layout-side {
+ background-color: #212529;
+ color: var(--bb-disabled-bg);
+}
+
+.layout.is-page.color1 .layout-footer {
+ background-color: #343a40;
+}
+
+.layout.is-page.color1 .layout-header-bar {
+ background-color: #2b7cd0;
+ border-color: #014186;
+}
+
+.layout.is-page.color1 .layout-drawer:hover {
+ background-color: #3184dc;
+}
+
+.color2,
+.layout.is-page.color2 .layout-header {
+ background-color: #28a745;
+}
+
+.layout.is-page.color2 .layout-side .layout-banner {
+ background-color: #24903d
+}
+
+.layout.is-page.color2 .layout-side {
+ background-color: #212529;
+ color: var(--bb-disabled-bg);
+}
+
+.layout.is-page.color2 .layout-footer {
+ background-color: #343a40;
+}
+
+.layout.is-page.color2 .layout-header-bar {
+ background-color: #258c3c;
+ border-color: #014186;
+}
+
+.layout.is-page.color2 .layout-drawer:hover {
+ background-color: #24903d;
+}
+
+.color3,
+.layout.is-page.color3 .layout-header {
+ background-color: #e83e8c;
+}
+
+.layout.is-page.color3 .layout-side .layout-banner {
+ background-color: #c5417e
+}
+
+.layout.is-page.color3 .layout-side {
+ background-color: #212529;
+ color: var(--bb-disabled-bg);
+}
+
+.layout.is-page.color3 .layout-footer {
+ background-color: #343a40;
+}
+
+.layout.is-page.color3 .layout-header-bar {
+ background-color: #c73477;
+ border-color: #014186;
+}
+
+.layout.is-page.color3 .layout-drawer:hover {
+ background-color: #c5417e;
+}
+
+.color4,
+.layout.is-page.color4 .layout-header {
+ background-color: #ffc107;
+}
+
+.layout.is-page.color4 .layout-side .layout-banner {
+ background-color: #e4af10
+}
+
+.layout.is-page.color4 .layout-side {
+ background-color: #212529;
+ color: var(--bb-disabled-bg);
+}
+
+.layout.is-page.color4 .layout-footer {
+ background-color: #343a40;
+}
+
+.layout.is-page.color4 .layout-header-bar {
+ background-color: #e2b221;
+ border-color: #014186;
+}
+
+.layout.is-page.color4 .layout-drawer:hover {
+ background-color: #e4af10;
+}
+
+.color5,
+.layout.is-page.color5 .layout-header {
+ background-color: #17a2b8;
+}
+
+.color6,
+.layout.is-page.color6 .layout-header {
+ background-color: #6610f2;
+}
+
+.layout.is-page.color6 .layout-side .layout-banner {
+ background-color: #4b0cb3
+}
+
+.layout.is-page.color6 .layout-side {
+ background-color: #212529;
+ color: var(--bb-disabled-bg);
+}
+
+.layout.is-page.color6 .layout-footer {
+ background-color: #343a40;
+}
+
+.layout.is-page.color6 .layout-header-bar {
+ background-color: #4b0ab5;
+ border-color: #014186;
+}
+
+.layout.is-page.color6 .layout-drawer:hover {
+ background-color: #4b0cb3;
+}
+
+.layout-drawer {
+ padding: 13px;
+ margin-right: -1rem;
+ cursor: pointer;
+}
+
+ .layout-drawer:hover {
+ background-color: #1893a7;
+ }
+
+.layout-drawer-body {
+ padding: 1rem;
+}
+
+.layout-item {
+ cursor: pointer;
+ border: 2px solid #e9ecef;
+ padding: 4px;
+ border-radius: var(--bs-border-radius);
+ height: 80px;
+ width: 120px;
+ transition: border .3s linear;
+}
+
+ .layout-item:hover,
+ .layout-item.active {
+ border: 2px solid #28a745;
+ }
+
+ .layout-item .layout-left {
+ width: 30%;
+ }
+
+ .layout-item .layout-left .layout-left-header {
+ height: 16px;
+ background-color: var(--bb-layout-sidebar-banner-background);
+ }
+
+ .layout-item .layout-left .layout-left-body,
+ .layout-item .layout-body .layout-left {
+ background-color: #2f4050;
+ }
+
+ .layout-item .layout-right .layout-right-header,
+ .layout-item .layout-top {
+ background-color: #17a2b8;
+ height: 16px;
+ }
+
+ .layout-item .layout-right .layout-right-footer,
+ .layout-item .layout-footer {
+ background-color: #5b6e84;
+ height: 12px;
+ }
+
+ .layout-item .layout-top,
+ .layout-item .layout-body,
+ .layout-item .layout-footer {
+ width: 100%;
+ }
+
+.layout.is-page .layout-right {
+ background-color: #fff;
+}
+
+::deep + .widget .dropdown-body h3 {
+ color: #666666;
+ font-size: 14px;
+ margin-bottom: 10px;
+}
+
+::deep + .widget .dropdown-body h4 {
+ color: #444444;
+ font-size: 15px;
+ margin: 0;
+}
+
+::deep + .widget .dropdown-body small {
+ color: #999999;
+ font-size: 10px;
+ position: absolute;
+ top: 0;
+ right: 0;
+}
+
+::deep + .widget .dropdown-item > div:not(.progress):last-child {
+ width: calc(100% - 40px);
+}
+
+::deep + .widget .dropdown-item {
+ padding: 0.5rem 1rem;
+}
+
+::deep + .widget .progress {
+ height: 7px;
+}
+
+::deep + .widget .dropdown-item.active,
+::deep + .widget .dropdown-item:active {
+ color: inherit;
+}
+
+::deep + .widget .dropdown-item:not(:nth-of-type(odd)):active {
+ background-color: inherit;
+}
+
+.page-layout-demo-option {
+ margin-top: 1.5rem;
+ border: 1px solid rgba(0,0,0,.125);
+ border-radius: var(--bs-border-radius);
+ padding: 1.5rem 1rem 1rem 1rem;
+ position: relative;
+}
+
+ .page-layout-demo-option > p {
+ position: absolute;
+ top: -10px;
+ padding: 0 0.5rem;
+ background: #fff;
+ }
+
+ .page-layout-demo-option .tabs-body-content {
+ margin: 0 -1rem -2rem -1rem;
+ }
+
+.page-layout-demo-footer-link {
+ color: #fff;
+}
diff --git a/src/BootstrapBlazor.Server/Components/Layout/PracticeLayout.razor b/src/BootstrapBlazor.Server/Components/Layout/PracticeLayout.razor
new file mode 100644
index 000000000..0f7c7b8bd
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Layout/PracticeLayout.razor
@@ -0,0 +1,17 @@
+@inherits LayoutComponentBase
+@layout BaseLayout
+
+
diff --git a/src/BootstrapBlazor.Server/Components/Layout/PracticeLayout.razor.css b/src/BootstrapBlazor.Server/Components/Layout/PracticeLayout.razor.css
new file mode 100644
index 000000000..31b38341c
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Layout/PracticeLayout.razor.css
@@ -0,0 +1,73 @@
+.section {
+ --bb-sidebar-width: 0;
+}
+
+.main {
+ padding: 1rem;
+}
+
+.sidebar-title {
+ height: 50px;
+ align-items: center;
+ padding: 1rem;
+ border-bottom: solid 1px #c0c4cc;
+ display: none;
+}
+
+.sidebar-text {
+ font-weight: 700;
+}
+
+::deep p {
+ line-height: 2;
+}
+
+ ::deep p:last-child {
+ margin-bottom: 0;
+ }
+
+::deep .wwads-cn {
+ --ad-min-height: 120px;
+ --ad-margin-bottom: 1rem;
+ min-height: var(--ad-min-height);
+ margin-bottom: var(--ad-margin-bottom);
+ overflow: hidden;
+ position: absolute;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ margin: .5rem;
+}
+
+ ::deep .wwads-cn.debug {
+ --ad-min-height: 0;
+ --ad-margin-bottom: 0;
+ }
+
+@media (min-width: 768px) {
+ .section {
+ --bb-sidebar-width: 300px;
+ display: flex;
+ flex-direction: row;
+ -webkit-font-smoothing: antialiased;
+ }
+
+ .sidebar-title {
+ display: flex;
+ }
+
+ .sidebar {
+ width: var(--bb-sidebar-width);
+ height: calc(100vh);
+ position: sticky;
+ top: 0;
+ border-right: solid 1px #c0c4cc;
+ background-color: #f0f0f0;
+ margin-top: calc(var(--bs-header-height)*-1);
+ }
+
+ .main {
+ flex: 1;
+ height: 100%;
+ }
+}
diff --git a/src/BootstrapBlazor.Server/Components/Layout/PracticeLoginLayout.razor b/src/BootstrapBlazor.Server/Components/Layout/PracticeLoginLayout.razor
new file mode 100644
index 000000000..49379bac4
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Layout/PracticeLoginLayout.razor
@@ -0,0 +1,22 @@
+@inherits LayoutComponentBase
+@layout PracticeLayout
+
+
+
+
+
+
+
+ @Body
+
+
+
+
+
+
+
+@code
+{
+ [NotNull]
+ private LoginModel? Model { get; set; } = new();
+}
diff --git a/src/BootstrapBlazor.Server/Components/Layout/PracticeLoginLayout.razor.css b/src/BootstrapBlazor.Server/Components/Layout/PracticeLoginLayout.razor.css
new file mode 100644
index 000000000..452b087b3
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Layout/PracticeLoginLayout.razor.css
@@ -0,0 +1,34 @@
+.container {
+ --login-max-width: 540px;
+ --login-padding-x: 1.5rem;
+ --login-padding-y: .75rem;
+ --bs-border-radius: 23px;
+ max-width: var(--login-max-width);
+ margin: 0 auto;
+}
+
+::deep h4 {
+ margin-bottom: 1.5rem;
+}
+
+::deep .form-control {
+ --bb-form-control-padding: var(--login-padding-y) var(--login-padding-x);
+ font-size: .875rem;
+ margin-bottom: 1rem;
+}
+
+::deep .btn {
+ --bs-btn-padding-x: var(--login-padding-x);
+ --bs-btn-padding-y: var(--login-padding-y);
+ width: 100%;
+ margin-bottom: 1rem;
+}
+
+ ::deep .btn:first-of-type {
+ margin-bottom: 0;
+ }
+
+::deep .form-check {
+ padding: var(--login-padding-y) var(--login-padding-x);
+ margin-bottom: 1rem;
+}
diff --git a/src/BootstrapBlazor.Server/Components/Layout/PracticeNavMenu.razor b/src/BootstrapBlazor.Server/Components/Layout/PracticeNavMenu.razor
new file mode 100644
index 000000000..bc0aff71f
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Layout/PracticeNavMenu.razor
@@ -0,0 +1,16 @@
+@inherits WebSiteModuleComponentBase
+@attribute [JSModuleAutoLoader("Layout/NavMenu.razor.js")]
+@inject DownloadService DownloadService
+
+
+
+
diff --git a/src/BootstrapBlazor.Server/Components/Layout/PracticeNavMenu.razor.cs b/src/BootstrapBlazor.Server/Components/Layout/PracticeNavMenu.razor.cs
new file mode 100644
index 000000000..f5cce75e6
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Layout/PracticeNavMenu.razor.cs
@@ -0,0 +1,259 @@
+// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+// Website: https://www.blazor.zone or https://argozhang.github.io/
+
+using BootstrapBlazor.Server.Components.Pages;
+using Microsoft.AspNetCore.Components.Web;
+using System.Text;
+
+namespace BootstrapBlazor.Server.Components.Layout;
+
+///
+/// 实战栏目侧边菜单
+///
+public partial class PracticeNavMenu
+{
+ [Inject]
+ [NotNull]
+ private IStringLocalizer? AppLocalizer { get; set; }
+
+ [Inject]
+ [NotNull]
+ private TitleService? TitleService { get; set; }
+
+ [Inject]
+ [NotNull]
+ private CodeSnippetService? CodeSnippetService { get; set; }
+
+ [Inject]
+ [NotNull]
+ private IZipArchiveService? ZipArchiveService { get; set; }
+
+ [NotNull]
+ private List? Menus { get; set; }
+
+ ///
+ ///
+ ///
+ protected override async Task OnInitializedAsync()
+ {
+ await base.OnInitializedAsync();
+
+ Menus =
+ [
+ new MenuItem()
+ {
+ Template = CreateDownloadButtonComponent("dashboard", dashboardFileList),
+ Text = "仪表盘 Dashboard",
+ Url = "practice/dashboard"
+ },
+ new MenuItem()
+ {
+ Text = "登陆和注册 Login & Register",
+ Url = "practice/login",
+ Items = new List()
+ {
+ //new()
+ //{
+ // Template = CreateDownloadButtonComponent("template1", Template1),
+ // Text = "模板 Template 1",
+ // Url = "template1"
+ //},
+ //new()
+ //{
+ // Template = CreateDownloadButtonComponent("template2", Template2),
+ // Text = "模板 Template 2",
+ // Url = "template2",
+ //},
+ //new()
+ //{
+ // Template = CreateDownloadButtonComponent("template3", Template3),
+ // Text = "模板 Template 3",
+ // Url = "template3"
+ //},
+ //new()
+ //{
+ // Template = CreateDownloadButtonComponent("template4", Template4),
+ // Text = "模板 Template 4",
+ // Url = "template4"
+ //},
+ //new()
+ //{
+ // Template = CreateDownloadButtonComponent("template5", Template5),
+ // Text = "模板 Template 5",
+ // Url = "template5"
+ //},
+ new()
+ {
+ Template = CreateDownloadButtonComponent("template6", Template6),
+ Text = "模板 Template 6",
+ Url = "template6"
+ },
+ new()
+ {
+ Template = CreateDownloadButtonComponent("template7", Template7),
+ Text = "模板 Template 7",
+ Url = "template7"
+ },
+ new()
+ {
+ Template = CreateDownloadButtonComponent("template8", Template8),
+ Text = "模板 Template 8",
+ Url = "template8"
+ },
+ new()
+ {
+ Template = CreateDownloadButtonComponent("template9", Template9),
+ Text = "模板 Template 9",
+ Url = "template9"
+ }
+ }
+ },
+ new MenuItem()
+ {
+ Template = CreateDownloadButtonComponent("waterfall", waterfallFileList),
+ Text = "瀑布流图片 Waterfall",
+ Url = "practice/waterfall"
+ }
+ ];
+ }
+
+ ///
+ /// OnClickMenu 回调
+ ///
+ ///
+ ///
+ private async Task OnClickMenu(MenuItem item)
+ {
+ if (!item.Items.Any() && !string.IsNullOrEmpty(item.Text))
+ {
+ await TitleService.SetTitle($"{item.Text} - {AppLocalizer["Title"]}");
+ }
+ }
+
+ ///
+ /// 动态创建下载按钮
+ ///
+ ///
+ ///
+ ///
+ private RenderFragment CreateDownloadButtonComponent(string name, string[] fileList) => BootstrapDynamicComponent.CreateComponent(new Dictionary
+ {
+ [nameof(Button.Color)] = Color.Danger,
+ [nameof(Button.Icon)] = "fas fa-download",
+ [nameof(Button.Size)] = Size.ExtraSmall,
+ [nameof(Button.OnClick)] = EventCallback.Factory.Create(this, () => DownloadZipArchive(name, fileList))
+ }).Render();
+
+ ///
+ /// 打包并下载源码
+ ///
+ ///
+ ///
+ ///
+ private async Task DownloadZipArchive(string name, string[] fileList)
+ {
+ using var stream = await ZipArchiveService.ArchiveAsync(fileList, new ArchiveOptions()
+ {
+ ReadStreamAsync = async file =>
+ {
+ var code = await CodeSnippetService.GetFileContentAsync(file);
+ return new MemoryStream(Encoding.UTF8.GetBytes(code));
+ }
+ });
+ await DownloadService.DownloadFromStreamAsync($"BootstrapBlazor-{name}.zip", stream);
+ stream.Close();
+ }
+
+ private readonly string[] dashboardFileList = new[]
+ {
+ "Practices/Dashboard.razor",
+ "Practices/Dashboard.razor.cs",
+ "Practices/Dashboard.razor.css",
+ "Practices/DashboardData.cs",
+ "Services/DashboardService.cs"
+ };
+
+ private readonly string[] Template1 = new[]
+ {
+ "Practices/LoginAndRegister/Template1.razor",
+ "Practices/LoginAndRegister/Template1.razor.css",
+ };
+
+ private readonly string[] Template2 = new[]
+ {
+ "Practices/LoginAndRegister/Template2.razor",
+ "Practices/LoginAndRegister/Template2.razor.css",
+ };
+
+ private readonly string[] Template3 = new[]
+ {
+ "Practices/LoginAndRegister/Template3.razor",
+ "Practices/LoginAndRegister/Template3.razor.css",
+ };
+
+ private readonly string[] Template4 = new[]
+ {
+ "Practices/LoginAndRegister/Template4.razor",
+ "Practices/LoginAndRegister/Template4.razor.css",
+ "Practices/LoginAndRegister/Template4.razor.js",
+ };
+
+ private readonly string[] Template5 = new[]
+ {
+ "Practices/LoginAndRegister/Template5.razor",
+ "Practices/LoginAndRegister/Template5.razor.css",
+ "Practices/LoginAndRegister/Template5.razor.js",
+ };
+
+ private readonly string[] Template6 = new[]
+ {
+ "Practices/LoginAndRegister/Template6.razor",
+ "Practices/LoginAndRegister/Template6.razor.css",
+ "Shared/PracticeLayout.razor",
+ "Shared/PracticeLayout.razor.cs",
+ "Shared/PracticeLayout.razor.css",
+ "Shared/PracticeLoginLayout.razor",
+ "Shared/PracticeLoginLayout.razor.css"
+ };
+
+ private readonly string[] Template7 = new[]
+ {
+ "Practices/LoginAndRegister/Template7.razor",
+ "Practices/LoginAndRegister/Template7.razor.css",
+ "Shared/PracticeLayout.razor",
+ "Shared/PracticeLayout.razor.cs",
+ "Shared/PracticeLayout.razor.css",
+ "Shared/PracticeLoginLayout.razor",
+ "Shared/PracticeLoginLayout.razor.css"
+ };
+
+ private readonly string[] Template8 = new[]
+ {
+ "Practices/LoginAndRegister/Template8.razor",
+ "Practices/LoginAndRegister/Template8.razor.css",
+ "Shared/PracticeLayout.razor",
+ "Shared/PracticeLayout.razor.cs",
+ "Shared/PracticeLayout.razor.css",
+ "Shared/PracticeLoginLayout.razor",
+ "Shared/PracticeLoginLayout.razor.css"
+ };
+
+ private readonly string[] Template9 = new[]
+ {
+ "Practices/LoginAndRegister/Template9.razor",
+ "Practices/LoginAndRegister/Template9.razor.css",
+ "Shared/PracticeLayout.razor",
+ "Shared/PracticeLayout.razor.cs",
+ "Shared/PracticeLayout.razor.css",
+ "Shared/PracticeLoginLayout.razor",
+ "Shared/PracticeLoginLayout.razor.css"
+ };
+
+ private readonly string[] waterfallFileList = new[]
+ {
+ "Practices/Waterfall.razor",
+ "Practices/Waterfall.razor.cs",
+ "Practices/Waterfall.razor.css"
+ };
+}
diff --git a/src/BootstrapBlazor.Server/Components/Layout/PracticeNavMenu.razor.css b/src/BootstrapBlazor.Server/Components/Layout/PracticeNavMenu.razor.css
new file mode 100644
index 000000000..4151d020a
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Layout/PracticeNavMenu.razor.css
@@ -0,0 +1,43 @@
+.switchs {
+ display: flex;
+ border-bottom: solid 1px #c0c4cc;
+ justify-content: center;
+ align-items: center;
+}
+
+ .switchs ::deep .form-label {
+ margin: 0 0.5rem 0 0;
+ }
+
+ .switchs ::deep .switch {
+ width: auto;
+ }
+
+.navbar {
+ background-color: #8548ff;
+}
+
+.navbar-toggler {
+ background-color: var(--bs-indigo);
+}
+
+@media (min-width: 768px) {
+ .sidebar-content {
+ height: calc(100vh - var(--bs-header-height));
+ }
+
+ .sidebar-content.collapse {
+ display: flex;
+ flex-direction: column;
+ }
+
+ ::deep .scroll {
+ overflow-x: hidden;
+ max-height: calc(100% - 36px);
+ padding: 5px 0;
+ }
+
+ ::deep .scroll .menu {
+ width: var(--bb-sidebar-width);
+ }
+}
diff --git a/src/BootstrapBlazor.Server/Components/Layout/PrintLayout.razor b/src/BootstrapBlazor.Server/Components/Layout/PrintLayout.razor
new file mode 100644
index 000000000..e1a9a7567
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Layout/PrintLayout.razor
@@ -0,0 +1,3 @@
+@inherits LayoutComponentBase
+
+@Body
diff --git a/src/BootstrapBlazor.Server/Components/Pages/App.razor b/src/BootstrapBlazor.Server/Components/Pages/App.razor
new file mode 100644
index 000000000..12246c34f
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Pages/App.razor
@@ -0,0 +1,57 @@
+@inject IHostEnvironment Env
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ @if (Env.IsDevelopment())
+ {
+
+ }
+ @if (Env.IsProduction())
+ {
+
+ }
+
+ @if (Env.IsProduction())
+ {
+
+
+
+ }
+
+
+
diff --git a/src/BootstrapBlazor.Server/Components/Pages/Breakpoints.razor b/src/BootstrapBlazor.Server/Components/Pages/Breakpoints.razor
new file mode 100644
index 000000000..c4cdf7532
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Pages/Breakpoints.razor
@@ -0,0 +1,58 @@
+@page "/breakpoint"
+@inject IStringLocalizer Localizer
+
+@Localizer["Heading"]
+
+@Localizer["Heading1"]
+
+@Localizer["Paragraph1"]
+
+
+ @Localizer["Paragraph2"]
+
+
+
+
+
+ @Localizer["TableHeading1"]
+ @Localizer["TableHeading2"]
+ @Localizer["TableHeading3"]
+
+
+
+
+ @Localizer["Name1"]
+ xs
+ < 576 @Localizer["Amount"]
+
+
+ @Localizer["Name2"]
+ sm
+ >= 576 @Localizer["Amount"]
+
+
+ @Localizer["Name3"]
+ md
+ >= 768 @Localizer["Amount"]
+
+
+ @Localizer["Name4"]
+ lg
+ >= 992 @Localizer["Amount"]
+
+
+ @Localizer["Name5"]
+ xl
+ >= 1200 @Localizer["Amount"]
+
+
+ @Localizer["Name6"]
+ xxl
+ >= 1400 @Localizer["Amount"]
+
+
+
+
+
+ @Localizer["Footer1"] xxl
@Localizer["Footer2"] Dialog
@Localizer["Footer3"] dialog-xxl
+
diff --git a/src/BootstrapBlazor.Server/Components/Pages/Breakpoints.razor.css b/src/BootstrapBlazor.Server/Components/Pages/Breakpoints.razor.css
new file mode 100644
index 000000000..8a7116d71
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Pages/Breakpoints.razor.css
@@ -0,0 +1,4 @@
+thead tr th:last-child,
+tbody tr td:last-child {
+ text-align: right;
+}
diff --git a/src/BootstrapBlazor.Server/Components/Pages/Coms.razor b/src/BootstrapBlazor.Server/Components/Pages/Coms.razor
new file mode 100644
index 000000000..7fb1b9c14
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Pages/Coms.razor
@@ -0,0 +1,157 @@
+@page "/components"
+@inject IStringLocalizer Localizer
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/BootstrapBlazor.Server/Components/Pages/Coms.razor.cs b/src/BootstrapBlazor.Server/Components/Pages/Coms.razor.cs
new file mode 100644
index 000000000..89085039e
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Pages/Coms.razor.cs
@@ -0,0 +1,23 @@
+// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+// Website: https://www.blazor.zone or https://argozhang.github.io/
+
+namespace BootstrapBlazor.Server.Components.Pages;
+
+///
+///
+///
+public sealed partial class Coms
+{
+ private List ComponentItems { get; } = [];
+
+ private string? SearchText { get; set; }
+
+ private Task OnSearch(string searchText)
+ {
+ SearchText = searchText;
+
+ StateHasChanged();
+ return Task.CompletedTask;
+ }
+}
diff --git a/src/BootstrapBlazor.Server/Components/Pages/Coms.razor.css b/src/BootstrapBlazor.Server/Components/Pages/Coms.razor.css
new file mode 100644
index 000000000..1a82ec02a
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Pages/Coms.razor.css
@@ -0,0 +1,26 @@
+.coms-search {
+ position: sticky;
+ z-index: 1;
+ top: 0;
+}
+
+ .coms-search .row {
+ padding: 1rem 0;
+ background: #fff;
+ }
+
+.coms-search-filter {
+ height: 2rem;
+ width: 100%;
+ background: linear-gradient(rgba(255,255,255,1),rgba(255,255,255,0.8),rgba(255,255,255,0));
+}
+
+@media (min-width: 768px) {
+ .coms-search {
+ top: 3rem;
+ }
+
+ .coms-search.hide {
+ top: 0;
+ }
+}
diff --git a/src/BootstrapBlazor.Server/Components/Pages/Error.razor b/src/BootstrapBlazor.Server/Components/Pages/Error.razor
new file mode 100644
index 000000000..79929d783
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Pages/Error.razor
@@ -0,0 +1,16 @@
+@page "/error"
+
+
+Error.
+An error occurred while processing your request.
+
+Development Mode
+
+ Swapping to Development environment will display more detailed information about the error that occurred.
+
+
+ The Development environment shouldn't be enabled for deployed applications.
+ It can result in displaying sensitive information from exceptions to end users.
+ For local debugging, enable the Development environment by setting the ASPNETCORE_ENVIRONMENT environment variable to Development
+ and restarting the app.
+
\ No newline at end of file
diff --git a/src/BootstrapBlazor.Server/Components/Pages/Golbalization.razor b/src/BootstrapBlazor.Server/Components/Pages/Golbalization.razor
new file mode 100644
index 000000000..852c8de9c
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Pages/Golbalization.razor
@@ -0,0 +1,8 @@
+@page "/globalization"
+@inject IStringLocalizer Localizer
+
+@Localizer["Title"]
+
+@Localizer["SubTitle"]
+
+@((MarkupString)Localizer["P1"].Value)
diff --git a/src/BootstrapBlazor.Server/Components/Pages/Index.razor b/src/BootstrapBlazor.Server/Components/Pages/Index.razor
new file mode 100644
index 000000000..b8a93edff
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Pages/Index.razor
@@ -0,0 +1,161 @@
+@layout HomeLayout
+@inherits WebSiteModuleComponentBase
+@attribute [JSModuleAutoLoader("Pages/Index.razor.js")]
+@page "/"
+@page "/index"
+@page "/home"
+
+
+
+
+
+
+
+
+
+
+
+
+
+ @Localizer["CarouselH1"]
+ @Localizer["CarouselP1"]
+
+
+
+
+
+
+
+ @Localizer["CarouselH2"]
+ @Localizer["CarouselP2"]
+
+
+
+
+
+
+
+ @Localizer["CarouselH3"]
+ @Localizer["CarouselP3"]
+
+
+
+
+
+
+
+ @Localizer["CarouselH4"]
+ @Localizer["CarouselP4"]
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@Localizer["ContainerH1"]
+
@((MarkupString)Localizer["ContainerD1", Options.CurrentValue.TotalCount].Value)
+
+
+
+
+
+
+
+
@Localizer["ContainerH2"]
+
@Localizer["ContainerD2"]
+
+
+
+
+
+
+
+
@Localizer["ContainerH3"]
+
@Localizer["ContainerD3"]
+
+
+
+
+
+
+
+
@Localizer["ContainerH4"]
+
@Localizer["ContainerD4"]
+
+
+
+
+
+
+
+
@Localizer["ContainerH5"]
+
@Localizer["ContainerD5"]
+
+
+
+
+
+
+
+
@Localizer["ContainerH6"]
+
@Localizer["ContainerD6"]
+
+
+
+
+
+
@Localizer["DonateH1"]
+
@Localizer["DonateH2"]
+
+
+
diff --git a/src/BootstrapBlazor.Server/Components/Pages/Index.razor.cs b/src/BootstrapBlazor.Server/Components/Pages/Index.razor.cs
new file mode 100644
index 000000000..a07d02cf2
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Pages/Index.razor.cs
@@ -0,0 +1,30 @@
+// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+// Website: https://www.blazor.zone or https://argozhang.github.io/
+
+using Microsoft.Extensions.Options;
+
+namespace BootstrapBlazor.Server.Components.Pages;
+
+///
+/// Index 组件
+///
+public partial class Index
+{
+ private string? BodyClassString => CssBuilder.Default(Localizer["BodyClassString"])
+ .Build();
+
+ [Inject]
+ [NotNull]
+ private IStringLocalizer? Localizer { get; set; }
+
+ [Inject]
+ [NotNull]
+ private IOptionsMonitor? Options { get; set; }
+
+ ///
+ ///
+ ///
+ ///
+ protected override Task InvokeInitAsync() => InvokeVoidAsync("init", Id, Localizer["DynamicText"].Value.ToCharArray(), Localizer["DynamicText1"].Value.ToCharArray(), Localizer["DynamicText2"].Value.ToCharArray());
+}
diff --git a/src/BootstrapBlazor.Server/Components/Pages/Index.razor.css b/src/BootstrapBlazor.Server/Components/Pages/Index.razor.css
new file mode 100644
index 000000000..69e1b5c18
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Pages/Index.razor.css
@@ -0,0 +1,196 @@
+.welcome {
+ margin-bottom: 2rem;
+ line-height: 1.75;
+}
+
+ .welcome ::deep .carousel {
+ padding: 1rem;
+ height: 380px;
+ display: flex;
+ flex-direction: column;
+ border-radius: var(--bs-border-radius);
+ border: 1px solid #dce3e8;
+ padding: 1rem;
+ }
+
+ .welcome ::deep .carousel img {
+ width: 100%;
+ height: auto;
+ }
+
+ .welcome ::deep .carousel .carousel-caption {
+ position: absolute;
+ margin-top: 1rem;
+ color: #607D8B;
+ border-top: solid 1px #dce3e8;
+ height: 120px;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ }
+
+ .welcome ::deep .carousel .carousel-indicators [data-bs-target] {
+ background-color: #607D8B;
+ }
+
+.welcome-header {
+ margin-bottom: 2rem;
+ margin-top: 2rem;
+ font-size: 1rem;
+ line-height: 2;
+}
+
+.welcome-body {
+ font-size: 22px;
+ margin-top: 1rem;
+ margin-bottom: 1rem;
+ letter-spacing: 2px;
+}
+
+ .welcome-body .typed {
+ color: #0073dc;
+ font-weight: 500;
+ }
+
+ .welcome-body .typed-cursor {
+ color: #0073dc;
+ }
+
+ .welcome-body .typed-cursor {
+ animation: flash 1s ease-in-out infinite;
+ }
+
+ .welcome-body .typed-cursor.active {
+ animation: none;
+ }
+
+.welcome-body-en {
+ font-size: 32px;
+ margin-top: 2rem;
+ line-height: 1.5;
+}
+
+ .welcome-body-en .typed {
+ color: #0073dc;
+ font-weight: 500;
+ }
+
+@keyframes flash {
+ 0%, 100% {
+ opacity: 1;
+ }
+
+ 50% {
+ opacity: 0;
+ }
+}
+
+.welcome-footer {
+ display: flex;
+ flex-direction: column;
+}
+
+ .welcome-footer div:not(:last-child) {
+ margin-bottom: 1rem;
+ }
+
+ .welcome-footer div {
+ justify-content: space-between;
+ }
+
+ .welcome-footer .tag {
+ cursor: pointer;
+ }
+
+.intro p {
+ font-size: 15px;
+ color: #1a1a1a;
+ letter-spacing: .41px;
+ text-align: left;
+ line-height: 24px;
+}
+
+.intro h3 {
+ color: #1a1a1a;
+ letter-spacing: .1px;
+ text-align: left;
+ line-height: 25px;
+ font-weight: 400;
+ margin: 15px 0;
+ font-size: 1.25rem;
+}
+
+.donate {
+ margin-top: 2rem;
+ margin-bottom: 2rem;
+ padding-top: 2rem;
+ text-align: center;
+ border-top: solid 1px #ddd;
+ position: relative;
+}
+
+ .donate h3 {
+ margin-bottom: 1.5rem;
+ }
+
+ .donate .barcode {
+ width: 280px;
+ }
+
+@media (max-width: 576px) {
+ .intro .card {
+ border-color: transparent !important;
+ }
+}
+
+@media (min-width: 576px) {
+ .intro .card {
+ border-color: #dce3e8;
+ height: 263px;
+ width: 100%;
+ padding: 1rem;
+ cursor: pointer;
+ transition: all .3s ease-in-out;
+ }
+
+ .intro .card:hover,
+ .coms-demo .card:hover {
+ box-shadow: 0 1px 7px 0 rgba(0,0,0,0.05), 0 2px 8px 0 rgba(0,0,0,0.07), 0 3px 9px 0 rgba(0,0,0,0.06), 0 5px 10px 0 rgba(0,0,0,0.03);
+ }
+
+ .intro .card p, .intro .card, .intro .card h3 {
+ text-align: center;
+ }
+}
+
+@media (min-width: 768px) {
+ .welcome-header {
+ margin-top: 0;
+ margin-bottom: 0;
+ }
+
+ .donate .barcode {
+ width: 480px;
+ }
+}
+
+@media (min-width: 992px) {
+ .welcome ::deep .carousel {
+ height: 456px;
+ }
+
+ .welcome-footer {
+ position: absolute;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ padding: 0 15px;
+ margin-bottom: 0;
+ }
+}
+
+@media (min-width: 1200px) {
+ .welcome ::deep .carousel {
+ height: 520px;
+ }
+}
diff --git a/src/BootstrapBlazor.Server/Components/Pages/Index.razor.js b/src/BootstrapBlazor.Server/Components/Pages/Index.razor.js
new file mode 100644
index 000000000..4d3085bab
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Pages/Index.razor.js
@@ -0,0 +1,79 @@
+import Data from '../../_content/BootstrapBlazor/modules/data.js?v=$version'
+
+export function init(id, text1, text2, text3) {
+ const el = document.getElementById(id)
+ const index = {
+ element: el, text1, text2, text3,
+ cursorElement: el.nextElementSibling,
+ type: () => {
+ const typeChar = (original, reverse) => {
+ const plant = original.concat()
+ return new Promise((resolver, reject) => {
+ index.cursorElement.classList.add('active')
+ index.eventHandler = setInterval(() => {
+ if (plant.length > 0) {
+ if (!reverse) {
+ index.element.textContent = index.element.textContent + plant.shift()
+ }
+ else {
+ plant.pop()
+ index.element.textContent = plant.join('')
+ }
+ }
+ else {
+ clearInterval(index.eventHandler)
+ index.eventHandler = false
+ index.cursorElement.classList.remove('active')
+
+ index.typeHandler = window.setTimeout(() => {
+ window.clearTimeout(index.typeHandler)
+ index.typeHandler = false
+ if (reverse) {
+ return resolver()
+ } else {
+ typeChar(original, true).then(() => {
+ return resolver()
+ })
+ }
+ }, 1000)
+ }
+ }, 200)
+ })
+ }
+
+ const loop = () => {
+ index.handler = setTimeout(() => {
+ clearTimeout(index.handler)
+ index.handler = false
+ typeChar(text1, false).then(() => {
+ typeChar(text2, false).then(() => {
+ typeChar(text3).then(() => {
+ loop()
+ })
+ })
+ })
+ }, 200)
+ }
+
+ loop()
+ }
+ }
+
+ index.type()
+ Data.set(id, index)
+}
+
+export function dispose(id) {
+ const index = Data.get(id)
+ Data.remove(id)
+
+ if (index.handler) {
+ clearTimeout(index.handler)
+ }
+ if (index.eventHandler) {
+ clearInterval(index.eventHandler)
+ }
+ if (index.typeHandler) {
+ clearTimeout(index.typeHandler)
+ }
+}
diff --git a/src/BootstrapBlazor.Server/Components/Pages/Install.razor b/src/BootstrapBlazor.Server/Components/Pages/Install.razor
new file mode 100644
index 000000000..71d833762
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Pages/Install.razor
@@ -0,0 +1,56 @@
+@page "/install"
+@inject PackageVersionService VersionManager
+@inject IStringLocalizer Localizer
+@inject IOptionsMonitor WebsiteOption
+
+@Localizer["InstallTitle"]
+
+Git
+
+@Localizer["GitP1"]
+
+
+
+@((MarkupString)Localizer["GitP2"].Value)
+
+@Localizer["NugetInstall"]
+
+
+
+@Localizer["EnvBuildTitle"]
+
+
+ @((MarkupString)Localizer["EnvLi1"].Value)
+ @((MarkupString)Localizer["EnvLi2"].Value)
+ @((MarkupString)string.Format(Localizer["EnvLi3"].Value, WebsiteOption.CurrentValue.BootstrapBlazorLink))
+
+
+git clone @WebsiteOption.CurrentValue.BootstrapBlazorLink
+
+@code {
+ ///
+ /// 获得/设置 版本号字符串
+ ///
+ private string Version { get; set; } = "fetching";
+
+ ///
+ /// OnInitializedAsync 方法
+ ///
+ ///
+ protected override async Task OnInitializedAsync()
+ {
+ Version = await VersionManager.GetVersionAsync();
+ }
+}
diff --git a/src/BootstrapBlazor.Server/Components/Pages/Install.razor.css b/src/BootstrapBlazor.Server/Components/Pages/Install.razor.css
new file mode 100644
index 000000000..c303e3841
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Pages/Install.razor.css
@@ -0,0 +1,28 @@
+.git img {
+ height: 44px;
+ width: auto;
+ display: block;
+}
+
+.git .git-fork {
+ display: flex;
+ align-items: center;
+ padding: 0 10px;
+}
+
+.git a {
+ border: solid 1px #ddd;
+ display: block;
+ padding: 6px 10px;
+ border-radius: var(--bs-border-radius);
+}
+
+.git .git-fork img {
+ height: 56px;
+}
+
+.git .git-fork span {
+ font-size: 1.8rem;
+ color: #1c3949;
+ margin-left: 38px;
+}
diff --git a/src/BootstrapBlazor.Server/Components/Pages/Install_Maui.razor b/src/BootstrapBlazor.Server/Components/Pages/Install_Maui.razor
new file mode 100644
index 000000000..ac4e10616
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Pages/Install_Maui.razor
@@ -0,0 +1,226 @@
+@page "/install-maui"
+@inject IStringLocalizer Localizer
+@inject PackageVersionService VersionManager
+
+@Title
+
+@Localizer["H1"]
+
+@Localizer["P1"]
+
+ visual studio 2022 17.3.0
@Localizer["P2"]
+ net6
+
+
+@Localizer["P3"]
+
+@Localizer["P4"]
+1.Visual Studio 2022
+2. @Localizer["P5"]
+3. @Localizer["P6"] @Localizer["P7"] @Localizer["P8"] @Localizer["P9"] , @Localizer["P10"] @Localizer["P11"] , @Localizer["P12"]
+
+@Localizer["P13"]
+@((MarkupString)Localizer["P14"].Value)
+@Localizer["P15"] Manage Nuget Packages
+dotnet add package BootstrapBlazor --version @Version
+
+@Localizer["P16"]
+
+@Localizer["P17"]
+@Localizer["P18"]
+
+
+ @((MarkupString)Localizer["P33"].Value)
+
+<head>
+ ...
+
+ <!-- @Localizer["P19"] !-->
+ <link href="_content/BootstrapBlazor.FontAwesome/css/font-awesome.min.css" rel="stylesheet">
+ <link href="_content/BootstrapBlazor/css/bootstrap.blazor.bundle.min.css" rel="stylesheet">
+
+ ...
+ <link href="css/app.css" rel="stylesheet">
+ <link href="MauiApp1.styles.css" rel="stylesheet">
+</head>
+@Localizer["P20"]
+
+<body>
+ ...
+ <!-- @Localizer["P21"] !-->
+ <script src="_content/BootstrapBlazor/js/bootstrap.blazor.bundle.min.js"></script>
+ ...
+ <script src="_framework/blazor.webview.js" autostart="false" ></script>
+</body>
+@Localizer["P22"]
+
+MauiProgram.cs
+var builder = MauiApp.CreateBuilder();
+
+builder.Services.AddMauiBlazorWebView();
+
+// @Localizer["CodeComment"]
+builder.Services.AddBootstrapBlazor();
+
+return builder.Build();
+
+@Localizer["P23"]
+@Localizer["P24"] ~/_Imports.razor
@Localizer["P25"] Razor
@Localizer["P26"]
+@@using BootstrapBlazor.Components
+
+@Localizer["P27"] BootstrapBlazorRoot
@Localizer["P28"] ~/Main.razor
@Localizer["P29"]
+<BootstrapBlazorRoot>
+ <Router AppAssembly="@@typeof(App).Assembly">
+ <Found Context="routeData">
+ <PageTitle>Title</PageTitle>
+ <RouteView RouteData="@@routeData" DefaultLayout="@@typeof(MainLayout)" />
+ <FocusOnNavigate RouteData="@@routeData" Selector="h1" />
+ </Found>
+ <NotFound>
+ <PageTitle>Not found</PageTitle>
+ <LayoutView Layout="@@typeof(MainLayout)">
+ <p>@Localizer["P30"] ...</p>
+ </LayoutView>
+ </NotFound>
+ </Router>
+</BootstrapBlazorRoot>
+
+@Localizer["P31"]
+@((MarkupString)Localizer["P32"].Value)
+@Localizer["P34"] Button
@Localizer["P35"]
+<Button Color="Color.Primary" Icon="fa-solid fa-font-awesome" Text="@Localizer["P36"]" />
+@Localizer["P37"] Visual studio 2022 @Localizer["P38"] F5 @Localizer["P39"]
+
+
+@Localizer["P40"]
+@Localizer["P41"] NativeContent.xaml
@Localizer["P42"]
+
+<ContentView
+ x:Class="MauiApp1.Pages.NativeContent"
+ xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
+ xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml">
+ <VerticalStackLayout
+ Padding="30,0"
+ Spacing="25"
+ VerticalOptions="Center">
+
+ <Image
+ HeightRequest="200"
+ HorizontalOptions="Center"
+ SemanticProperties.Description="Cute dot net bot waving hi to you!"
+ Source="dotnet_bot.png" />
+
+ <Label
+ FontSize="32"
+ HorizontalOptions="Center"
+ SemanticProperties.HeadingLevel="Level1"
+ Text="Hello, World!" />
+
+ <Label
+ FontSize="18"
+ HorizontalOptions="Center"
+ SemanticProperties.Description="Welcome to dot net Multi platform App U I"
+ SemanticProperties.HeadingLevel="Level2"
+ Text="Welcome to .NET Multi-platform App UI" />
+
+ <Button
+ x:Name="CounterBtn"
+ Clicked="OnCounterClicked"
+ HorizontalOptions="Center"
+ SemanticProperties.Hint="Counts the number of times you click"
+ Text="Click me" />
+
+ </VerticalStackLayout>
+</ContentView>
+
+ NativeContent.xaml.cs
+
+public partial class NativeContent : ContentView
+{
+ public NativeContent()
+ {
+ InitializeComponent();
+ }
+
+ int count = 0;
+
+ private void OnCounterClicked(object sender, EventArgs e)
+ {
+ count++;
+
+ if (count == 1)
+ CounterBtn.Text = $"Clicked {count} time";
+ else
+ CounterBtn.Text = $"Clicked {count} times";
+ }
+}
+@Localizer["P43"] MainPage.xaml
@Localizer["P44"] ContentPage
@Localizer["P45"] TabbedPage
@Localizer["P46"] NavigationPage
@Localizer["P47"]
+
+<TabbedPage
+ x:Class="MauiApp1.MainPage"
+ xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
+ xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
+ xmlns:local="clr-namespace:MauiApp1"
+ xmlns:pages="clr-namespace:MauiApp1.Pages"
+ BackgroundColor="{DynamicResource PageBackgroundColor}">
+ <ContentPage Title="Home">
+ <BlazorWebView HostPage="wwwroot/index.html">
+ <BlazorWebView.RootComponents>
+ <RootComponent ComponentType="{x:Type pages:Index}" Selector="#app" />
+ </BlazorWebView.RootComponents>
+ </BlazorWebView>
+ </ContentPage>
+ <ContentPage Title="NativeContent">
+ <pages:NativeContent />
+ </ContentPage>
+ <ContentPage Title="Counter">
+ <BlazorWebView HostPage="wwwroot/index.html">
+ <BlazorWebView.RootComponents>
+ <RootComponent ComponentType="{x:Type pages:Counter}" Selector="#app" />
+ </BlazorWebView.RootComponents>
+ </BlazorWebView>
+ </ContentPage>
+ <ContentPage Title="Weather">
+ <BlazorWebView HostPage="wwwroot/index.html">
+ <BlazorWebView.RootComponents>
+ <RootComponent ComponentType="{x:Type pages:FetchData}" Selector="#app" />
+ </BlazorWebView.RootComponents>
+ </BlazorWebView>
+ </ContentPage>
+</TabbedPage>
+
+public partial class MainPage : TabbedPage
+{
+ public MainPage()
+ {
+ InitializeComponent();
+ }
+}
+@Localizer["P48"] Visual studio 2022 @Localizer["P49"] F5 @Localizer["P50"]
+
+
+
+@code
+{
+ private string Version { get; set; } = "latest";
+ [Parameter]
+ public string Title { get; set; } = "";
+
+ protected override async Task OnInitializedAsync()
+ {
+ Version = await VersionManager.GetVersionAsync();
+ Title = @Localizer["P51"];
+ }
+}
diff --git a/src/BootstrapBlazor.Server/Components/Pages/Install_Server.razor b/src/BootstrapBlazor.Server/Components/Pages/Install_Server.razor
new file mode 100644
index 000000000..167289fcf
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Pages/Install_Server.razor
@@ -0,0 +1,53 @@
+@page "/install-server"
+@inject IStringLocalizer Localizer
+
+
+
+ 4. @Localizer["D1"] Blazor Server App @Localizer["D2"] Create
+
+
+
+
+ ~/Pages/_Host.cshtml
.NET5
+ ~/Pages/_Layout.cshtml
.NET6
+
+
+
+
+ ~/Pages/_Host.cshtml
.NET5
+ ~/Pages/_Layout.cshtml
.NET6
+
+
+
+
+ Starup.cs
.NET5
+ Program.cs
.NET6
+
+ Startup.cs
+ namespace MyBlazorAppName
+{
+ public class Startup
+ {
+ public void ConfigureServices(IServiceCollection services)
+ {
+ services.AddServerSideBlazor();
+
+ // @Localizer["CodeComment"]
+ services.AddBootstrapBlazor();
+ }
+ }
+}
+
+ Program.cs
+ var builder = WebApplication.CreateBuilder(args);
+
+// Add services to the container.
+builder.Services.AddServerSideBlazor();
+
+// @Localizer["CodeComment"]
+builder.Services.AddBootstrapBlazor();
+
+var app = builder.Build();
+//more code may be present here
+
+
diff --git a/src/BootstrapBlazor.Server/Components/Pages/Install_wasm.razor b/src/BootstrapBlazor.Server/Components/Pages/Install_wasm.razor
new file mode 100644
index 000000000..3b9b9fd36
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Pages/Install_wasm.razor
@@ -0,0 +1,46 @@
+@page "/install-wasm"
+@inject IStringLocalizer Localizer
+
+
+
+ 4. @((MarkupString)Localizer["Install_wasmDescription"].Value)
+
+
+
+ wwwroot/index.html
+
+
+ wwwroot/index.html
+
+
+ var builder = WebAssemblyHostBuilder.CreateDefault(args);
+builder.RootComponents.Add<App>("app");
+builder.RootComponents.Add<HeadOutlet>("head::after");
+
+// @Localizer["Install_wasmCodeComment"]
+builder.Services.AddBootstrapBlazor();
+
+var host = builder.Build();
+
+await SetCultureAsync(host);
+
+await builder.Build().RunAsync();
+
+static async Task SetCultureAsync(WebAssemblyHost host)
+{
+ // 如果 localStorage 未设置语言使用浏览器请求语言
+ var jsRuntime = host.Services.GetRequiredService<IJSRuntime>();
+ var cultureName = await jsRuntime.GetCulture();
+
+ if (!string.IsNullOrEmpty(cultureName))
+ {
+ var culture = new CultureInfo(cultureName);
+
+ // 注意 wasm 模式此处必须使用 DefaultThreadCurrentCulture 不可以使用 CurrentCulture
+ CultureInfo.DefaultThreadCurrentCulture = culture;
+ CultureInfo.DefaultThreadCurrentUICulture = culture;
+ }
+}
+
+
+
diff --git a/src/BootstrapBlazor.Server/Components/Pages/Introduction.razor b/src/BootstrapBlazor.Server/Components/Pages/Introduction.razor
new file mode 100644
index 000000000..d594b5dea
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Pages/Introduction.razor
@@ -0,0 +1,73 @@
+@page "/docs"
+@page "/introduction"
+
+@Localizer["Title"]
+
+@Localizer["P1"]
+
+@Localizer["P2"]
+
+@((MarkupString)Localizer["P3"].Value)
+
+@Localizer["UpdateTitle"]
+
+
+ @((MarkupString)Localizer["UpdateLog"].Value)
+ @Localizer["UpdateLogLink"]
+
+
+@Localizer["LearnTitle"]
+
+
+
+@Localizer["ProjectsShow"]
+
+@((MarkupString)Localizer["P5", LocalizerRules].Value)
+
+@Localizer["ShowWebSiteTitle"]:@WebsiteOption.CurrentValue.AdminUrl
+
+@Localizer["GetStarted"]
+
+Bootstrap @Localizer["QuikStart"]
+
+@Localizer["Features"]
+
+@((MarkupString)Localizer["P6"].Value)
+
+@Localizer["Advantage"]
+
+
+ @((MarkupString)Localizer["AdvantageLi1"].Value)
+ @((MarkupString)Localizer["AdvantageLi2"].Value)
+ @Localizer["AdvantageLi3"]
+ @Localizer["AdvantageLi4"]
+ @Localizer["AdvantageLi5"]
+
+
+@Localizer["Community"]
+
+
diff --git a/src/BootstrapBlazor.Server/Components/Pages/Introduction.razor.cs b/src/BootstrapBlazor.Server/Components/Pages/Introduction.razor.cs
new file mode 100644
index 000000000..d6d425a9f
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Pages/Introduction.razor.cs
@@ -0,0 +1,46 @@
+// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+// Website: https://www.blazor.zone or https://argozhang.github.io/
+
+using Microsoft.Extensions.Options;
+
+namespace BootstrapBlazor.Server.Components.Pages;
+
+///
+///
+///
+public partial class Introduction
+{
+ ///
+ ///
+ ///
+ [Inject]
+ [NotNull]
+ private IOptionsMonitor? WebsiteOption { get; set; }
+
+ ///
+ ///
+ ///
+ [Inject]
+ [NotNull]
+ private IStringLocalizer? Localizer { get; set; }
+
+ [NotNull]
+ private string[]? LocalizerRules { get; set; }
+
+ ///
+ ///
+ ///
+ protected override void OnInitialized()
+ {
+ base.OnInitialized();
+
+ LocalizerRules =
+ [
+ WebsiteOption.CurrentValue.BootstrapAdminLink,
+ WebsiteOption.CurrentValue.BootstrapAdminLink + "/stargazers",
+ WebsiteOption.CurrentValue.BootstrapAdminLink + "/badge/star.svg?theme=gvp",
+ WebsiteOption.CurrentValue.BootstrapAdminLink
+ ];
+ }
+}
diff --git a/src/BootstrapBlazor.Server/Components/Pages/Layout.razor b/src/BootstrapBlazor.Server/Components/Pages/Layout.razor
new file mode 100644
index 000000000..938ab64a5
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Pages/Layout.razor
@@ -0,0 +1,32 @@
+@page "/z-index"
+
+@inject IStringLocalizer Localizer
+
+@Localizer["Heading"]
+
+@Localizer["Para1"] Bootstrap
@Localizer["Para2"] z-index
@Localizer["Para3"]:
+
+$zindex-dropdown: 1000;
+$zindex-sticky: 1020;
+$zindex-fixed: 1030;
+$zindex-offcanvas-backdrop: 1040;
+$zindex-offcanvas: 1045;
+$zindex-modal-backdrop: 1050;
+$zindex-modal: 1055;
+$zindex-popover: 1070;
+$zindex-swal: 1075;
+$zindex-tooltip: 1080;
+
+@Localizer["Para4"] Message
Dialog
Swal
Toast
@Localizer["Para5"]:
+
+Drawer: 1050;
+Dialog: 1050;
+Swal: 1075;
+Message: 1090;
+Toast: 1090;
+
+@Localizer["Para6"]
+
+
+
+@Localizer["Footer1"] Drawer
@Localizer["Footer2"]
diff --git a/src/BootstrapBlazor.Server/Components/Pages/Layout.razor.cs b/src/BootstrapBlazor.Server/Components/Pages/Layout.razor.cs
new file mode 100644
index 000000000..444981c91
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Pages/Layout.razor.cs
@@ -0,0 +1,77 @@
+// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+// Website: https://www.blazor.zone or https://argozhang.github.io/
+
+namespace BootstrapBlazor.Server.Components.Pages;
+
+///
+///
+///
+public partial class Layout
+{
+ [Inject]
+ [NotNull]
+ private DialogService? Dialog { get; set; }
+
+ [Inject]
+ [NotNull]
+ private ToastService? Toast { get; set; }
+
+ [Inject]
+ [NotNull]
+ private SwalService? Swal { get; set; }
+
+ [Inject]
+ [NotNull]
+ private MessageService? Message { get; set; }
+
+ private async Task ShowDialog()
+ {
+ await Dialog.Show(new DialogOption()
+ {
+ Title = "测试弹窗",
+ BodyTemplate = builder =>
+ {
+ builder.AddContent(0, BootstrapDynamicComponent.CreateComponent(new Dictionary
+ {
+ [nameof(Button.Text)] = "Toast",
+ [nameof(Button.OnClickWithoutRender)] = async () =>
+ {
+ await Toast.Show(new ToastOption()
+ {
+ Title = "Toast",
+ Content = "Dialog 中弹窗 Toast 测试成功",
+ IsAutoHide = false
+ });
+ }
+ }).Render());
+ builder.AddContent(0, BootstrapDynamicComponent.CreateComponent(new Dictionary
+ {
+ ["class"] = "ms-3",
+ [nameof(Button.Text)] = "Message",
+ [nameof(Button.OnClickWithoutRender)] = async () =>
+ {
+ await Message.Show(new MessageOption()
+ {
+ Content = "Dialog 中弹窗 Message 测试成功"
+ });
+ }
+ }).Render());
+ builder.AddContent(0, BootstrapDynamicComponent.CreateComponent(new Dictionary
+ {
+ ["class"] = "ms-3",
+ [nameof(Button.Text)] = "Swal",
+ [nameof(Button.OnClickWithoutRender)] = async () =>
+ {
+ await Swal.Show(new SwalOption()
+ {
+ Category = SwalCategory.Success,
+ Title = "Sweet Alert",
+ Content = "Dialog 中弹窗 Swal 测试成功"
+ });
+ }
+ }).Render());
+ }
+ });
+ }
+}
diff --git a/src/BootstrapBlazor.Server/Components/Pages/Localization.razor b/src/BootstrapBlazor.Server/Components/Pages/Localization.razor
new file mode 100644
index 000000000..2e66b96f3
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Pages/Localization.razor
@@ -0,0 +1,362 @@
+@page "/localization"
+@inject IStringLocalizer Localizer
+
+@Localizer["Title"]
+
+
+ @Localizer["P1"] BootstrapBlazor
@Localizer["P2"] UI
@Localizer["P3"]:
+
+
+
+
+ @Localizer["T3"]
wasm
@Localizer["T4"]
en
,
@Localizer["T5"]
+ @((MarkupString)Localizer["LocalizationFileDesc"].Value)
+
+
+@Localizer["N1"]
+
+
+
+
BootstrapBlazor
@Localizer["N2"]
Json
@Localizer["N3"]
UI
@Localizer["N4"]。
BootstrapBlazor @Localizer["N5"]。
+
+
+ @Localizer["N6"]
+ @Localizer["N7"]
+
+ @((MarkupString)Localizer["AdditionalJsonFile"].Value)
+
+ @Localizer["N8"]
+ @Localizer["N9"]
+ @Localizer["ES"]
+ @Localizer["TW"]
+
+
+ @Localizer["N10"] zh-CN
@Localizer["N11"] zh-CN
@Localizer["N12"]:zh-CN
@Localizer["N13"] zh
+
+
+ @Localizer["N14"] FallbackCulture
@Localizer["N15"] en
+
+
+ @Localizer["N16"]:
+
+ @Localizer["N17"] Centos
Ubuntu
mac
@Localizer["N18"]:
+
+
+{
+ "BootstrapBlazorOptions": {
+ "DefaultCultureInfo": "en"
+ }
+}
+
+@Localizer["N19"]
+
+Server-Side App
+
+1. @Localizer["N20"]
+
+@Localizer["N21"] FallbackCultureName
@Localizer["N22"] SupportedCultures
@Localizer["N23"]
+
+{
+ "BootstrapBlazorOptions": {
+ "FallbackCultureName": "en",
+ "SupportedCultures": [
+ "zh-CN",
+ "en-US"
+ ]
+ }
+}
+
+2. @Localizer["N24"]
+
+
+
+builder.Services.AddRazorPages();
+builder.Services.AddServerSideBlazor();
+
+// @Localizer["N25"]
+builder.Services.AddBootstrapBlazor();
+
+// @Localizer["N26"]
+builder.Services.AddRequestLocalization<IOptionsMonitor<BootstrapBlazorOptions>>((localizerOption, blazorOption)=>
+{
+ blazorOption.OnChange(op => Invoke(op));
+ Invoke(blazorOption.CurrentValue);
+
+ void Invoke(BootstrapBlazorOptions option)
+ {
+ var supportedCultures = option.GetSupportedCultures();
+ localizerOption.SupportedCultures = supportedCultures;
+ localizerOption.SupportedUICultures = supportedCultures;
+ }
+});
+
+var app = builder.Build();
+
+// @Localizer["N27"]
+var option = app.Services.GetService<IOptions<RequestLocalizationOptions>>();
+if (option != null)
+{
+ app.UseRequestLocalization(option.Value);
+}
+
+
+
+public class Startup
+{
+ public void ConfigureServices(IServiceCollection services)
+ {
+ // @Localizer["N28"]
+ services.AddBootstrapBlazor();
+
+ // @Localizer["N29"]
+ services.AddRequestLocalization<IOptions<BootstrapBlazorOptions>>((localizerOption, blazorOption) =>
+ {
+ var supportedCultures = blazorOption.Value.GetSupportedCultures();
+
+ localizerOption.SupportedCultures = supportedCultures;
+ localizerOption.SupportedUICultures = supportedCultures;
+ });
+ }
+
+ public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
+ {
+ // @Localizer["N30"]
+ app.UseRequestLocalization(app.ApplicationServices.GetService<IOptions<RequestLocalizationOptions>>()!.Value);
+ }
+}
+
+
+
+3. @Localizer["N31"]
+[Route("[controller]/[action]")]
+public class CultureController : Controller
+{
+ public IActionResult SetCulture(string culture, string redirectUri)
+ {
+ if (!string.IsNullOrEmpty(culture))
+ {
+ HttpContext.Response.Cookies.Append(
+ CookieRequestCultureProvider.DefaultCookieName,
+ CookieRequestCultureProvider.MakeCookieValue(new RequestCulture(culture, culture)));
+ }
+
+ return LocalRedirect(redirectUri);
+ }
+
+ public IActionResult ResetCulture(string redirectUri)
+ {
+ HttpContext.Response.Cookies.Delete(CookieRequestCultureProvider.DefaultCookieName);
+
+ return LocalRedirect(redirectUri);
+ }
+}
+
+3. @Localizer["N32"]
+@@inherits BootstrapComponentBase
+@@inject IOptions<BootstrapBlazorOptions> BootstrapOptions
+@@inject NavigationManager NavigationManager
+@@inject ICultureStorage CultureStorage
+
+<div @@attributes="@@AdditionalAttributes" class="@@ClassString">
+ <label>@Localizer["N33"]:</label>
+ <Select Value="@@SelectedCulture" OnSelectedItemChanged="@@SetCulture">
+ <Options>
+ @@foreach (var kv in Configuration.GetSupportCultures())
+ {
+ <SelectOption Text="@@kv.Key" Value="@@kv.Value" />
+ }
+ </Options>
+ </Select>
+</div>
+
+@@code {
+ private string? ClassString => CssBuilder.Default("culture-selector")
+ .AddClassFromAttributes(AdditionalAttributes)
+ .Build();
+
+ private string SelectedCulture { get; set; } = CultureInfo.CurrentUICulture.Name;
+
+ private async Task SetCulture(SelectedItem item)
+ {
+ if (CultureStorage.Mode == CultureStorageMode.Webapi)
+ {
+ // @Localizer["N34"]
+ if (SelectedCulture != item.Value)
+ {
+ var culture = item.Value;
+ var uri = new Uri(NavigationManager.Uri).GetComponents(UriComponents.PathAndQuery, UriFormat.Unescaped);
+ var query = $"?culture={Uri.EscapeDataString(culture)}&redirectUri={Uri.EscapeDataString(uri)}";
+
+ // use a path that matches your culture redirect controller from the previous steps
+ NavigationManager.NavigateTo("/Culture/SetCulture" + query, forceLoad: true);
+ }
+ }
+ else
+ {
+ var cultureName = item.Value;
+ if (cultureName != CultureInfo.CurrentCulture.Name)
+ {
+ await JSRuntime.SetCulture(cultureName);
+ var culture = new CultureInfo(cultureName);
+ CultureInfo.CurrentCulture = culture;
+ CultureInfo.CurrentUICulture = culture;
+
+ NavigationManager.NavigateTo(NavigationManager.Uri, forceLoad: true);
+ }
+ }
+ }
+}
+
+4. @Localizer["N35"] Json
@Localizer["N36"]
+
+
+ BootstrapBlazor
@Localizer["N37"] resx
@Localizer["N38"] json
@Localizer["N39"] json
@Localizer["N40"]
+
+
+
+
@Localizer["N41"]
+
+
+ @Localizer["N42"]
+ @Localizer["N43"]
+ @Localizer["N44"]
+ @Localizer["N45"]
+
+
+
+public void ConfigureServices(IServiceCollection services)
+{
+ services.AddBootstrapBlazor(null, options =>
+ {
+ // @Localizer["N46"]
+ options.IgnoreLocalizerMissing = true;
+
+ // @Localizer["N47"]
+ options.ResourceManagerStringLocalizerType = typeof(Program);
+
+ // @Localizer["N48"]
+ options.AdditionalJsonAssemblies = new[] { typeof(BootstrapBlazor.Shared.App).Assembly };
+
+ // @Localizer["N49"]
+ options.AdditionalJsonFiles = new string[]
+ {
+ @@"D:\Argo\src\BootstrapBlazor\src\BootstrapBlazor.Server\Locales\zh-TW.json",
+ @@"D:\Argo\src\BootstrapBlazor\src\BootstrapBlazor.Server\Locales\zh-CN.json"
+ };
+ });
+}
+
+
+@Localizer["N50"] ConfigureJsonLocalizationOptions
+
+public void ConfigureServices(IServiceCollection services)
+{
+ services.AddBootstrapBlazor();
+ services.ConfigureJsonLocalizationOptions(options =>
+ {
+ // @Localizer["N51"]
+ options.IgnoreLocalizerMissing = true;
+
+ // @Localizer["N52"]
+ options.AdditionalJsonAssemblies = new Assembly[]
+ {
+ typeof(BootstrapBlazor.Shared.App).Assembly,
+ };
+
+ // @Localizer["N53"]
+ options.AdditionalJsonFiles = new string[]
+ {
+ @@"D:\Argo\src\BootstrapBlazor\src\BootstrapBlazor.Server\Locales\zh-TW.json",
+ @@"D:\Argo\src\BootstrapBlazor\src\BootstrapBlazor.Server\Locales\zh-CN.json"
+ };
+ });
+}
+
+Web Assembly
+
+1. @Localizer["N54"]
+public static async Task Main(string[] args)
+{
+ var builder = WebAssemblyHostBuilder.CreateDefault(args);
+
+ builder.RootComponents.Add<App>("app");
+
+ builder.Services.AddTransient(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
+
+ // @Localizer["N55"]
+ builder.Services.AddBootstrapBlazor();
+
+ builder.Services.AddSingleton<ICultureStorage, DefaultCultureStorage>();
+
+ // @Localizer["N56"]
+ builder.Services.Configure<BootstrapBlazorOptions>(op =>
+ {
+ op.ToastDelay = 4000;
+ op.SupportedCultures = new List<string> { "zh-CN", "en-US" };
+ });
+
+ var host = builder.Build();
+
+ await GetCultureAsync(host);
+
+ await host.RunAsync();
+}
+
+private static async Task GetCultureAsync(WebAssemblyHost host)
+{
+ var jsRuntime = host.Services.GetRequiredService<IJSRuntime>();
+ var cultureName = await jsRuntime.GetCulture() ?? "zh-CN";
+ var culture = new CultureInfo(cultureName);
+ CultureInfo.DefaultThreadCurrentCulture = culture;
+ CultureInfo.DefaultThreadCurrentUICulture = culture;
+}
+
+internal class DefaultCultureStorage : ICultureStorage
+{
+ public CultureStorageMode Mode { get; set; } = CultureStorageMode.LocalStorage;
+}
+
+
+2. @Localizer["N57"]
+
+@Localizer["N58"]
+
+@Localizer["N59"]
+
+public static async Task Main(string[] args)
+{
+ // @Localizer["N60"]
+ CultureInfo.CurrentCulture = new CultureInfo("zh-CN");
+ CultureInfo.CurrentUICulture = new CultureInfo("zh-CN");
+
+ // ...
+
+ var host = builder.Build();
+
+ await GetCultureAsync(host);
+
+ await host.RunAsync();
+}
+
+
+@Localizer["N61"]
+
+
+
+"BootstrapBlazorOptions": {
+ "IgnoreLocalizerMissing": true
+}
+
+
+var builder = WebApplication.CreateBuilder(args);
+
+// @Localizer["N62"]
+builder.Services.AddBootstrapBlazor(null, options =>
+{
+ // @Localizer["N63"]
+ options.IgnoreLocalizerMissing = true;
+});
+
+
+
+
diff --git a/src/BootstrapBlazor.Server/Components/Pages/Localization.razor.css b/src/BootstrapBlazor.Server/Components/Pages/Localization.razor.css
new file mode 100644
index 000000000..85dd63f38
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Pages/Localization.razor.css
@@ -0,0 +1,11 @@
+::deep .gitee-icon {
+ width: 32px;
+ height: auto;
+}
+
+::deep .github-icon {
+ font-size: 32px;
+ line-height: 32px;
+ vertical-align: middle;
+ color: #000;
+}
diff --git a/src/BootstrapBlazor.Server/Components/Pages/Practice.razor b/src/BootstrapBlazor.Server/Components/Pages/Practice.razor
new file mode 100644
index 000000000..f54c02bc3
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Pages/Practice.razor
@@ -0,0 +1,10 @@
+@layout PracticeLayout
+@page "/practice"
+@inject IStringLocalizer Localizer
+
+
+
+
+
+
+
diff --git a/src/BootstrapBlazor.Server/Components/Pages/Practice.razor.css b/src/BootstrapBlazor.Server/Components/Pages/Practice.razor.css
new file mode 100644
index 000000000..1a82ec02a
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Pages/Practice.razor.css
@@ -0,0 +1,26 @@
+.coms-search {
+ position: sticky;
+ z-index: 1;
+ top: 0;
+}
+
+ .coms-search .row {
+ padding: 1rem 0;
+ background: #fff;
+ }
+
+.coms-search-filter {
+ height: 2rem;
+ width: 100%;
+ background: linear-gradient(rgba(255,255,255,1),rgba(255,255,255,0.8),rgba(255,255,255,0));
+}
+
+@media (min-width: 768px) {
+ .coms-search {
+ top: 3rem;
+ }
+
+ .coms-search.hide {
+ top: 0;
+ }
+}
diff --git a/src/BootstrapBlazor.Server/Components/Pages/Routes.razor b/src/BootstrapBlazor.Server/Components/Pages/Routes.razor
new file mode 100644
index 000000000..d96a90e1e
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Pages/Routes.razor
@@ -0,0 +1,7 @@
+@using System.Reflection
+
+
+
+
+
+
diff --git a/src/BootstrapBlazor.Server/Components/Pages/Template.razor b/src/BootstrapBlazor.Server/Components/Pages/Template.razor
new file mode 100644
index 000000000..1af60ca6a
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Pages/Template.razor
@@ -0,0 +1,51 @@
+@page "/template"
+@inject PackageVersionService VersionManager
+@inject IStringLocalizer Localizer
+@inject IOptionsMonitor WebsiteOption
+
+@Localizer["Title"]
+
+@Localizer["SubTitle"]
+
+@((MarkupString)Localizer["P1"].Value)
+
+@Localizer["P2"]
+dotnet new install Bootstrap.Blazor.Templates::@Version
+
+@Localizer["P3"]
+dotnet new bbapp
+
+@((MarkupString)Localizer["P4"].Value)
+
+@Localizer["P5"]
+dotnet new update
+@Localizer["P6"]
+
+@Localizer["P7"]
+dotnet new uninstall Bootstrap.Blazor.Templates
+
+@Localizer["SubTitle1"]
+
+@((MarkupString)Localizer["P8"].Value)
+
+1. @Localizer["P9"]
+
+
+
+
+
+
+
+2. @Localizer["P17"]
+
+
+
+
+
+3. @Localizer["P18"]
+
+
+
+
+
+
diff --git a/src/BootstrapBlazor.Server/Components/Pages/Template.razor.cs b/src/BootstrapBlazor.Server/Components/Pages/Template.razor.cs
new file mode 100644
index 000000000..239ed7301
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Pages/Template.razor.cs
@@ -0,0 +1,27 @@
+// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+// Website: https://www.blazor.zone or https://argozhang.github.io/
+
+namespace BootstrapBlazor.Server.Components.Pages;
+
+///
+///
+///
+public sealed partial class Template
+{
+ ///
+ /// 获得/设置 版本号字符串
+ ///
+ private string Version { get; set; } = "*";
+
+ private string TemplateUrl => $"{WebsiteOption.CurrentValue.BootstrapBlazorLink}/wikis/%E9%A1%B9%E7%9B%AE%E6%A8%A1%E6%9D%BF%E4%BD%BF%E7%94%A8%E6%95%99%E7%A8%8B?sort_id=3059284";
+
+ ///
+ /// OnInitializedAsync 方法
+ ///
+ ///
+ protected override async Task OnInitializedAsync()
+ {
+ Version = await VersionManager.GetVersionAsync("Bootstrap.Blazor.Templates");
+ }
+}
diff --git a/src/BootstrapBlazor.Server/Components/Pages/Theme.razor b/src/BootstrapBlazor.Server/Components/Pages/Theme.razor
new file mode 100644
index 000000000..8523cb498
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Pages/Theme.razor
@@ -0,0 +1,24 @@
+@page "/theme"
+@inject IStringLocalizer Localizer
+
+@Localizer["H1"]
+
+@Localizer["H2"]
+
+@Localizer["P1"]:
+
+
+ @Localizer["P2"]
+ @Localizer["P3"]
+ @Localizer["P4"]
+ @Localizer["P5"]
+
+
+@Localizer["P6"]
+
+@Localizer["P7"] Motronic
@Localizer["P8"] head
@Localizer["P9"]:
+
+<link href="_content/BootstrapBlazor/css/bootstrap.blazor.bundle.min.css" rel="stylesheet">
+
+// @Localizer["P10"]
+<link rel="stylesheet" href="_content/BootstrapBlazor/css/motronic.min.css">
diff --git a/src/BootstrapBlazor.Server/Components/Samples/Ajaxs.razor b/src/BootstrapBlazor.Server/Components/Samples/Ajaxs.razor
new file mode 100644
index 000000000..1c3cffb72
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Samples/Ajaxs.razor
@@ -0,0 +1,34 @@
+@page "/ajax"
+
+@Localizer["AjaxTitle"]
+
+@Localizer["AjaxDescribe"]
+
+
+
+ @Localizer["NormalB"]
+
@((MarkupString)Localizer["NormalDiv"].Value)
+
+ var option = new AjaxOption
+{
+ Url = "/api/Login",
+ Data = new User() { UserName = "admin", Password = "1234567" }
+};
+var result = await AjaxService.InvokeAsync(option);
+
+
+
@Localizer["NormalButtonText1"]
+
@Localizer["NormalButtonText2"]
+ @if (!string.IsNullOrEmpty(ResultMessage))
+ {
+
@ResultMessage
+ }
+
+
+
+
+ @Localizer["GoToButtonText1"]
+ @Localizer["GoToButtonText2"]
+
+
+
diff --git a/src/BootstrapBlazor.Server/Components/Samples/Ajaxs.razor.cs b/src/BootstrapBlazor.Server/Components/Samples/Ajaxs.razor.cs
new file mode 100644
index 000000000..731a1eb1d
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Samples/Ajaxs.razor.cs
@@ -0,0 +1,87 @@
+// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+// Website: https://www.blazor.zone or https://argozhang.github.io/
+
+namespace BootstrapBlazor.Server.Components.Samples;
+
+///
+/// Ajax 组件代码
+///
+public partial class Ajaxs
+{
+ [Inject]
+ [NotNull]
+ private IStringLocalizer? Localizer { get; set; }
+
+ [Inject]
+ [NotNull]
+ private AjaxService? AjaxService { get; set; }
+
+ [Inject]
+ [NotNull]
+ private SwalService? SwalService { get; set; }
+
+ private string? ResultMessage { get; set; }
+
+ private Task Success() => ProcessResponse("admin", "123456");
+
+ private Task Fail() => ProcessResponse("admin", "123");
+
+ private async Task ProcessResponse(string userName, string password)
+ {
+ var option = new AjaxOption()
+ {
+ Url = "/api/Login",
+ Data = new User() { UserName = userName, Password = password }
+ };
+ var result = await AjaxService.InvokeAsync(option);
+ if (result == null)
+ {
+ ResultMessage = "Login failed";
+ }
+ else
+ {
+ if (200 == result.RootElement.GetProperty("code").GetInt32())
+ {
+ await SwalService.Show(new SwalOption() { Content = "Login success!", Category = SwalCategory.Success });
+ }
+ else
+ {
+ await SwalService.Show(new SwalOption() { Content = $"Login failed: {result.RootElement.GetProperty("message").GetString()}", Category = SwalCategory.Error });
+ }
+ }
+ }
+
+ class User
+ {
+ public string? UserName { get; set; }
+
+ public string? Password { get; set; }
+ }
+
+ private Task Goto() => AjaxService.Goto("/introduction");
+
+ private Task GotoSelf() => AjaxService.Goto("/ajaxs");
+
+ ///
+ /// 获得属性方法
+ ///
+ ///
+ private IEnumerable GetMethods() => new MethodItem[]
+ {
+ new MethodItem()
+ {
+ Name = "InvokeAsync",
+ Description = Localizer["InvokeAsync"],
+ Parameters = "AjaxOption",
+ ReturnValue = "string"
+ },
+ new MethodItem()
+ {
+ Name = "Goto",
+ Description = Localizer["GoTo"],
+ Parameters = "string",
+ ReturnValue = " — "
+ }
+ };
+}
diff --git a/src/BootstrapBlazor.Server/Components/Samples/Alerts.razor b/src/BootstrapBlazor.Server/Components/Samples/Alerts.razor
new file mode 100644
index 000000000..c065a135a
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Samples/Alerts.razor
@@ -0,0 +1,71 @@
+@page "/alert"
+
+@Title
+
+@SubTitle
+
+
+ @AlertPrimaryText
+ @AlertSecondaryText
+ @AlertSuccessText
+ @AlertDangerText
+ @AlertWarningText
+ @AlertInfoText
+ @AlertDarkText
+
+
+
+ @AlertPrimaryText
+ @AlertSecondaryText
+ @AlertSuccessText
+ @AlertDangerText
+ @AlertWarningText
+ @AlertInfoText
+ @AlertDarkText
+
+
+
+
+ @AlertPrimaryText
+ @AlertWarningText
+ @AlertInfoText
+ @AlertDangerText
+
+
+
+ @AlertPrimaryText
+ @AlertSuccessText
+ @AlertWarningText
+ @AlertInfoText
+ @AlertDangerText
+
+
+
+ @AlertPrimaryText
+ @AlertSuccessText
+ @AlertWarningText
+ @AlertInfoText
+ @AlertDangerText
+
+
+
+
+ @AlertInfoText
+
+
+ @AlertSuccessText
+
+
+ @AlertPrimaryText
+
+
+ @AlertWarningText
+
+
+ @AlertDangerText
+
+
+
+
+
+
diff --git a/src/BootstrapBlazor.Server/Components/Samples/Alerts.razor.cs b/src/BootstrapBlazor.Server/Components/Samples/Alerts.razor.cs
new file mode 100644
index 000000000..73897df31
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Samples/Alerts.razor.cs
@@ -0,0 +1,186 @@
+namespace BootstrapBlazor.Server.Components.Samples;
+
+///
+/// Alert 组件示例
+///
+public partial class Alerts
+{
+ [NotNull]
+ private string? Title { get; set; }
+
+ [NotNull]
+ private string? SubTitle { get; set; }
+
+ [NotNull]
+ private string? BaseUsageText { get; set; }
+
+ [NotNull]
+ private string? CloseButtonUsageText { get; set; }
+
+ [NotNull]
+ private string? WithIconUsageText { get; set; }
+
+ [NotNull]
+ private string? ShowBarUsageText { get; set; }
+
+ [NotNull]
+ private string? IntroText1 { get; set; }
+
+ [NotNull]
+ private string? IntroText2 { get; set; }
+
+ [NotNull]
+ private string? IntroText3 { get; set; }
+
+ [NotNull]
+ private string? IntroText4 { get; set; }
+
+ [Inject]
+ [NotNull]
+ private IStringLocalizer? Localizer { get; set; }
+
+ [NotNull]
+ private string? AlertPrimaryText { get; set; }
+
+ [NotNull]
+ private string? AlertSecondaryText { get; set; }
+
+ [NotNull]
+ private string? AlertSuccessText { get; set; }
+
+ [NotNull]
+ private string? AlertDangerText { get; set; }
+
+ [NotNull]
+ private string? AlertWarningText { get; set; }
+
+ [NotNull]
+ private string? AlertInfoText { get; set; }
+
+ [NotNull]
+ private string? AlertDarkText { get; set; }
+
+ ///
+ /// OnInitialized 方法
+ ///
+ protected override void OnInitialized()
+ {
+ base.OnInitialized();
+ Title ??= Localizer[nameof(Title)];
+ SubTitle ??= Localizer[nameof(SubTitle)];
+ BaseUsageText ??= Localizer[nameof(BaseUsageText)];
+ IntroText1 ??= Localizer[nameof(IntroText1)];
+ CloseButtonUsageText ??= Localizer[nameof(CloseButtonUsageText)];
+ IntroText2 ??= Localizer[nameof(IntroText2)];
+ WithIconUsageText ??= Localizer[nameof(WithIconUsageText)];
+ IntroText3 ??= Localizer[nameof(IntroText3)];
+ ShowBarUsageText ??= Localizer[nameof(ShowBarUsageText)];
+ IntroText4 ??= Localizer[nameof(IntroText4)];
+ AlertPrimaryText ??= Localizer[nameof(AlertPrimaryText)];
+ AlertSecondaryText ??= Localizer[nameof(AlertSecondaryText)];
+ AlertDangerText ??= Localizer[nameof(AlertDangerText)];
+ AlertSuccessText ??= Localizer[nameof(AlertSuccessText)];
+ AlertWarningText ??= Localizer[nameof(AlertWarningText)];
+ AlertInfoText ??= Localizer[nameof(AlertInfoText)];
+ AlertDarkText ??= Localizer[nameof(AlertDarkText)];
+ }
+
+ [NotNull]
+ private ConsoleLogger? Logger { get; set; }
+
+ ///
+ /// 关闭警告框回调方法
+ ///
+ ///
+ private Task DismissClick()
+ {
+ Logger.Log("Alert Dismissed");
+ return Task.CompletedTask;
+ }
+
+ ///
+ /// 获得事件方法
+ ///
+ ///
+ private static IEnumerable GetEvents() => new EventItem[]
+ {
+ new()
+ {
+ Name = "OnDismiss",
+ Description = "Close the alert box callback method",
+ Type = "EventCallback"
+ }
+ };
+
+ ///
+ /// 获得属性方法
+ ///
+ ///
+ private static IEnumerable GetAttributes() => new AttributeItem[]
+ {
+ new()
+ {
+ Name = "ChildContent",
+ Description = "Content",
+ Type = "RenderFragment",
+ ValueList = " — ",
+ DefaultValue = " — "
+ },
+ new()
+ {
+ Name = "Class",
+ Description = "Style",
+ Type = "string",
+ ValueList = " — ",
+ DefaultValue = " — "
+ },
+ new()
+ {
+ Name = "Color",
+ Description = "Color",
+ Type = "Color",
+ ValueList = "Primary / Secondary / Success / Danger / Warning / Info / Dark",
+ DefaultValue = "Primary"
+ },
+ new()
+ {
+ Name = "Icon",
+ Description = "Icon",
+ Type = "string",
+ ValueList = " — ",
+ DefaultValue = " — "
+ },
+ new()
+ {
+ Name = "ShowDismiss",
+ Description = "Close Button",
+ Type = "bool",
+ ValueList = " — ",
+ DefaultValue = "false"
+ },
+ new()
+ {
+ Name = "ShowBar",
+ Description = "Show the left Bar",
+ Type = "bool",
+ ValueList = "true|false",
+ DefaultValue = "false"
+ },
+ new()
+ {
+ Name = "ShowBorder",
+ Description = "Show border",
+ Type = "bool",
+ ValueList = "true|false",
+ DefaultValue = "false"
+ },
+ new()
+ {
+ Name = "ShowShadow",
+ Description = "Show Shadow",
+ Type = "bool",
+ ValueList = "true|false",
+ DefaultValue = "false"
+ }
+ };
+}
diff --git a/src/BootstrapBlazor.Server/Components/Samples/AnchorLinks.razor b/src/BootstrapBlazor.Server/Components/Samples/AnchorLinks.razor
new file mode 100644
index 000000000..271ef1d15
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Samples/AnchorLinks.razor
@@ -0,0 +1,17 @@
+@page "/anchor-link"
+
+@Localizer["AnchorLinkTitle"]
+
+@Localizer["AnchorLinkDescribe1"] Hash @Localizer["AnchorLinkDescribe2"]
+
+
+
+
+
+
+ AnchorLink
@Localizer["AnchorLinkTips1"] Id
@Localizer["AnchorLinkTips2"]
+ @Localizer["AnchorLinkTips3"] Icon
@Localizer["AnchorLinkTips4"]
+ @((MarkupString)Localizer["AnchorLinkTips5"].Value)
+
+
+
diff --git a/src/BootstrapBlazor.Server/Components/Samples/AnchorLinks.razor.cs b/src/BootstrapBlazor.Server/Components/Samples/AnchorLinks.razor.cs
new file mode 100644
index 000000000..ce3e2acf9
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Samples/AnchorLinks.razor.cs
@@ -0,0 +1,51 @@
+// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+// Website: https://www.blazor.zone or https://argozhang.github.io/
+
+namespace BootstrapBlazor.Server.Components.Samples;
+
+///
+///
+///
+public partial class AnchorLinks
+{
+ [Inject]
+ [NotNull]
+ private IStringLocalizer? Localizer { get; set; }
+
+ private IEnumerable GetAttributes() => new AttributeItem[]
+ {
+ new()
+ {
+ Name = nameof(AnchorLink.Id),
+ Description = Localizer[$"Attr{nameof(AnchorLink.Id)}"],
+ Type = "string",
+ ValueList = " — ",
+ DefaultValue = " — "
+ },
+ new()
+ {
+ Name = nameof(AnchorLink.Icon),
+ Description = Localizer[$"Attr{nameof(AnchorLink.Icon)}"],
+ Type = "string",
+ ValueList = " — ",
+ DefaultValue = "fa-solid fa-link"
+ },
+ new()
+ {
+ Name = nameof(AnchorLink.Text),
+ Description = Localizer[$"Attr{nameof(AnchorLink.Text)}"],
+ Type = "string",
+ ValueList = " — ",
+ DefaultValue = " — "
+ },
+ new()
+ {
+ Name = nameof(AnchorLink.TooltipText),
+ Description = Localizer[$"Attr{nameof(AnchorLink.TooltipText)}"],
+ Type = "string",
+ ValueList = " — ",
+ DefaultValue = " — "
+ }
+ };
+}
diff --git a/src/BootstrapBlazor.Server/Components/Samples/Anchors.razor b/src/BootstrapBlazor.Server/Components/Samples/Anchors.razor
new file mode 100644
index 000000000..16c17af06
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Samples/Anchors.razor
@@ -0,0 +1,36 @@
+@page "/anchor"
+
+@Localizer["Title"]
+
+@Localizer["SubTitle"]
+
+
+
+
@((MarkupString)Localizer["IntroText2"].Value)
+
+
+ Anchor1
+
+
+ Anchor2
+
+
+ Anchor3
+
+
+ Anchor4
+
+
+
+
Anchor1
+
@((MarkupString)Localizer["ContentText1"].Value)
+
Anchor2
+
@((MarkupString)Localizer["ContentText1"].Value)
+
Anchor3
+
@((MarkupString)Localizer["ContentText1"].Value)
+
Anchor4
+
@((MarkupString)Localizer["ContentText1"].Value)
+
+
+
+
diff --git a/src/BootstrapBlazor.Server/Components/Samples/Anchors.razor.cs b/src/BootstrapBlazor.Server/Components/Samples/Anchors.razor.cs
new file mode 100644
index 000000000..07d09161f
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Samples/Anchors.razor.cs
@@ -0,0 +1,59 @@
+namespace BootstrapBlazor.Server.Components.Samples;
+
+///
+/// Anchors 组件示例
+///
+public partial class Anchors
+{
+ [Inject]
+ [NotNull]
+ private IStringLocalizer? Localizer { get; set; }
+
+ ///
+ /// 获得属性方法
+ ///
+ ///
+ private IEnumerable GetAttributes() => new AttributeItem[]
+ {
+ new()
+ {
+ Name = "Target",
+ Description = Localizer["DescTarget"],
+ Type = "string",
+ ValueList = " — ",
+ DefaultValue = " — "
+ },
+ new()
+ {
+ Name = "Container",
+ Description = Localizer["DescContainer"],
+ Type = "string",
+ ValueList = " — ",
+ DefaultValue = " — "
+ },
+ new()
+ {
+ Name = "IsAnimation",
+ Description = Localizer["DescIsAnimation"],
+ Type = "boolean",
+ ValueList = "true|false",
+ DefaultValue = "true"
+ },
+ new()
+ {
+ Name = "Offset",
+ Description = Localizer["DescOffset"],
+ Type = "int",
+ ValueList = " — ",
+ DefaultValue = "0"
+ },
+ new()
+ {
+ Name = "ChildContent",
+ Description = Localizer["DescChildContent"],
+ Type = "RenderFragment",
+ ValueList = " — ",
+ DefaultValue = " — "
+ }
+ };
+}
diff --git a/src/BootstrapBlazor.Server/Components/Samples/AutoCompletes.razor b/src/BootstrapBlazor.Server/Components/Samples/AutoCompletes.razor
new file mode 100644
index 000000000..dd890fe94
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Samples/AutoCompletes.razor
@@ -0,0 +1,101 @@
+@page "/auto-complete"
+@inject IStringLocalizer Localizer
+
+@Localizer["Title"]
+
+@Localizer["Description"]
+
+
+ @Localizer["NormalDescription"]
+
+
+
+
+
+ @Localizer["LikeMatchDescription"]
+
+
+
+
+
+ @((MarkupString)Localizer["NoDataTipDescription"].Value)
+
+
+
+
+
+ @Localizer["ValueChangedDescription"]
+
+
+
+
+
+ @((MarkupString)Localizer["ShowLabelDescription"].Value)
+
+
+
+
+
+
+
+
+
+
+
+
+ @Localizer["DebounceDescription"]
+
+
+
+
+
+
+
+
+
+
+
+
+
+ @context
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/BootstrapBlazor.Server/Components/Samples/AutoCompletes.razor.cs b/src/BootstrapBlazor.Server/Components/Samples/AutoCompletes.razor.cs
new file mode 100644
index 000000000..a0c18a692
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Samples/AutoCompletes.razor.cs
@@ -0,0 +1,174 @@
+// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+// Website: https://www.blazor.zone or https://argozhang.github.io/
+
+namespace BootstrapBlazor.Server.Components.Samples;
+
+///
+///
+///
+public sealed partial class AutoCompletes
+{
+ private Foo Model { get; set; } = new Foo() { Name = "" };
+
+ private static List StaticItems => new() { "1", "12", "123", "1234", "12345", "123456", "abc", "abcdef", "ABC", "aBcDeFg", "ABCDEFG" };
+
+ private readonly List _items = new();
+ private IEnumerable Items => _items;
+ private Task OnValueChanged(string val)
+ {
+ _items.Clear();
+ _items.Add($"{val}@163.com");
+ _items.Add($"{val}@126.com");
+ _items.Add($"{val}@sina.com");
+ _items.Add($"{val}@hotmail.com");
+ return Task.CompletedTask;
+ }
+
+ [NotNull]
+ private ConsoleLogger? Logger { get; set; }
+
+ private Task OnSelectedItemChanged(string val)
+ {
+ Logger.Log($"Value: {val}");
+ return Task.CompletedTask;
+ }
+
+ [NotNull]
+ private ConsoleLogger? GroupLogger { get; set; }
+
+ private Task GroupOnSelectedItemChanged(string val)
+ {
+ GroupLogger.Log($"Value: {val}");
+ return Task.CompletedTask;
+ }
+
+ ///
+ /// 获得属性方法
+ ///
+ ///
+ private IEnumerable GetAttributes() => new AttributeItem[]
+ {
+
+ new()
+ {
+ Name = "ShowLabel",
+ Description = Localizer["Att1"],
+ Type = "bool",
+ ValueList = "true|false",
+ DefaultValue = "true"
+ },
+ new()
+ {
+ Name = "ChildContent",
+ Description = Localizer["Att2"],
+ Type = "RenderFragment",
+ ValueList = " — ",
+ DefaultValue = " — "
+ },
+ new()
+ {
+ Name = "ItemTemplate",
+ Description = Localizer["AttItemTemplate"],
+ Type = "RenderFragment",
+ ValueList = " — ",
+ DefaultValue = " — "
+ },
+ new()
+ {
+ Name = "Items",
+ Description = Localizer["Att3"],
+ Type = "IEnumerable",
+ ValueList = " — ",
+ DefaultValue = " — "
+ },
+ new()
+ {
+ Name = "NoDataTip",
+ Description = Localizer["Att4"],
+ Type = "string",
+ ValueList = " — ",
+ DefaultValue = Localizer["Att4DefaultValue"]!
+ },
+ new()
+ {
+ Name = "DisplayCount",
+ Description = Localizer["Att5"],
+ Type = "int?",
+ ValueList = " — ",
+ DefaultValue = " — "
+ },
+ new()
+ {
+ Name = "ValueChanged",
+ Description = Localizer["Att6"],
+ Type = "Action",
+ ValueList = " — ",
+ DefaultValue = " — "
+ },
+ new()
+ {
+ Name = "IsLikeMatch",
+ Description = Localizer["Att7"],
+ Type = "bool",
+ ValueList = "true|false",
+ DefaultValue = "false"
+ },
+ new()
+ {
+ Name = "IgnoreCase",
+ Description = Localizer["Att8"],
+ Type = "bool",
+ ValueList = "true|false",
+ DefaultValue = "true"
+ },
+ new()
+ {
+ Name = "OnCustomFilter",
+ Description = Localizer["Att9"],
+ Type = "Func>>",
+ ValueList = " — ",
+ DefaultValue = " — "
+ },
+ new()
+ {
+ Name = "Debounce",
+ Description = Localizer["Debounce"],
+ Type = "int",
+ ValueList = " — ",
+ DefaultValue = "0"
+ },
+ new()
+ {
+ Name = nameof(AutoComplete.SkipEnter),
+ Description = Localizer[nameof(AutoComplete.SkipEnter)],
+ Type = "bool",
+ ValueList = "true/false",
+ DefaultValue = "false"
+ },
+ new()
+ {
+ Name = nameof(AutoComplete.SkipEsc),
+ Description = Localizer[nameof(AutoComplete.SkipEsc)],
+ Type = "bool",
+ ValueList = "true/false",
+ DefaultValue = "false"
+ },
+ new()
+ {
+ Name = nameof(AutoComplete.OnValueChanged),
+ Description = Localizer[nameof(AutoComplete.OnValueChanged)],
+ Type = "Func",
+ ValueList = " — ",
+ DefaultValue = " — "
+ },
+ new()
+ {
+ Name = nameof(AutoComplete.OnSelectedItemChanged),
+ Description = Localizer[nameof(AutoComplete.OnSelectedItemChanged)],
+ Type = "Func",
+ ValueList = " — ",
+ DefaultValue = " — "
+ }
+ };
+}
diff --git a/src/BootstrapBlazor.Server/Components/Samples/AutoFills.razor b/src/BootstrapBlazor.Server/Components/Samples/AutoFills.razor
new file mode 100644
index 000000000..8fe89f96a
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Samples/AutoFills.razor
@@ -0,0 +1,69 @@
+@page "/auto-fill"
+@inject IStringLocalizer Localizer
+
+@Localizer["Title"]
+@Localizer["Description"]
+
+
+
+ @((MarkupString)@Localizer["NormalDesc"].Value)
+
+
+
+
+
+
+
+
+
@context.Name
+
@Foo.GetTitle(context.Id)
+
+
+
+
+
+
+
+
+
+ @((MarkupString)Localizer["CustomFilterDesc"].Value)
+
+
+
+
+
+
+
+
@context.Name
+
@Foo.GetTitle(context.Id)
+
+
+
+
+
+
+
+
+
+ @((MarkupString)@Localizer["ShowDropdownListOnFocusDesc"].Value)
+
+
+
+
+
+
+
+
+
@context.Name
+
@Foo.GetTitle(context.Id)
+
+
+
+
+
+
+
+
diff --git a/src/BootstrapBlazor.Server/Components/Samples/AutoFills.razor.cs b/src/BootstrapBlazor.Server/Components/Samples/AutoFills.razor.cs
new file mode 100644
index 000000000..edd711da3
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Samples/AutoFills.razor.cs
@@ -0,0 +1,157 @@
+// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+// Website: https://www.blazor.zone or https://argozhang.github.io/
+
+namespace BootstrapBlazor.Server.Components.Samples;
+
+///
+///
+///
+partial class AutoFills
+{
+ [NotNull]
+ private Foo Model { get; set; } = new();
+
+ private Task OnSelectedItemChanged(Foo foo)
+ {
+ Model = Utility.Clone(foo);
+ StateHasChanged();
+ return Task.CompletedTask;
+ }
+
+ private static string OnGetDisplayText(Foo foo) => foo.Name ?? "";
+
+ [NotNull]
+ private IEnumerable? Items { get; set; }
+
+ [Inject]
+ [NotNull]
+ private IStringLocalizer? LocalizerFoo { get; set; }
+
+ ///
+ protected override void OnInitialized()
+ {
+ base.OnInitialized();
+
+ Items = Foo.GenerateFoo(LocalizerFoo);
+ Model = Items.First();
+ }
+
+ private Task> OnCustomFilter(string searchText)
+ {
+ var items = string.IsNullOrEmpty(searchText) ? Items : Items.Where(i => i.Count > 50 && i.Name!.Contains(searchText));
+ return Task.FromResult(items);
+ }
+
+ ///
+ /// Get property method
+ ///
+ ///
+ private IEnumerable GetAttributes() => new AttributeItem[]
+ {
+ new()
+ {
+ Name = "DisplayCount",
+ Description = Localizer["Att1"],
+ Type = "int",
+ ValueList = " — ",
+ DefaultValue = " — "
+ },
+ new()
+ {
+ Name = "NoDataTip",
+ Description = Localizer["Att2"],
+ Type = "string",
+ ValueList = " — ",
+ DefaultValue = Localizer["Def2"]
+ },
+ new()
+ {
+ Name = "IgnoreCase",
+ Description = Localizer["Att3"],
+ Type = "bool",
+ ValueList = "true/false",
+ DefaultValue = "true"
+ },
+ new()
+ {
+ Name = "IsLikeMatch",
+ Description = Localizer["Att4"],
+ Type = "bool",
+ ValueList = "true/false",
+ DefaultValue = "false"
+ },
+ new()
+ {
+ Name = "Items",
+ Description = Localizer["Att5"],
+ Type = "IEnumerable",
+ ValueList = " — ",
+ DefaultValue = " — "
+ },
+ new()
+ {
+ Name = "Debounce",
+ Description = Localizer["Att6"],
+ Type = "int",
+ ValueList = " — ",
+ DefaultValue = "0"
+ },
+ new()
+ {
+ Name = "OnCustomFilter",
+ Description = Localizer["Att7"],
+ Type = "Func>>",
+ ValueList = " — ",
+ DefaultValue = " — "
+ },
+ new()
+ {
+ Name = "OnGetDisplayText",
+ Description = Localizer["Att8"],
+ Type = "Func",
+ ValueList = " — ",
+ DefaultValue = " — "
+ },
+ new()
+ {
+ Name = "OnSelectedItemChanged",
+ Description = Localizer["Att9"],
+ Type = "Func",
+ ValueList = " — ",
+ DefaultValue = " — "
+ },
+ new()
+ {
+ Name = nameof(AutoFill.ShowDropdownListOnFocus),
+ Description = Localizer["Att10"],
+ Type = "bool",
+ ValueList = "true/false",
+ DefaultValue = "true"
+ },
+ new()
+ {
+ Name = "Template",
+ Description = Localizer["Att11"],
+ Type = "RenderFragment",
+ ValueList = " — ",
+ DefaultValue = " — "
+ },
+ new()
+ {
+ Name = nameof(AutoFill.SkipEnter),
+ Description = Localizer["Att12"],
+ Type = "bool",
+ ValueList = "true/false",
+ DefaultValue = "false"
+ },
+ new()
+ {
+ Name = nameof(AutoFill.SkipEsc),
+ Description = Localizer["Att13"],
+ Type = "bool",
+ ValueList = "true/false",
+ DefaultValue = "false"
+ }
+ };
+}
diff --git a/src/BootstrapBlazor.Server/Components/Samples/AutoRedirects.razor b/src/BootstrapBlazor.Server/Components/Samples/AutoRedirects.razor
new file mode 100644
index 000000000..07a2eaa50
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Samples/AutoRedirects.razor
@@ -0,0 +1,12 @@
+@page "/auto-redirect"
+@inject IStringLocalizer Localizer
+
+@Localizer["Title"]
+@Localizer["Description"]
+
+
+
+
+
+
+
diff --git a/src/BootstrapBlazor.Server/Components/Samples/AutoRedirects.razor.cs b/src/BootstrapBlazor.Server/Components/Samples/AutoRedirects.razor.cs
new file mode 100644
index 000000000..751f69c89
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Samples/AutoRedirects.razor.cs
@@ -0,0 +1,60 @@
+// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+// Website: https://www.blazor.zone or https://argozhang.github.io/
+
+namespace BootstrapBlazor.Server.Components.Samples;
+
+///
+/// AutoRedirects
+///
+public partial class AutoRedirects
+{
+ [NotNull]
+ private ConsoleLogger? Logger { get; set; }
+
+ private Task OnBeforeRedirectAsync()
+ {
+ Logger.Log("Ready to redirect");
+ return Task.FromResult(true);
+ }
+
+ ///
+ /// Get property method
+ ///
+ ///
+ private IEnumerable GetAttributes() => new AttributeItem[]
+ {
+ new()
+ {
+ Name = nameof(AutoRedirect.Interval),
+ Description = "Time interval",
+ Type = "int",
+ ValueList = " — ",
+ DefaultValue = "60000"
+ },
+ new()
+ {
+ Name = nameof(AutoRedirect.RedirectUrl),
+ Description = "Redirect address",
+ Type = "string",
+ ValueList = " — ",
+ DefaultValue = " — "
+ },
+ new()
+ {
+ Name = nameof(AutoRedirect.IsForceLoad),
+ Description = "Whether to force redirection",
+ Type = "string",
+ ValueList = " — ",
+ DefaultValue = " — "
+ },
+ new()
+ {
+ Name = nameof(AutoRedirect.OnBeforeRedirectAsync),
+ Description = "Callback method before address jump",
+ Type = "Func>",
+ ValueList = " — ",
+ DefaultValue = " — "
+ }
+ };
+}
diff --git a/src/BootstrapBlazor.Server/Components/Samples/Avatars.razor b/src/BootstrapBlazor.Server/Components/Samples/Avatars.razor
new file mode 100644
index 000000000..ea563f7c1
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Samples/Avatars.razor
@@ -0,0 +1,59 @@
+@page "/avatar"
+@inject IStringLocalizer Localizer
+
+@Localizer["Title"]
+
+@Localizer["SubTitle"]
+
+
+
+
+
+
+
+
+
+
+
+
+
+ @((MarkupString)Localizer["BorderDiv1"].Value)
+ @((MarkupString)Localizer["BorderDiv2"].Value)
+
+
+
+
+
+
+
diff --git a/src/BootstrapBlazor.Server/Components/Samples/Avatars.razor.cs b/src/BootstrapBlazor.Server/Components/Samples/Avatars.razor.cs
new file mode 100644
index 000000000..412bd9797
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Samples/Avatars.razor.cs
@@ -0,0 +1,98 @@
+// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+// Website: https://www.blazor.zone or https://argozhang.github.io/
+
+namespace BootstrapBlazor.Server.Components.Samples;
+
+///
+/// Avatars 组件
+///
+public sealed partial class Avatars
+{
+ private static async Task GetUrlAsync()
+ {
+ // 模拟异步获取图像地址
+ await Task.Delay(500);
+ return "./images/Argo-C.png";
+ }
+
+ ///
+ /// 获得属性方法
+ ///
+ ///
+ private IEnumerable GetAttributes() => new AttributeItem[]
+ {
+ new()
+ {
+ Name = "Size",
+ Description = Localizer["Size"],
+ Type = "Size",
+ ValueList = "ExtraSmall|Small|Medium|Large|ExtraLarge|ExtraExtraLarge",
+ DefaultValue = "None"
+ },
+ new()
+ {
+ Name = "IsBorder",
+ Description = Localizer["IsBorder"],
+ Type = "bool",
+ ValueList = "true|false",
+ DefaultValue = "false"
+ },
+ new()
+ {
+ Name = "IsCircle",
+ Description = Localizer["IsCircle"],
+ Type = "bool",
+ ValueList = "true|false",
+ DefaultValue = "false"
+ },
+ new()
+ {
+ Name = "IsIcon",
+ Description = Localizer["IsIcon"],
+ Type = "bool",
+ ValueList = "true|false",
+ DefaultValue = "false"
+ },
+ new()
+ {
+ Name = "IsText",
+ Description = Localizer["IsText"],
+ Type = "bool",
+ ValueList = "true|false",
+ DefaultValue = "false"
+ },
+ new()
+ {
+ Name = "Icon",
+ Description = Localizer["Icon"],
+ Type = "string",
+ ValueList = " — ",
+ DefaultValue = "fa-solid fa-user"
+ },
+ new()
+ {
+ Name = "Text",
+ Description = Localizer["Text"],
+ Type = "string",
+ ValueList = " — ",
+ DefaultValue = " — "
+ },
+ new()
+ {
+ Name = "Url",
+ Description = Localizer["Url"],
+ Type = "string",
+ ValueList = " — ",
+ DefaultValue = " — "
+ },
+ new()
+ {
+ Name = "GetUrlAsync",
+ Description = Localizer["GetUrlAsync"],
+ Type = "Func>",
+ ValueList = " — ",
+ DefaultValue = " — "
+ }
+ };
+}
diff --git a/src/BootstrapBlazor.Server/Components/Samples/Badges.razor b/src/BootstrapBlazor.Server/Components/Samples/Badges.razor
new file mode 100644
index 000000000..d81402cee
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Samples/Badges.razor
@@ -0,0 +1,52 @@
+@page "/badge"
+@inject IStringLocalizer Localizer
+
+@Localizer["Title"]
+
+@Localizer["SubTitle"]
+
+
+
+
primary
+
secondary
+
success
+
danger
+
warning
+
info
+
dark
+
light
+
+
+
+
+
+
primary
+
secondary
+
success
+
danger
+
warning
+
info
+
dark
+
light
+
+
+
+
+
+
+
+
+ @Localizer["ButtonSpan"]
+ 1
+
+
+
+
+
+
+
diff --git a/src/BootstrapBlazor.Server/Components/Samples/Badges.razor.cs b/src/BootstrapBlazor.Server/Components/Samples/Badges.razor.cs
new file mode 100644
index 000000000..24757b46b
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Samples/Badges.razor.cs
@@ -0,0 +1,51 @@
+// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+// Website: https://www.blazor.zone or https://argozhang.github.io/
+
+namespace BootstrapBlazor.Server.Components.Samples;
+
+///
+///
+///
+public sealed partial class Badges
+{
+ ///
+ /// 获得属性方法
+ ///
+ ///
+ private IEnumerable GetAttributes() => new AttributeItem[]
+ {
+ new()
+ {
+ Name = "ChildContent",
+ Description = Localizer["ChildContent"],
+ Type = "RenderFragment",
+ ValueList = " — ",
+ DefaultValue = " — "
+ },
+ new()
+ {
+ Name = "Class",
+ Description = Localizer["Class"],
+ Type = "string",
+ ValueList = " — ",
+ DefaultValue = " — "
+ },
+ new()
+ {
+ Name = "Color",
+ Description = Localizer["Color"],
+ Type = "Color",
+ ValueList = "Primary / Secondary / Success / Danger / Warning / Info / Dark",
+ DefaultValue = "Primary"
+ },
+ new()
+ {
+ Name = "IsPill",
+ Description = Localizer["IsPill"],
+ Type = "boolean",
+ ValueList = " — ",
+ DefaultValue = "false"
+ }
+ };
+}
diff --git a/src/BootstrapBlazor.Server/Components/Samples/Badges.razor.css b/src/BootstrapBlazor.Server/Components/Samples/Badges.razor.css
new file mode 100644
index 000000000..45ccb57ee
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Samples/Badges.razor.css
@@ -0,0 +1,21 @@
+.badge-widget {
+ display: inline-block;
+ border: solid 1px #ddd;
+ border-radius: var(--bs-border-radius);
+ padding: 6px 12px;
+ position: relative;
+ transition: all .25s linear;
+ cursor: pointer;
+}
+
+ .badge-widget:hover {
+ box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(40, 167, 69, 0.5);
+ border-color: #28a745 !important;
+ }
+
+ .badge-widget ::deep .badge {
+ position: absolute;
+ top: -6px;
+ right: -6px;
+ opacity: 0.8;
+ }
diff --git a/src/BootstrapBlazor.Server/Components/Samples/BaiduOcr.razor b/src/BootstrapBlazor.Server/Components/Samples/BaiduOcr.razor
new file mode 100644
index 000000000..ad2ce7650
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Samples/BaiduOcr.razor
@@ -0,0 +1,136 @@
+@page "/ocr"
+@inject IBaiduOcr OcrService
+@inject IStringLocalizer Localizer
+@inject ToastService ToastService
+
+@Localizer["Title"]
+
+@Localizer["SubTitle"]
+
+@Localizer["BaiduOcrDesc"]
+
+
+
+@Localizer["BaiduOcrIntro"]
+
+@((MarkupString)Localizer["BaiduOcrStep1"].Value)
+@((MarkupString)Localizer["BaiduOcrStep2"].Value)
+
+
+
+
+ @if (Invoice != null)
+ {
+
+ }
+
+
+
+ 发票种类
+ 增值税专用发票:special_vat_invoice
+ 增值税电子专用发票:elec_special_vat_invoice
+ 增值税普通发票:normal_invoice
+ 增值税普通发票(电子):elec_normal_invoice
+ 增值税普通发票(卷式):roll_normal_invoice
+ 通行费增值税电子普通发票:toll_elec_normal_invoice
+ 区块链电子发票(目前仅支持深圳地区):blockchain_invoice
+ 全电发票(专用发票):elec_invoice_special
+ 全电发票(普通发票):elec_invoice_normal
+ 货运运输业增值税专用发票:special_freight_transport_invoice
+ 机动车销售发票:motor_vehicle_invoice
+ 二手车销售发票:used_vehicle_invoice
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/BootstrapBlazor.Server/Components/Samples/BaiduOcr.razor.cs b/src/BootstrapBlazor.Server/Components/Samples/BaiduOcr.razor.cs
new file mode 100644
index 000000000..8ebad43ec
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Samples/BaiduOcr.razor.cs
@@ -0,0 +1,130 @@
+// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+// Website: https://www.blazor.zone or https://argozhang.github.io/
+
+using Microsoft.AspNetCore.Components.Forms;
+
+namespace BootstrapBlazor.Server.Components.Samples;
+
+///
+/// 百度文字识别示例
+///
+public partial class BaiduOcr : IDisposable
+{
+ private InvoiceEntity? Invoice { get; set; }
+
+ /*以下示例为本站特殊处理逻辑可不参考*/
+ private bool IsLoading { get; set; }
+
+ private string ButtonIcon { get; } = "fa-solid fa-cloud-arrow-up";
+
+ private string LoadingIcon { get; } = "fa-solid fa-spinner fa-spin-pulse";
+
+ private string Icon => IsLoading ? LoadingIcon : ButtonIcon;
+
+ ///
+ /// 取消请求令牌
+ ///
+ private CancellationTokenSource? TokenSource { get; set; }
+
+ private async Task OnClickToUploadBlock(UploadFile file)
+ {
+ if (file.File != null)
+ {
+ // 设置 按钮禁用
+ IsLoading = true;
+ StateHasChanged();
+
+ // 获得上传文件
+ var payload = await file.GetBytesAsync(file.File.Size);
+ if (payload?.Any() ?? false)
+ {
+ try
+ {
+ TokenSource ??= new();
+ var result = await OcrService.CheckVatInvoiceAsync(payload, TokenSource.Token);
+ Invoice = result.Entity;
+ if (result.Entity != null)
+ {
+ await ToastService.Success("Vat Invoice", "VAT Invoice success!");
+ }
+ else
+ {
+ await ToastService.Information("Vat Invoice", $"{result.ErrorCode}: {result.ErrorMessage}");
+ }
+ }
+ catch (TaskCanceledException)
+ {
+
+ }
+ }
+
+ IsLoading = false;
+ StateHasChanged();
+ }
+ }
+
+ private InvoiceForm Model { get; set; } = new() { InvoiceType = "elec_special_vat_invoice", TotalAmount = "0" };
+
+ private async Task Verify(EditContext context)
+ {
+ var result = await OcrService.VerifyInvoiceAsync(Model.InvoiceCode, Model.InvoiceNum, Model.InvoiceDate, Model.InvoiceType, Model.CheckCode, Model.TotalAmount);
+ if (result.ErrorCode != 0)
+ {
+ await ToastService.Information("Verify Vat", $"{result.ErrorCode}: {result.ErrorMessage}");
+ }
+ else if (result.Entity != null)
+ {
+ await ToastService.Success("Verify Vat", result.Entity?.VerifyMessage);
+ }
+ }
+
+ private class InvoiceForm
+ {
+ [Required(ErrorMessage = "发票代码不能为空")]
+ [NotNull]
+ public string? InvoiceCode { get; set; }
+
+ [Required(ErrorMessage = "发票号码不能为空")]
+ [NotNull]
+ public string? InvoiceNum { get; set; }
+
+ [Required(ErrorMessage = "开票日期不能为空")]
+ [NotNull]
+ public string? InvoiceDate { get; set; }
+
+ [NotNull]
+ public string? InvoiceType { get; set; }
+
+ [Required(ErrorMessage = "校验码不能为空")]
+ [NotNull]
+ public string? CheckCode { get; set; }
+
+ [NotNull]
+ public string? TotalAmount { get; set; }
+ }
+
+ ///
+ /// 关闭网页时调用
+ ///
+ ///
+ ///
+ protected virtual void Dispose(bool disposing)
+ {
+ if (disposing && TokenSource != null)
+ {
+ TokenSource.Cancel();
+ TokenSource.Dispose();
+ }
+ }
+
+ ///
+ /// 关闭网页时调用
+ ///
+ ///
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+}
diff --git a/src/BootstrapBlazor.Server/Components/Samples/BarcodeReaders.razor b/src/BootstrapBlazor.Server/Components/Samples/BarcodeReaders.razor
new file mode 100644
index 000000000..42f3061d6
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Samples/BarcodeReaders.razor
@@ -0,0 +1,36 @@
+@page "/barcode-reader"
+@inject IStringLocalizer Localizer
+
+@Localizer["SubTitle"]
+
+
+
+@Localizer["Attention"]
+
+ @((MarkupString)Localizer["Li1"].Value)
+ @Localizer["Li4"]
+
+
+
+ @Localizer["Step"]
+
+ @Localizer["BasicUsageLi1"]
+ @Localizer["BasicUsageLi2"]
+ @Localizer["BasicUsageLi3"]
+
+
+
+
+
+
+ @Localizer["Step"]
+
+ @Localizer["ImageLi1"]
+ @Localizer["ImageLi2"]
+ @Localizer["ImageLi3"]
+
+
+
+
+
+
diff --git a/src/BootstrapBlazor.Server/Components/Samples/BarcodeReaders.razor.cs b/src/BootstrapBlazor.Server/Components/Samples/BarcodeReaders.razor.cs
new file mode 100644
index 000000000..2586658ff
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Samples/BarcodeReaders.razor.cs
@@ -0,0 +1,187 @@
+// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+// Website: https://www.blazor.zone or https://argozhang.github.io/
+
+namespace BootstrapBlazor.Server.Components.Samples;
+
+///
+///
+///
+public sealed partial class BarcodeReaders
+{
+ [NotNull]
+ private ConsoleLogger? Logger { get; set; }
+
+ private Task OnInit(IEnumerable devices)
+ {
+ var cams = string.Join("", devices.Select(i => i.Label));
+ Logger.Log($"{Localizer["InitLog"]} {cams}");
+ return Task.CompletedTask;
+ }
+ private Task OnResult(string barcode)
+ {
+ Logger.Log($"{Localizer["ScanCodeLog"]} {barcode}");
+ return Task.CompletedTask;
+ }
+
+ private Task OnError(string error)
+ {
+ Logger.Log($"{Localizer["ErrorLog"]} {error}");
+ return Task.CompletedTask;
+ }
+
+ private Task OnStart()
+ {
+ Logger.Log(Localizer["OpenCameraLog"]);
+ return Task.CompletedTask;
+ }
+
+ private Task OnClose()
+ {
+ Logger.Log(Localizer["CloseCameraLog"]);
+ return Task.CompletedTask;
+ }
+
+ [NotNull]
+ private ConsoleLogger? ImageLogger { get; set; }
+
+ private Task OnImageResult(string barcode)
+ {
+ ImageLogger.Log($"{Localizer["ScanCodeLog"]} {barcode}");
+ return Task.CompletedTask;
+ }
+
+ private Task OnImageError(string err)
+ {
+ ImageLogger.Log($"{Localizer["ErrorLog"]} {err}");
+ return Task.CompletedTask;
+ }
+
+ ///
+ /// 获得属性
+ ///
+ ///
+ private IEnumerable GetAttributes() => new AttributeItem[]
+ {
+ new()
+ {
+ Name = "ButtonScanText",
+ Description = Localizer["ButtonScanText"],
+ Type = "string",
+ ValueList = " — ",
+ DefaultValue = Localizer["ButtonScanTextDefaultValue"]
+ },
+ new()
+ {
+ Name = "ButtonStopText",
+ Description = Localizer["ButtonStopText"],
+ Type = "string",
+ ValueList = " — ",
+ DefaultValue = Localizer["ButtonStopTextDefaultValue"]
+ },
+ new()
+ {
+ Name = "AutoStopText",
+ Description = Localizer["AutoStopText"],
+ Type = "string",
+ ValueList = " — ",
+ DefaultValue = Localizer["AutoStopTextDefaultValue"]
+ },
+ new()
+ {
+ Name = "DeviceLabel",
+ Description = Localizer["DeviceLabel"],
+ Type = "string",
+ ValueList = " — ",
+ DefaultValue = Localizer["DeviceLabelDefaultValue"]
+ },
+ new()
+ {
+ Name = "InitDevicesString",
+ Description = Localizer["InitDevicesString"],
+ Type = "string",
+ ValueList = " — ",
+ DefaultValue = Localizer["InitDevicesStringDefaultValue"]
+ },
+ new()
+ {
+ Name = "NotFoundDevicesString",
+ Description = Localizer["NotFoundDevicesString"],
+ Type = "string",
+ ValueList = " — ",
+ DefaultValue = Localizer["NotFoundDevicesStringDefaultValue"]
+ },
+ new()
+ {
+ Name = "AutoStart",
+ Description = Localizer["AutoStart"],
+ Type = "boolean",
+ ValueList = "true|false",
+ DefaultValue = "false"
+ },
+ new()
+ {
+ Name = "AutoStop",
+ Description = Localizer["AutoStart"],
+ Type = "boolean",
+ ValueList = "true|false",
+ DefaultValue = "false"
+ },
+ new()
+ {
+ Name = "ScanType",
+ Description = "",
+ Type = "ScanType",
+ ValueList = "Camera|Image",
+ DefaultValue = "Camera"
+ },
+ new()
+ {
+ Name = "OnInit",
+ Description = Localizer["OnInit"],
+ Type = "Func, Task>",
+ ValueList = " — ",
+ DefaultValue = " — "
+ },
+ new()
+ {
+ Name = "OnResult",
+ Description = Localizer["OnResult"],
+ Type = "Func",
+ ValueList = " — ",
+ DefaultValue = " — "
+ },
+ new()
+ {
+ Name = "OnStart",
+ Description = Localizer["OnStart"],
+ Type = "Func",
+ ValueList = " — ",
+ DefaultValue = " — "
+ },
+ new()
+ {
+ Name = "OnClose",
+ Description = Localizer["OnClose"],
+ Type = "Func",
+ ValueList = " — ",
+ DefaultValue = " — "
+ },
+ new()
+ {
+ Name = "OnError",
+ Description = Localizer["OnError"],
+ Type = "Func",
+ ValueList = " — ",
+ DefaultValue = " — "
+ },
+ new()
+ {
+ Name = "OnDeviceChanged",
+ Description = Localizer["OnDeviceChanged"],
+ Type = "Func",
+ ValueList = " — ",
+ DefaultValue = " — "
+ }
+ };
+}
diff --git a/src/BootstrapBlazor.Server/Components/Samples/Blocks.razor b/src/BootstrapBlazor.Server/Components/Samples/Blocks.razor
new file mode 100644
index 000000000..5a409959e
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Samples/Blocks.razor
@@ -0,0 +1,73 @@
+@page "/block"
+@inject IStringLocalizer Localizer
+
+@Localizer["Title"]
+
+@Localizer["SubTitle"]
+
+
+
+
+ @Localizer["Content"]
+
+
+
+
+
+
+
+
+
+ @((MarkupString)Localizer["TemplateDiv1"].Value)
+
+
+ @((MarkupString)Localizer["TemplateDiv2"].Value)
+
+
+
+
+
+
+
+
+
+ @((MarkupString)Localizer["AuthorizateDiv1", UserName].Value)
+
+
+
+
+
+ @((MarkupString)Localizer["AuthorizateDiv2", context.User.Identity?.Name!].Value)
+
+
+ @((MarkupString)Localizer["AuthorizateDiv3"].Value)
+
+
+
+
+
+
+
+
+
+ @((MarkupString)Localizer["UsersDiv1", UserName].Value)
+
+
+
+
+
+
+
+
+
+ @((MarkupString)Localizer["RolesDiv1"].Value)
+
+
+
+
+
+
+ @((MarkupString)Localizer["Tips"].Value)
+
+
+
diff --git a/src/BootstrapBlazor.Server/Components/Samples/Blocks.razor.cs b/src/BootstrapBlazor.Server/Components/Samples/Blocks.razor.cs
new file mode 100644
index 000000000..11933f176
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Samples/Blocks.razor.cs
@@ -0,0 +1,108 @@
+// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+// Website: https://www.blazor.zone or https://argozhang.github.io/
+
+using Microsoft.AspNetCore.Components.Authorization;
+
+namespace BootstrapBlazor.Server.Components.Samples;
+
+///
+///
+///
+public partial class Blocks
+{
+ private bool IsShow { get; set; } = true;
+
+ private string GetIcon() => IsShow ? "fa-solid fa-eye-slash" : "fa-solid fa-eye";
+
+ private string GetText() => IsShow ? Localizer["IsHide"] : Localizer["IsShow"];
+
+ private void ToggleCondition() => IsShow = !IsShow;
+
+ private Task OnQueryCondition(string name) => Task.FromResult(IsShow);
+
+ private bool IsShow2 { get; set; } = true;
+
+ private void ToggleCondition2() => IsShow2 = !IsShow2;
+
+ private string GetIcon2() => IsShow2 ? "fa-solid fa-eye-slash" : "fa-solid fa-eye";
+
+ private string GetText2() => IsShow2 ? Localizer["IsHide"] : Localizer["IsShow"];
+
+ [Inject]
+ [NotNull]
+ private AuthenticationStateProvider? AuthenticationStateProvider { get; set; }
+
+ private bool IsAuth { get; set; }
+
+ private IEnumerable Users { get; } = new string[] { "BootstrapBlazor" };
+
+ [NotNull]
+ private string? UserName { get; set; }
+
+ private string GetUser() => IsAuth ? "fa-solid fa-user-secret" : "fa-solid fa-user";
+
+ private string GetUserText() => IsAuth ? Localizer["Logout"] : Localizer["Login"];
+
+ private async Task ToggleAuthor()
+ {
+ if (AuthenticationStateProvider is MockAuthenticationStateProvider mock)
+ {
+ if (!IsAuth)
+ {
+ mock.Login();
+ var state = await mock.GetAuthenticationStateAsync();
+ UserName = state.User.Identity?.Name;
+ IsAuth = state.User.Identity?.IsAuthenticated ?? false;
+ }
+ else
+ {
+ mock.Logout();
+ IsAuth = false;
+ UserName = "";
+ }
+ }
+ }
+
+ private IEnumerable Roles { get; } = new string[] { "User" };
+
+ private Task OnQueryCondition2(string name) => Task.FromResult(IsShow2);
+
+ private Task OnQueryUser(string name) => Task.FromResult(IsAuth);
+
+ private IEnumerable GetAttributes() => new AttributeItem[]
+ {
+ new()
+ {
+ Name = nameof(Block.OnQueryCondition),
+ Description = Localizer["OnQueryCondition"],
+ Type = "Func>",
+ ValueList = " — ",
+ DefaultValue = "true"
+ },
+ new()
+ {
+ Name = nameof(Block.ChildContent),
+ Description = Localizer["ChildContent"],
+ Type = "RenderFragment",
+ ValueList = " — ",
+ DefaultValue = " — "
+ },
+ new()
+ {
+ Name = nameof(Block.Authorized),
+ Description = Localizer["Authorized"],
+ Type = "RenderFragment",
+ ValueList = " — ",
+ DefaultValue = " — "
+ },
+ new()
+ {
+ Name = nameof(Block.NotAuthorized),
+ Description = Localizer["NotAuthorized"],
+ Type = "RenderFragment",
+ ValueList = " — ",
+ DefaultValue = " — "
+ }
+ };
+}
diff --git a/src/BootstrapBlazor.Server/Components/Samples/Bluetooth.razor b/src/BootstrapBlazor.Server/Components/Samples/Bluetooth.razor
new file mode 100644
index 000000000..8a87f2ca8
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Samples/Bluetooth.razor
@@ -0,0 +1,76 @@
+@page "/blue-tooth"
+@inject IStringLocalizer Localizer
+
+@Localizer["BluetoothTitle"]
+
+
+
+
+ @((MarkupString)Localizer["Tips"].Value)
+
+
+
+ @if (ShowUI)
+ {
+ @Localizer["InnerUI"]
+
+
+
+ }
+ else
+ {
+ @Localizer["BasicUsage"]
+
+
+ @Localizer["ConnectButtonText"]
+ @Localizer["DisconnectButtonText"]
+ @Localizer["PrintButtonText"]
+
+ }
+
+@message
+@statusMessage
+@errorMessage
+
+ @Localizer["SwitchUI"]
+
+
+@Localizer["BluetoothTitle"]
+
+
+ @Localizer["GetBatteryLevelButtonText"]
+
+
+ @value %
+ @message
+ @statusMessage
+ @errorMessage
+
+
+@Localizer["BluetoothHeartRate"]
+
+
+ @Localizer["GetHeartrateButtonText"]
+ @Localizer["StopHeartrateButtonText"]
+
+
+ @message
+ @statusMessage
+ @errorMessage
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/BootstrapBlazor.Server/Components/Samples/Bluetooth.razor.cs b/src/BootstrapBlazor.Server/Components/Samples/Bluetooth.razor.cs
new file mode 100644
index 000000000..014d0acc0
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Samples/Bluetooth.razor.cs
@@ -0,0 +1,365 @@
+// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+// Website: https://www.blazor.zone or https://argozhang.github.io/
+
+namespace BootstrapBlazor.Server.Components.Samples;
+
+///
+/// Bluetooth
+///
+public partial class Bluetooth
+{
+ Printer printer { get; set; } = new Printer();
+
+ ///
+ /// 显示内置界面
+ ///
+ bool ShowUI { get; set; } = false;
+
+ private string? message;
+ private string? statusMessage;
+ private string? errorMessage;
+
+ private Task OnResult(string? result)
+ {
+ message = result;
+ StateHasChanged();
+ return Task.CompletedTask;
+ }
+
+ private Task OnUpdateStatus(string message)
+ {
+ statusMessage = message;
+ StateHasChanged();
+ return Task.CompletedTask;
+ }
+
+ private Task OnError(string message)
+ {
+ errorMessage = message;
+ StateHasChanged();
+ return Task.CompletedTask;
+ }
+
+ private Task OnGetDevices(List? devices)
+ {
+ message = "";
+ if (devices == null || devices!.Count == 0) return Task.CompletedTask;
+ message += $"已配对设备{devices.Count}:{Environment.NewLine}";
+ devices.ForEach(a => message += $" {a}{Environment.NewLine}");
+ //this.message = this.message.Replace(Environment.NewLine, " ");
+ StateHasChanged();
+ return Task.CompletedTask;
+ }
+
+ ///
+ /// 切换 UI 方法
+ ///
+ public void SwitchUI()
+ {
+ ShowUI = !ShowUI;
+ }
+
+ Heartrate heartrate { get; set; } = new Heartrate();
+
+ private Task OnUpdateValue(int v)
+ {
+ value = v;
+ statusMessage = $"心率{value}";
+ StateHasChanged();
+ return Task.CompletedTask;
+ }
+
+ ///
+ /// 获取心率
+ ///
+ public async void GetHeartrate()
+ {
+ await heartrate.GetHeartrate();
+ }
+
+ ///
+ /// 停止获取心率
+ ///
+ public async void StopHeartrate()
+ {
+ await heartrate.StopHeartrate();
+ }
+
+ BatteryLevel batteryLevel { get; set; } = new BatteryLevel();
+
+ private decimal? value = 0;
+
+ private Task OnUpdateValue(decimal value)
+ {
+ this.value = value;
+ this.statusMessage = Localizer["DeviceBattery", value];
+ StateHasChanged();
+ return Task.CompletedTask;
+ }
+
+ private Task OnUpdateStatus(BluetoothDevice device)
+ {
+ this.statusMessage = device.Status;
+ StateHasChanged();
+ return Task.CompletedTask;
+ }
+
+ ///
+ /// 获取设备电量
+ ///
+ public async void GetBatteryLevel()
+ {
+ await batteryLevel.GetBatteryLevel();
+ }
+
+ ///
+ /// 获得属性方法
+ ///
+ ///
+ private IEnumerable GetAttributes() => new AttributeItem[]
+ {
+
+ new()
+ {
+ Name = "Commands",
+ Description = Localizer["CommandsAttr"],
+ Type = "string?",
+ ValueList = "-",
+ DefaultValue = "-"
+ },
+ new()
+ {
+ Name = "Print",
+ Description = Localizer["PrintAttr"],
+ Type = "async Task",
+ ValueList = "-",
+ DefaultValue = "-"
+ },
+ new()
+ {
+ Name = "OnUpdateStatus",
+ Description = Localizer["OnUpdateStatusAttr"],
+ Type = "Func?",
+ ValueList = "-",
+ DefaultValue = "-"
+ },
+ new()
+ {
+ Name = "OnUpdateError",
+ Description = Localizer["OnUpdateErrorAttr"],
+ Type = "Func?",
+ ValueList = "-",
+ DefaultValue = "-"
+ },
+ new()
+ {
+ Name = "PrinterElement",
+ Description = Localizer["PrinterElementAttr"],
+ Type = "ElementReference",
+ ValueList = "-",
+ DefaultValue = "-"
+ },
+ new()
+ {
+ Name = "Opt",
+ Description = Localizer["OptAttr"],
+ Type = "PrinterOption",
+ ValueList = "-",
+ DefaultValue = "-"
+ },
+ new()
+ {
+ Name = "ShowUI",
+ Description = Localizer["ShowUIAttr"],
+ Type = "bool",
+ ValueList = "True|False",
+ DefaultValue = "False"
+ },
+ new()
+ {
+ Name = "Debug",
+ Description = Localizer["DebugAttr"],
+ Type = "bool",
+ ValueList = "True|False",
+ DefaultValue = "False"
+ },
+ new()
+ {
+ Name = "DeviceName",
+ Description = Localizer["DeviceNameAttr"],
+ Type = "string?",
+ ValueList = "-",
+ DefaultValue = "-"
+ },
+ };
+
+ ///
+ /// 获得属性方法
+ ///
+ ///
+ private IEnumerable GetPrinterOptionAttributes() => new AttributeItem[]
+ {
+ new()
+ {
+ Name = "NamePrefix",
+ Description = Localizer["NamePrefixAttr"],
+ Type = "string?",
+ ValueList = "-",
+ DefaultValue = "null"
+ },
+ new()
+ {
+ Name = "MaxChunk",
+ Description = Localizer["MaxChunkAttr"],
+ Type = "int",
+ ValueList = "-",
+ DefaultValue = "100"
+ },
+ };
+
+ ///
+ /// 获得蓝牙设备类
+ ///
+ ///
+ private IEnumerable GetBluetoothDeviceAttributes() => new AttributeItem[]
+ {
+ new()
+ {
+ Name = "Name",
+ Description = Localizer["NameAttr"],
+ Type = "string?",
+ ValueList = "-",
+ DefaultValue = "null"
+ },
+ new()
+ {
+ Name = "Value",
+ Description = Localizer["ValueAttr"],
+ Type = "decimal?",
+ ValueList = "-",
+ DefaultValue = "null"
+ },
+ new()
+ {
+ Name = "Status",
+ Description = Localizer["StatusAttr"],
+ Type = "string?",
+ ValueList = "-",
+ DefaultValue = "null"
+ },
+ new()
+ {
+ Name = "Error",
+ Description = Localizer["ErrorAttr"],
+ Type = "string?",
+ ValueList = "-",
+ DefaultValue = "null"
+ }
+ };
+
+ ///
+ /// 获得属性方法
+ ///
+ ///
+ private IEnumerable GetAttributesBatteryLevel() => new AttributeItem[]
+ {
+ new()
+ {
+ Name = "GetBatteryLevel",
+ Description = Localizer["GetBatteryLevelAttr"],
+ Type = "async Task",
+ ValueList = "-",
+ DefaultValue = "-"
+ },
+ new()
+ {
+ Name = "OnUpdateValue",
+ Description = Localizer["OnUpdateValueAttr"],
+ Type = "Func?",
+ ValueList = "-",
+ DefaultValue = "-"
+ },
+ new()
+ {
+ Name = "OnUpdateStatus",
+ Description = Localizer["OnUpdateStatusAttr"],
+ Type = "Func?",
+ ValueList = "-",
+ DefaultValue = "-"
+ },
+ new()
+ {
+ Name = "OnUpdateError",
+ Description = Localizer["OnUpdateErrorAttr"],
+ Type = "Func?",
+ ValueList = "-",
+ DefaultValue = "-"
+ },
+ new()
+ {
+ Name = "BatteryLevelElement",
+ Description = Localizer["BatteryLevelElementAttr"],
+ Type = "ElementReference",
+ ValueList = "-",
+ DefaultValue = "-"
+ }
+ };
+
+
+ ///
+ /// 获得属性方法
+ ///
+ ///
+ private IEnumerable GetAttributesHeartrate() => new AttributeItem[]
+ {
+ new()
+ {
+ Name = "GetHeartrate",
+ Description = Localizer["GetHeartrateAttr"],
+ Type = "async Task",
+ ValueList = "-",
+ DefaultValue = "-"
+ },
+ new()
+ {
+ Name = "StopHeartrate",
+ Description = Localizer["StopHeartrateAttr"],
+ Type = "async Task",
+ ValueList = "-",
+ DefaultValue = "-"
+ },
+ new()
+ {
+ Name = "OnUpdateValue",
+ Description = Localizer["OnUpdateValueAttr"],
+ Type = "Func?",
+ ValueList = "-",
+ DefaultValue = "-"
+ },
+ new()
+ {
+ Name = "OnUpdateStatus",
+ Description = Localizer["OnUpdateStatusAttr"],
+ Type = "Func?",
+ ValueList = "-",
+ DefaultValue = "-"
+ },
+ new()
+ {
+ Name = "OnUpdateError",
+ Description = Localizer["OnUpdateErrorAttr"],
+ Type = "Func?",
+ ValueList = "-",
+ DefaultValue = "-"
+ },
+ new()
+ {
+ Name = "HeartrateElement",
+ Description = Localizer["HeartrateElementAttr"],
+ Type = "ElementReference",
+ ValueList = "-",
+ DefaultValue = "-"
+ }
+ };
+}
diff --git a/src/BootstrapBlazor.Server/Components/Samples/Bluetooth.razor.css b/src/BootstrapBlazor.Server/Components/Samples/Bluetooth.razor.css
new file mode 100644
index 000000000..c5237467f
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Samples/Bluetooth.razor.css
@@ -0,0 +1,11 @@
+.hidden {
+ display: none;
+}
+
+.notSupported {
+ padding: 1em;
+ background-color: red;
+ color: white;
+ margin-top: 1em;
+ margin-bottom: 1em;
+}
diff --git a/src/BootstrapBlazor.Server/Components/Samples/Breadcrumbs.razor b/src/BootstrapBlazor.Server/Components/Samples/Breadcrumbs.razor
new file mode 100644
index 000000000..ec9979523
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Samples/Breadcrumbs.razor
@@ -0,0 +1,10 @@
+@page "/breadcrumb"
+@inject IStringLocalizer Localizer
+
+@Localizer["Title"]
+
+@Localizer["Describe"]
+
+
+
+
diff --git a/src/BootstrapBlazor.Server/Components/Samples/Breadcrumbs.razor.cs b/src/BootstrapBlazor.Server/Components/Samples/Breadcrumbs.razor.cs
new file mode 100644
index 000000000..51576e31a
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Samples/Breadcrumbs.razor.cs
@@ -0,0 +1,28 @@
+// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+// Website: https://www.blazor.zone or https://argozhang.github.io/
+
+namespace BootstrapBlazor.Server.Components.Samples;
+
+///
+/// Breadcrumbs 组件示例
+///
+public partial class Breadcrumbs
+{
+ [NotNull]
+ private IEnumerable? DataSource { get; set; }
+
+ ///
+ /// OnInitialized 方法
+ ///
+ protected override void OnInitialized()
+ {
+ base.OnInitialized();
+ DataSource = new List
+ {
+ new BreadcrumbItem("Home", "#"),
+ new BreadcrumbItem("Library", "#"),
+ new BreadcrumbItem("Data")
+ };
+ }
+}
diff --git a/src/BootstrapBlazor.Server/Components/Samples/Buttons.razor b/src/BootstrapBlazor.Server/Components/Samples/Buttons.razor
new file mode 100644
index 000000000..f726c5c29
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Samples/Buttons.razor
@@ -0,0 +1,159 @@
+@page "/button"
+@inject IStringLocalizer Localizer
+
+@Localizer["Title"]
+
+@Localizer["Description"]
+
+
+
+
@Localizer["PrimaryButton"]
+
@Localizer["SecondaryButton"]
+
@Localizer["SuccessButton"]
+
@Localizer["DangerButton"]
+
@Localizer["WarningButton"]
+
@Localizer["InformationButton"]
+
@Localizer["DarkButton"]
+
@Localizer["HighlightButton"]
+
@Localizer["LinkButton"]
+
@Localizer["NoneButtonColor"]
+
+
+
+
+
+
+
+
+ @Localizer["PrimaryButton"]
+
+
+ @Localizer["SecondaryButton"]
+
+
+ @Localizer["SuccessButton"]
+
+
+ @Localizer["DangerButton"]
+
+
+ @Localizer["WarningButton"]
+
+
+
+
+
+
+
+
+
+
+
@Localizer["PrimaryButton"]
+
@Localizer["SecondaryButton"]
+
@Localizer["SuccessButton"]
+
@Localizer["DangerButton"]
+
@Localizer["WarningButton"]
+
@Localizer["InformationButton"]
+
@Localizer["DarkButton"]
+
@Localizer["HighlightButton"]
+
@Localizer["LinkButton"]
+
+
+
+
+
+
@Localizer["ExtraSmallButton"]
+
@Localizer["SmallButton"]
+
@Localizer["NormalButton"]
+
@Localizer["MediumButton"]
+
@Localizer["LargeButton"]
+
@Localizer["ExtraLargeButton"]
+
@Localizer["ButtonExtraExtraLargeText"]
+
@Localizer["BlockButton"]
+
+
+
+
+
+
@Localizer["PrimaryButton"]
+
@Localizer["SecondaryButton"]
+
@Localizer["SuccessButton"]
+
@Localizer["DangerButton"]
+
@Localizer["WarningButton"]
+
@Localizer["InformationButton"]
+
@Localizer["DarkButton"]
+
@Localizer["HighlightButton"]
+
@Localizer["LinkButton"]
+
+
+ @((MarkupString)Localizer["Description1"].Value)
+ @((MarkupString)Localizer["Description2"].Value)
+
+ @Localizer["SubTitle"]
+
+ @((MarkupString)Localizer["IsDisabledTip"].Value)
+ @((MarkupString)Localizer["SetDisableTip"].Value)
+
+
+
+
+
+
+ @Localizer["ButtonOne"]
+ @Localizer["ButtonTwo"]
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ @ButtonText
+
+
+
+
+
+ @((MarkupString)Localizer["ButtonAsyncDescription"].Value)
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/BootstrapBlazor.Server/Components/Samples/Buttons.razor.cs b/src/BootstrapBlazor.Server/Components/Samples/Buttons.razor.cs
new file mode 100644
index 000000000..0d1da5ba5
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Samples/Buttons.razor.cs
@@ -0,0 +1,197 @@
+// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+// Website: https://www.blazor.zone or https://argozhang.github.io/
+
+using Microsoft.AspNetCore.Components.Web;
+
+namespace BootstrapBlazor.Server.Components.Samples;
+
+///
+///
+///
+public sealed partial class Buttons
+{
+ [NotNull]
+ private ConsoleLogger? NormalLogger { get; set; }
+
+ ///
+ ///
+ ///
+ ///
+ private void ButtonClick(MouseEventArgs e)
+ {
+ NormalLogger.Log($"Button Clicked");
+ }
+
+ private bool IsDisable { get; set; }
+
+ [NotNull]
+ private Button? ButtonDisableDemo { get; set; }
+
+ private void ClickButton1()
+ {
+ IsDisable = !IsDisable;
+ StateHasChanged();
+ }
+
+ private Task ClickButton2()
+ {
+ IsDisable = false;
+ ButtonDisableDemo.SetDisable(false);
+ return Task.CompletedTask;
+ }
+
+ private string ButtonText { get; set; } = "";
+
+ private Task ClickButtonShowText(string text)
+ {
+ ButtonText = text;
+ StateHasChanged();
+ return Task.CompletedTask;
+ }
+
+ private static Task ClickAsyncButton() => Task.Delay(5000);
+
+ ///
+ /// 获得事件方法
+ ///
+ ///
+ private IEnumerable GetEvents() => new EventItem[]
+ {
+ new()
+ {
+ Name = "OnClick",
+ Description = Localizer["EventDesc1"],
+ Type ="EventCallback"
+ },
+ new()
+ {
+ Name = "OnClickWithoutRender",
+ Description = Localizer["EventDesc2"],
+ Type ="Func"
+ }
+ };
+
+ ///
+ /// 获得属性方法
+ ///
+ ///
+ private IEnumerable GetAttributes() => new AttributeItem[]
+ {
+ new()
+ {
+ Name = "Color",
+ Description = Localizer["Att1"],
+ Type = "Color",
+ ValueList = "None / Active / Primary / Secondary / Success / Danger / Warning / Info / Light / Dark / Link",
+ DefaultValue = "Primary"
+ },
+ new()
+ {
+ Name = "Icon",
+ Description = Localizer["Att2"],
+ Type = "string",
+ ValueList = "",
+ DefaultValue = ""
+ },
+ new()
+ {
+ Name = "LoadingIcon",
+ Description = Localizer["Att3"],
+ Type = "string",
+ ValueList = "",
+ DefaultValue = "fa-fw fa-spin fa-solid fa-spinner"
+ },
+ new()
+ {
+ Name = "Text",
+ Description = Localizer["Att4"],
+ Type = "string",
+ ValueList = "",
+ DefaultValue = ""
+ },
+ new()
+ {
+ Name = "Size",
+ Description = Localizer["Att5"],
+ Type = "Size",
+ ValueList = "None / ExtraSmall / Small / Medium / Large / ExtraLarge",
+ DefaultValue = "None"
+ },
+ new()
+ {
+ Name = "Class",
+ Description = Localizer["Att6"],
+ Type = "string",
+ ValueList = " — ",
+ DefaultValue = " — "
+ },
+ new()
+ {
+ Name = "IsBlock",
+ Description = Localizer["Att7"],
+ Type = "boolean",
+ ValueList = " — ",
+ DefaultValue = "false"
+ },
+ new()
+ {
+ Name = "IsDisabled",
+ Description = Localizer["Att8"],
+ Type = "boolean",
+ ValueList = " — ",
+ DefaultValue = "false"
+ },
+ new()
+ {
+ Name = "IsOutline",
+ Description = Localizer["Att9"],
+ Type = "boolean",
+ ValueList = " — ",
+ DefaultValue = "false"
+ },
+ new()
+ {
+ Name = "IsAsync",
+ Description = Localizer["Att10"],
+ Type = "boolean",
+ ValueList = " — ",
+ DefaultValue = "false"
+ },
+ new()
+ {
+ Name = "ChildContent",
+ Description = Localizer["Att11"],
+ Type = "RenderFragment",
+ ValueList = " — ",
+ DefaultValue = " — "
+ },
+ new()
+ {
+ Name = "ButtonStyle",
+ Description = Localizer["Att12"],
+ Type = "ButtonStyle",
+ ValueList = "None / Circle / Round",
+ DefaultValue = "None"
+ },
+ new()
+ {
+ Name = "ButtonType",
+ Description = Localizer["Att13"],
+ Type = "ButtonType",
+ ValueList = "Button / Submit / Reset",
+ DefaultValue = "Button"
+ }
+ };
+
+ private IEnumerable GetMethods() => new MethodItem[]
+ {
+ new()
+ {
+ Name = "SetDisable",
+ Description = Localizer["MethodDesc1"],
+ Parameters = "disable",
+ ReturnValue = " — "
+ }
+ };
+}
diff --git a/src/BootstrapBlazor.Server/Components/Samples/Calendars.razor b/src/BootstrapBlazor.Server/Components/Samples/Calendars.razor
new file mode 100644
index 000000000..8bd95712b
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Samples/Calendars.razor
@@ -0,0 +1,126 @@
+@page "/calendar"
+@inject IStringLocalizer Localizer
+
+@Localizer["Title"]
+
+@Localizer["SubTitle"]
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@context.CellValue.Day
+
+
+
+
+
+
+
+
+
+
+
+ @((MarkupString)Localizer["AppText"].Value)
+
+
+ @Localizer["None"]
+ @Localizer["Chinese"]
+ @Localizer["Math"]
+ @Localizer["Chinese"]
+ @Localizer["Math"]
+ @Localizer["English"]
+ @Localizer["None"]
+
+
+ @Localizer["None"]
+ @Localizer["Math"]
+ @Localizer["English"]
+ @Localizer["Math"]
+ @Localizer["English"]
+ @Localizer["None"]
+
+
+ @Localizer["None"]
+ @Localizer["Math"]
+ @Localizer["Math"]
+ @Localizer["English"]
+ @Localizer["None"]
+
+
+ @Localizer["None"]
+ @Localizer["Math"]
+ @Localizer["Math"]
+ @Localizer["English"]
+ @Localizer["None"]
+
+
+ 午休
+
+
+ @Localizer["None"]
+ @Localizer["Math"]
+ @Localizer["Chinese"]
+ @Localizer["English"]
+ @Localizer["Math"]
+ @Localizer["English"]
+ @Localizer["None"]
+
+
+ @Localizer["None"]
+ @Localizer["Study"]
+ @Localizer["Study"]
+ @Localizer["Study"]
+ @Localizer["Study"]
+ @Localizer["Study"]
+ @Localizer["None"]
+
+
+ @Localizer["None"]
+ @Localizer["Study"]
+ @Localizer["Study"]
+ @Localizer["Study"]
+ @Localizer["Study"]
+ @Localizer["Study"]
+ @Localizer["None"]
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@Localizer["CellTemplateDemoSummary"]
+
+ @foreach (var crew in CalendarDemoDataHelper.Crews)
+ {
+
+
@crew.Name
+
@GetSumByName(crew.Name)
+
+ }
+
+
+
+
+
+
+
diff --git a/src/BootstrapBlazor.Server/Components/Samples/Calendars.razor.cs b/src/BootstrapBlazor.Server/Components/Samples/Calendars.razor.cs
new file mode 100644
index 000000000..1c17adc21
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Samples/Calendars.razor.cs
@@ -0,0 +1,79 @@
+// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+// Website: https://www.blazor.zone or https://argozhang.github.io/
+
+using System.Collections.Concurrent;
+
+namespace BootstrapBlazor.Server.Components.Samples;
+
+///
+///
+///
+public sealed partial class Calendars
+{
+ [NotNull]
+ private ConsoleLogger? NormalLogger { get; set; }
+
+ private void OnValueChanged(DateTime ts)
+ {
+ NormalLogger.Log($"{ts:yyyy-MM-dd}");
+ }
+
+ private DateTime BindValue { get; set; } = DateTime.Today;
+
+ private static string Formatter(DateTime ts) => ts.ToString("yyyy-MM-dd");
+
+ private ConcurrentDictionary> Data { get; } = new();
+
+ private DateTime CrewInfoValue { get; set; } = DateTime.Today;
+
+ private List GetCrewsByDate(DateTime d) => Data.GetOrAdd(d, CalendarDemoDataHelper.GetCrewsByDate);
+
+ private int GetSumByName(string name) => Data.Where(d => d.Key.Month == CrewInfoValue.Month).Sum(d => d.Value.FirstOrDefault(v => v.Name == name)?.Value ?? 0);
+
+ ///
+ /// 获得事件方法
+ ///
+ ///
+ private IEnumerable GetEvents() => new EventItem[]
+ {
+ new EventItem()
+ {
+ Name = "ValueChanged",
+ Description = Localizer["ValueChanged"],
+ Type ="EventCallback"
+ }
+ };
+
+ ///
+ /// 获得属性方法
+ ///
+ ///
+ private IEnumerable GetAttributes() => new AttributeItem[]
+ {
+ new()
+ {
+ Name = "Value",
+ Description = Localizer["Value"],
+ Type = "DateTime",
+ ValueList = " — ",
+ DefaultValue = " — "
+ },
+ new()
+ {
+ Name = "ChildContent",
+ Description = Localizer["ChildContent"],
+ Type = "RenderFragment",
+ ValueList = " — ",
+ DefaultValue = " — "
+ },
+ new()
+ {
+ Name = "CellTemplate",
+ Description = Localizer["CellTemplate"],
+ Type = "RenderFragment",
+ ValueList = " — ",
+ DefaultValue = " — "
+ }
+ };
+}
diff --git a/src/BootstrapBlazor.Server/Components/Samples/Calendars.razor.css b/src/BootstrapBlazor.Server/Components/Samples/Calendars.razor.css
new file mode 100644
index 000000000..b598187e4
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Samples/Calendars.razor.css
@@ -0,0 +1,36 @@
+.sum .col-12 {
+ display: flex;
+}
+
+ .sum .col-12 > div {
+ margin-right: 1rem;
+ min-width: 2rem;
+ }
+
+.none {
+ color: var(--bb-calendar-cell-disabled-color);
+}
+
+.less {
+ border-radius: var(--bs-border-radius);
+ position: absolute;
+ left: 0;
+ right: 0;
+ top: 0;
+ bottom: 0;
+ margin: 4px;
+ padding: 12px;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+}
+
+.ch {
+ background: #28a745;
+ color: #f8f9fa;
+}
+
+.en {
+ background: #007bff;
+ color: #f8f9fa;
+}
diff --git a/src/BootstrapBlazor.Server/Components/Samples/Cameras.razor b/src/BootstrapBlazor.Server/Components/Samples/Cameras.razor
new file mode 100644
index 000000000..0e1df0ce9
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Samples/Cameras.razor
@@ -0,0 +1,53 @@
+@page "/camera"
+@inject IStringLocalizer Localizer
+
+@Localizer["Title"]
+
+@Localizer["SubTitle"]
+
+@Localizer["Attention"]
+
+
+ @((MarkupString)Localizer["Li1"].Value)
+
+
+
+
+ @Localizer["BasicUsageStep"]
+
+ @Localizer["BasicUsageLi1"]
+ @Localizer["BasicUsageLi2"]
+ @Localizer["BasicUsageLi3"]
+
+
+
+
+
+ @if (ImageUrl != null)
+ {
+
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/BootstrapBlazor.Server/Components/Samples/Cameras.razor.cs b/src/BootstrapBlazor.Server/Components/Samples/Cameras.razor.cs
new file mode 100644
index 000000000..02c02f8ba
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Samples/Cameras.razor.cs
@@ -0,0 +1,257 @@
+// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+// Website: https://www.blazor.zone or https://argozhang.github.io/
+
+namespace BootstrapBlazor.Server.Components.Samples;
+
+///
+///
+///
+public sealed partial class Cameras
+{
+ private string? ImageUrl { get; set; }
+
+ [NotNull]
+ private ConsoleLogger? Logger { get; set; }
+
+ [NotNull]
+ private string? TraceOnInit { get; set; }
+
+ [NotNull]
+ private string? TraceOnError { get; set; }
+
+ [NotNull]
+ private string? TraceOnStar { get; set; }
+
+ [NotNull]
+ private string? TraceOnClose { get; set; }
+
+ [NotNull]
+ private string? TraceOnCapture { get; set; }
+
+ private string? PlayText { get; set; }
+
+ private string? StopText { get; set; }
+
+ private string? PreviewText { get; set; }
+
+ private string? SaveText { get; set; }
+
+ private bool PlayDisabled { get; set; } = true;
+
+ private bool StopDisabled { get; set; } = true;
+
+ private bool CaptureDisabled { get; set; } = true;
+
+ private List Devices { get; } = new();
+
+ private string? DeviceId { get; set; }
+
+ private string? DeviceLabel { get; set; }
+
+ private string? PlaceHolderString { get; set; }
+
+ [NotNull]
+ private Camera? Camera { get; set; }
+
+ private string? ImageContentData { get; set; }
+
+ private string? ImageStyleString => CssBuilder.Default("width: 320px; height: 240px; border-radius: var(--bs-border-radius);")
+ .AddClass("display: none;", string.IsNullOrEmpty(ImageContentData))
+ .Build();
+
+ ///
+ /// OnInitialized 方法
+ ///
+ protected override void OnInitialized()
+ {
+ base.OnInitialized();
+
+ TraceOnInit = Localizer[nameof(TraceOnInit)];
+ TraceOnError = Localizer[nameof(TraceOnError)];
+ TraceOnStar = Localizer[nameof(TraceOnStar)];
+ TraceOnClose = Localizer[nameof(TraceOnClose)];
+ TraceOnCapture = Localizer[nameof(TraceOnCapture)];
+ DeviceLabel = Localizer["DeviceLabel"];
+ PlaceHolderString = Localizer["InitDevicesString"];
+ PlayText = Localizer["PlayText"];
+ StopText = Localizer["StopText"];
+ PreviewText = Localizer["PreviewText"];
+ SaveText = Localizer["SaveText"];
+ }
+
+ private Task OnInit(List devices)
+ {
+ if (devices.Any())
+ {
+ Devices.AddRange(devices.Select(d => new SelectedItem(d.DeviceId, d.Label)));
+ PlayDisabled = false;
+ }
+ else
+ {
+ PlaceHolderString = Localizer["NotFoundDevicesString"];
+ }
+
+ foreach (var item in devices)
+ {
+ Logger.Log($"{TraceOnInit} {item.Label}-{item.DeviceId}");
+ }
+
+ StateHasChanged();
+ return Task.CompletedTask;
+ }
+
+ private async Task OnClickOpen()
+ {
+ await Camera.Open();
+ PlayDisabled = true;
+ StopDisabled = false;
+ CaptureDisabled = false;
+ }
+
+ private async Task OnClickClose()
+ {
+ await Camera.Close();
+ ImageContentData = null;
+ PlayDisabled = false;
+ StopDisabled = true;
+ CaptureDisabled = true;
+ }
+
+ private async Task OnClickPreview()
+ {
+ ImageContentData = null;
+ var stream = await Camera.Capture();
+ if (stream != null)
+ {
+ var reader = new StreamReader(stream);
+ ImageContentData = await reader.ReadToEndAsync();
+ reader.Close();
+ }
+ }
+
+ private Task OnClickSave() => Camera.SaveAndDownload($"capture_{DateTime.Now:hhmmss}.png");
+
+ private Task OnApply(int width, int height) => Camera.Resize(width, height);
+
+ private Task OnError(string err)
+ {
+ PlayDisabled = false;
+ StopDisabled = true;
+ CaptureDisabled = true;
+ PlaceHolderString = Localizer["NotFoundDevicesString"];
+ Logger.Log($"{TraceOnError} {err}");
+
+ StateHasChanged();
+ return Task.CompletedTask;
+ }
+
+ private Task OnOpen()
+ {
+ ImageUrl = null;
+ Logger.Log(TraceOnStar);
+ return Task.CompletedTask;
+ }
+
+ private Task OnClose()
+ {
+ Logger.Log(TraceOnClose);
+ return Task.CompletedTask;
+ }
+
+ ///
+ /// 获得属性方法
+ ///
+ ///
+ private IEnumerable GetAttributes() => new AttributeItem[]
+ {
+ new()
+ {
+ Name = nameof(BootstrapBlazor.Components.Camera.VideoWidth),
+ Description = Localizer["VideoWidth"],
+ Type = "int",
+ ValueList = " — ",
+ DefaultValue = "320"
+ },
+ new()
+ {
+ Name = nameof(BootstrapBlazor.Components.Camera.VideoHeight),
+ Description = Localizer["VideoHeight"],
+ Type = "int",
+ ValueList = " — ",
+ DefaultValue = "240"
+ },
+ new()
+ {
+ Name = "ShowPreview",
+ Description = Localizer["ShowPreview"],
+ Type = "bool",
+ ValueList = "true|false",
+ DefaultValue = "false"
+ },
+ new()
+ {
+ Name = "AutoStart",
+ Description = Localizer["AutoStart"],
+ Type = "bool",
+ ValueList = "true|false",
+ DefaultValue = "false"
+ },
+ new()
+ {
+ Name = "DeviceLabel",
+ Description = Localizer["DeviceLabel"],
+ Type = "string",
+ ValueList = " — ",
+ DefaultValue = " — "
+ },
+ new()
+ {
+ Name = "OnInit",
+ Description = Localizer["OnInit"],
+ Type = "Func, Task>",
+ ValueList = " — ",
+ DefaultValue = " — "
+ },
+ new()
+ {
+ Name = "OnStart",
+ Description = Localizer["OnStart"],
+ Type = "Func",
+ ValueList = " — ",
+ DefaultValue = " — "
+ },
+ new()
+ {
+ Name = "OnClose",
+ Description = Localizer["OnClose"],
+ Type = "Func",
+ ValueList = " — ",
+ DefaultValue = " — "
+ },
+ new()
+ {
+ Name = "OnCapture",
+ Description = Localizer["OnCapture"],
+ Type = "Func",
+ ValueList = " — ",
+ DefaultValue = " — "
+ },
+ new()
+ {
+ Name = nameof(BootstrapBlazor.Components.Camera.CaptureJpeg),
+ Description = Localizer["CaptureJpeg"],
+ Type = "bool",
+ ValueList = " — ",
+ DefaultValue = "false"
+ },
+ new()
+ {
+ Name = nameof(BootstrapBlazor.Components.Camera.Quality),
+ Description = Localizer["Quality"],
+ Type = "double",
+ ValueList = " — ",
+ DefaultValue = " 0.9d"
+ }
+ };
+}
diff --git a/src/BootstrapBlazor.Server/Components/Samples/Captchas.razor b/src/BootstrapBlazor.Server/Components/Samples/Captchas.razor
new file mode 100644
index 000000000..b9586943c
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Samples/Captchas.razor
@@ -0,0 +1,24 @@
+@page "/captcha"
+@inject IStringLocalizer Localizer
+
+@Localizer["Title"]
+
+@Localizer["SubTitle"]
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/BootstrapBlazor.Server/Components/Samples/Captchas.razor.cs b/src/BootstrapBlazor.Server/Components/Samples/Captchas.razor.cs
new file mode 100644
index 000000000..ba1165cc4
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Samples/Captchas.razor.cs
@@ -0,0 +1,170 @@
+// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+// Website: https://www.blazor.zone or https://argozhang.github.io/
+
+namespace BootstrapBlazor.Server.Components.Samples;
+
+///
+///
+///
+public sealed partial class Captchas
+{
+ private static Random ImageRandomer { get; set; } = new Random();
+
+ ///
+ /// GetImageName
+ ///
+ ///
+ private string GetImageName()
+ {
+ var index = Convert.ToInt32(ImageRandomer.Next(0, 8) / 1.0);
+ var imageName = Path.GetFileNameWithoutExtension(ImagesName);
+ var extendName = Path.GetExtension(ImagesName);
+ var fileName = $"{imageName}{index}{extendName}";
+ return Path.Combine(ImagesPath, fileName);
+ }
+
+ ///
+ /// 获得/设置 图床路径 默认值为 Pic.jpg 通过设置 Max 取 Pic0.jpg ... Pic8.jpg
+ ///
+ public string ImagesName { get; set; } = "Pic.jpg";
+
+ ///
+ /// 获得/设置 图床路径 默认值为 images
+ ///
+ public string ImagesPath { get; set; } = "./images";
+
+ [NotNull]
+ private Captcha? NormalCaptcha { get; set; }
+
+ [NotNull]
+ private ConsoleLogger? NormalLogger { get; set; }
+
+ private async Task OnValidAsync(bool ret)
+ {
+ var result = ret ? "成功" : "失败";
+ NormalLogger.Log($"验证码结果 -> {result}");
+ if (ret)
+ {
+ await Task.Delay(1000);
+ await NormalCaptcha.Reset();
+ }
+ }
+
+ ///
+ /// 获得属性方法
+ ///
+ ///
+ private IEnumerable GetAttributes() => new AttributeItem[]
+ {
+ new()
+ {
+ Name = "ImagesPath",
+ Description = Localizer["ImagesPath"],
+ Type = "string",
+ ValueList = " — ",
+ DefaultValue = "images"
+ },
+ new()
+ {
+ Name = "ImagesName",
+ Description = Localizer["ImagesName"],
+ Type = "string",
+ ValueList = " — ",
+ DefaultValue = "Pic.jpg"
+ },
+ new()
+ {
+ Name = "HeaderText",
+ Description = Localizer["HeaderText"],
+ Type = "string",
+ ValueList = " — ",
+ DefaultValue = Localizer["HeaderTextDefaultValue"]
+ },
+ new()
+ {
+ Name = "BarText",
+ Description = Localizer["BarText"],
+ Type = "string",
+ ValueList = " — ",
+ DefaultValue = Localizer["BarTextDefaultValue"]
+ },
+ new()
+ {
+ Name = "FailedText",
+ Description = Localizer["FailedText"],
+ Type = "string",
+ ValueList = " — ",
+ DefaultValue = Localizer["FailedTextDefaultValue"]
+ },
+ new()
+ {
+ Name = "LoadText",
+ Description = Localizer["LoadText"],
+ Type = "string",
+ ValueList = " — ",
+ DefaultValue = Localizer["LoadTextDefaultValue"]
+ },
+ new()
+ {
+ Name = "TryText",
+ Description = Localizer["TryText"],
+ Type = "string",
+ ValueList = " — ",
+ DefaultValue = Localizer["TryTextDefaultValue"]
+ },
+ new()
+ {
+ Name = "Offset",
+ Description = Localizer["Offset"],
+ Type = "int",
+ ValueList = " — ",
+ DefaultValue = "5"
+ },
+ new()
+ {
+ Name = "Width",
+ Description = Localizer["Width"],
+ Type = "int",
+ ValueList = " — ",
+ DefaultValue = "280"
+ },
+ new()
+ {
+ Name = "Height",
+ Description = Localizer["Height"],
+ Type = "int",
+ ValueList = " — ",
+ DefaultValue = "155"
+ }
+ };
+
+ ///
+ /// 获得事件方法
+ ///
+ ///
+ private IEnumerable GetEvents() => new EventItem[]
+ {
+ new()
+ {
+ Name = "OnValid",
+ Description = Localizer["OnValid"],
+ Type ="Action"
+ }
+ };
+
+ ///
+ /// 获得事件方法
+ ///
+ ///
+ private IEnumerable GetMethods() => new MethodItem[]
+ {
+ new()
+ {
+ Name = "GetImageName",
+ Description = Localizer["GetImageName"],
+ Parameters =" — ",
+ ReturnValue = "string"
+ }
+ };
+}
diff --git a/src/BootstrapBlazor.Server/Components/Samples/Cards.razor b/src/BootstrapBlazor.Server/Components/Samples/Cards.razor
new file mode 100644
index 000000000..f8861bfdb
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Samples/Cards.razor
@@ -0,0 +1,225 @@
+@page "/card"
+@inject IStringLocalizer Localizer
+
+@Localizer["Title"]
+
+@Localizer["SubTitle"]
+
+
+
+
+ Card title
+ Some quick example text to build on the card title and make up the bulk of the card's content.
+ Go somewhere
+
+
+
+
+
+
+
+ Featured
+
+
+ Special title treatment
+ With supporting text below as a natural lead-in to additional content.
+ Go somewhere
+
+
+ 2 days ago
+
+
+
+
+
+
+
+ Featured
+
+
+ Special title treatment
+ With supporting text below as a natural lead-in to additional content.
+ Go somewhere
+
+
+ 2 days ago
+
+
+
+
+
+
+
+
+
+ Header
+
+
+ Primary card title
+ Some quick example text to build on the card title and make up the bulk of the card's content.
+
+
+
+
+
+
+ Header
+
+
+ Secondary card title
+ Some quick example text to build on the card title and make up the bulk of the card's content.
+
+
+
+
+
+
+ Header
+
+
+ Success card title
+ Some quick example text to build on the card title and make up the bulk of the card's content.
+
+
+
+
+
+
+ Header
+
+
+ Warning card title
+ Some quick example text to build on the card title and make up the bulk of the card's content.
+
+
+
+
+
+
+ Header
+
+
+ Danger card title
+ Some quick example text to build on the card title and make up the bulk of the card's content.
+
+
+
+
+
+
+ Header
+
+
+ Info card title
+ Some quick example text to build on the card title and make up the bulk of the card's content.
+
+
+
+
+
+
+ Header
+
+
+ Dark card title
+ Some quick example text to build on the card title and make up the bulk of the card's content.
+
+
+
+
+
+
+
+ @((MarkupString)Localizer["CollapsibleIntroDesc"].Value)
+
+
+ @Localizer["CollapsibleBody"]
+
+
+
+
+ @Localizer["CollapsibleHeaderTemplate"]
+
+
+
+
+
+
+
+
+
+
+ @Localizer["CollapsibleBody"]
+
+
+
+
+ @Localizer["CollapsibleBody"]
+
+
+
+
+
+
+
+ @Localizer["CollapsibleHeaderTemplate"]
+
+
+
+
+
+
+
+
+
+
+ @Localizer["CollapsibleHeaderTemplateTitle"]
+
+
+
+
+
+
+
+ @Localizer["ShadowBody"]
+
+
+
+
+
+
+
+ @Localizer["CollapsibleHeaderTemplate"]
+
+
+
+
+
+
+
+
+
+
+ @Localizer["CollapsibleBody"]
+
+
+
+
+
+ @Localizer["CollapsibleHeaderTemplate"]
+
+
+
+
+
+
+
+
+
+
+ @Localizer["CollapsibleBody"]
+
+
+
+
+
diff --git a/src/BootstrapBlazor.Server/Components/Samples/Cards.razor.cs b/src/BootstrapBlazor.Server/Components/Samples/Cards.razor.cs
new file mode 100644
index 000000000..f6258d58a
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Samples/Cards.razor.cs
@@ -0,0 +1,92 @@
+// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+// Website: https://www.blazor.zone or https://argozhang.github.io/
+
+namespace BootstrapBlazor.Server.Components.Samples;
+
+///
+/// Card展示组件
+///
+public sealed partial class Cards
+{
+ ///
+ /// Card属性
+ ///
+ ///
+ private IEnumerable GetAttributes() => new AttributeItem[]
+ {
+ new()
+ {
+ Name = "BodyTemplate",
+ Description = Localizer["BodyTemplate"],
+ Type = "RenderFragment",
+ ValueList = " — ",
+ DefaultValue = " — "
+ },
+ new()
+ {
+ Name = "FooterTemplate",
+ Description = Localizer["FooterTemplate"],
+ Type = "RenderFragment",
+ ValueList = " — ",
+ DefaultValue = " — "
+ },
+ new()
+ {
+ Name = "HeaderTemplate",
+ Description = Localizer["HeaderTemplate"],
+ Type = "RenderFragment",
+ ValueList = " — ",
+ DefaultValue = " — "
+ },
+ new()
+ {
+ Name = "Class",
+ Description = Localizer["Class"],
+ Type = "string",
+ ValueList = " — ",
+ DefaultValue = " — "
+ },
+ new()
+ {
+ Name = "Color",
+ Description = Localizer["Color"],
+ Type = "Color",
+ ValueList = "None / Primary / Secondary / Success / Danger / Warning / Info / Light / Dark",
+ DefaultValue = " — "
+ },
+ new()
+ {
+ Name = "IsCenter",
+ Description = Localizer["IsCenter"],
+ Type = "boolean",
+ ValueList = "true / false",
+ DefaultValue = "false"
+ },
+ new()
+ {
+ Name = "IsCollapsible",
+ Description = Localizer["IsCollapsible"],
+ Type = "boolean",
+ ValueList = "true / false",
+ DefaultValue = "false"
+ },
+ new()
+ {
+ Name = nameof(Card.Collapsed),
+ Description = Localizer["Collapsed"],
+ Type = "boolean",
+ ValueList = "true / false",
+ DefaultValue = "false"
+ },
+ new()
+ {
+ Name = "IsShadow",
+ Description = Localizer["IsShadow"],
+ Type = "boolean",
+ ValueList = "true / false",
+ DefaultValue = "false"
+ }
+ };
+}
+
diff --git a/src/BootstrapBlazor.Server/Components/Samples/Carousels.razor b/src/BootstrapBlazor.Server/Components/Samples/Carousels.razor
new file mode 100644
index 000000000..79813c41d
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Samples/Carousels.razor
@@ -0,0 +1,210 @@
+@page "/carousel"
+@inject IStringLocalizer Localizer
+
+@Localizer["Title"]
+
+@Localizer["SubTitle"]
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ First slide label
+ Pic0.jpg
+
+
+
+
+
+
+
+ Second slide label
+ Pic1.jpg
+
+
+
+
+
+
+
+ Third slide label
+ Pic2.jpg
+
+
+
+
+
+
+
+
+
+ @((MarkupString)Localizer["CaptionClassP1"].Value)
+
+
+
+ First slide label
+ Pic0.jpg
+
+
+
+
+
+
+
+ Second slide label
+ Pic1.jpg
+
+
+
+
+
+
+
+ Third slide label
+ Pic2.jpg
+
+
+
+
+
+
+
+
+
+ CarouselOnClick
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Sales champion
+
www.blazor.zone
+
+
+
+ Carousel Item
+
+
+
+
+
Sales champion
+
www.blazor.zone
+
+
+
+ Carousel Item
+
+
+
+
+
Sales champion
+
www.blazor.zone
+
+
+
+ Carousel Item
+
+
+
+
+
+
+
+
+
Sales champion
+
www.blazor.zone
+
+
+
+ Carousel Item
+
+
+
+
+
Sales champion
+
www.blazor.zone
+
+
+
+ Carousel Item
+
+
+
+
+
Sales champion
+
www.blazor.zone
+
+
+
+ Carousel Item
+
+
+
+
+
+
+
+
diff --git a/src/BootstrapBlazor.Server/Components/Samples/Carousels.razor.cs b/src/BootstrapBlazor.Server/Components/Samples/Carousels.razor.cs
new file mode 100644
index 000000000..8328f4939
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Samples/Carousels.razor.cs
@@ -0,0 +1,91 @@
+// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+// Website: https://www.blazor.zone or https://argozhang.github.io/
+
+namespace BootstrapBlazor.Server.Components.Samples;
+
+///
+/// Carousels
+///
+public sealed partial class Carousels
+{
+ [NotNull]
+ private ConsoleLogger? OnClickLogger { get; set; }
+
+ ///
+ /// Images
+ ///
+ private static List Images => new()
+ {
+ "./images/Pic0.jpg",
+ "./images/Pic1.jpg",
+ "./images/Pic2.jpg"
+ };
+
+ ///
+ /// OnClick
+ ///
+ ///
+ ///
+ private Task OnClick(string imageUrl)
+ {
+ OnClickLogger.Log($"Image Clicked: {imageUrl}");
+ return Task.CompletedTask;
+ }
+
+ ///
+ /// 获得属性方法
+ ///
+ ///
+ private IEnumerable GetAttributes() => new AttributeItem[]
+ {
+ new()
+ {
+ Name = "Images",
+ Description = Localizer["Images"],
+ Type = "IEnumerable",
+ ValueList = "—",
+ DefaultValue = "—"
+ },
+ new()
+ {
+ Name = "IsFade",
+ Description = Localizer["IsFade"],
+ Type = "boolean",
+ ValueList = " — ",
+ DefaultValue = "false"
+ },
+ new()
+ {
+ Name = "HoverPause",
+ Description = Localizer["HoverPause"],
+ Type = "bool",
+ ValueList = "true|false",
+ DefaultValue = "true"
+ },
+ new()
+ {
+ Name = "Width",
+ Description = Localizer["Width"],
+ Type = "int",
+ ValueList = " — ",
+ DefaultValue = "—"
+ },
+ new()
+ {
+ Name = "OnClick",
+ Description = Localizer["OnClick"],
+ Type = "Func",
+ ValueList = " — ",
+ DefaultValue = " — "
+ },
+ new()
+ {
+ Name = "PlayMode",
+ Description = Localizer["PlayMode"],
+ Type = "CarouselPlayMode",
+ ValueList = "AutoPlayOnload|AutoPlayAfterManually|Manually",
+ DefaultValue = "AutoPlayOnload"
+ }
+ };
+}
diff --git a/src/BootstrapBlazor.Server/Components/Samples/Carousels.razor.css b/src/BootstrapBlazor.Server/Components/Samples/Carousels.razor.css
new file mode 100644
index 000000000..deb39ec5b
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Samples/Carousels.razor.css
@@ -0,0 +1,28 @@
+.carousel-item-demo2 {
+ display: flex;
+}
+
+ .carousel-item-demo2 .demo-item {
+ background-color: #e9ecef;
+ border-radius: var(--bs-border-radius);
+ padding: 1rem 2rem;
+ }
+
+ .carousel-item-demo2 .demo-item:not(:last-child) {
+ margin-right: 1rem;
+ }
+
+ .carousel-item-demo2 .demo-item img {
+ border-radius: var(--bs-border-radius);
+ margin: 1rem 0;
+ height: auto;
+ }
+
+ .carousel-item-demo2 .demo-item .top,
+ .carousel-item-demo2 .demo-item .bottom {
+ text-align: center;
+ }
+
+ .carousel-item-demo2 .demo-item .top > div:first-child {
+ font-size: 1.5rem;
+ }
diff --git a/src/BootstrapBlazor.Server/Components/Samples/Cascaders.razor b/src/BootstrapBlazor.Server/Components/Samples/Cascaders.razor
new file mode 100644
index 000000000..a23303005
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Samples/Cascaders.razor
@@ -0,0 +1,127 @@
+@page "/cascader"
+@inject IStringLocalizer Localizer
+
+@Localizer["Title"]
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ @((MarkupString)Localizer["Description"].Value)
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/BootstrapBlazor.Server/Components/Samples/Cascaders.razor.cs b/src/BootstrapBlazor.Server/Components/Samples/Cascaders.razor.cs
new file mode 100644
index 000000000..c7b070fdb
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Samples/Cascaders.razor.cs
@@ -0,0 +1,150 @@
+// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+// Website: https://www.blazor.zone or https://argozhang.github.io/
+
+namespace BootstrapBlazor.Server.Components.Samples;
+
+///
+/// Cascaders
+///
+public sealed partial class Cascaders
+{
+ ///
+ /// Foo 类为Demo测试用,如有需要请自行下载源码查阅
+ /// Foo class is used for Demo test, please download the source code if necessary
+ /// https://gitee.com/LongbowEnterprise/BootstrapBlazor/blob/main/src/BootstrapBlazor.Server/Data/Foo.cs
+ ///
+ private Foo Model { get; set; } = new Foo();
+
+ private Guid CurrentGuid { get; set; }
+
+ private readonly IEnumerable _guidItems = new CascaderItem[]
+ {
+ new CascaderItem(Guid.NewGuid().ToString(), "Guid1"),
+ new CascaderItem(Guid.NewGuid().ToString(), "Guid2")
+ };
+
+ private string Value { get; set; } = "Shanghai";
+
+ [NotNull]
+ private ConsoleLogger? NormalLogger { get; set; }
+
+ private List _items = new List();
+
+ ///
+ /// 下拉选项改变时调用此方法
+ ///
+ ///
+ private Task OnItemChanged(CascaderItem[] items)
+ {
+ NormalLogger.Log($"SelectedItem Text: {items[^1].Text} Value: {items[^1].Value} Selected");
+ return Task.CompletedTask;
+ }
+
+ ///
+ /// OnInitialized
+ ///
+ protected override void OnInitialized()
+ {
+ Value = Localizer["item1"];
+
+ _items = new List
+ {
+ new CascaderItem(Localizer["item1"], Localizer["item1"]),
+ new CascaderItem(Localizer["item2"], Localizer["item2"]),
+ new CascaderItem(Localizer["item3"], Localizer["item3"]),
+ };
+
+ _items[0].AddItem(new CascaderItem("item1_child1", Localizer["item1_child1"]));
+ _items[0].AddItem(new CascaderItem("item1_child2", Localizer["item1_child2"]));
+ _items[0].AddItem(new CascaderItem("item1_child3", Localizer["item1_child3"]));
+ _items[0].AddItem(new CascaderItem("item1_child4", Localizer["item1_child4"]));
+
+ _items[0].Items.ElementAt(0).AddItem(new CascaderItem("item1_child1_child", Localizer["item1_child1_child"]));
+
+ _items[1].AddItem(new CascaderItem("item2_child1", Localizer["item2_child1"]));
+ _items[1].AddItem(new CascaderItem("item2_child2", Localizer["item2_child2"]));
+ _items[1].AddItem(new CascaderItem("item2_child3", Localizer["item2_child3"]));
+
+ _items[2].AddItem(new CascaderItem("item3_child1", Localizer["item3_child1"]));
+ _items[2].AddItem(new CascaderItem("item3_child2", Localizer["item3_child2"]));
+ }
+
+ ///
+ /// 获得事件方法
+ ///
+ ///
+ private IEnumerable GetEvents() => new EventItem[]
+ {
+ new EventItem()
+ {
+ Name = nameof(Cascader.OnSelectedItemChanged),
+ Description = Localizer["Event1"],
+ Type ="Func"
+ }
+ };
+
+ ///
+ /// 获得属性方法
+ ///
+ ///
+ private IEnumerable GetAttributes() => new AttributeItem[]
+ {
+ new()
+ {
+ Name = "ShowLabel",
+ Description = Localizer["Att1"],
+ Type = "bool",
+ ValueList = "true|false",
+ DefaultValue = "true"
+ },
+ new()
+ {
+ Name = "DisplayText",
+ Description = Localizer["Att2"],
+ Type = "string",
+ ValueList = " — ",
+ DefaultValue = " — "
+ },
+ new()
+ {
+ Name = "PlaceHolder",
+ Description = Localizer["Att3"],
+ Type = "string",
+ ValueList = " — ",
+ DefaultValue = Localizer["Att3Default"]!
+ },
+ new()
+ {
+ Name = "Class",
+ Description = Localizer["Att4"],
+ Type = "string",
+ ValueList = " — ",
+ DefaultValue = " — "
+ },
+ new()
+ {
+ Name = "Color",
+ Description = Localizer["Att5"],
+ Type = "Color",
+ ValueList = "Primary / Secondary / Success / Danger / Warning / Info / Dark",
+ DefaultValue = "Primary"
+ },
+ new()
+ {
+ Name = "IsDisabled",
+ Description = Localizer["Att6"],
+ Type = "boolean",
+ ValueList = "true / false",
+ DefaultValue = "false"
+ },
+ new()
+ {
+ Name = "Items",
+ Description = Localizer["Att7"],
+ Type = "IEnumerable",
+ ValueList = " — ",
+ DefaultValue = " — "
+ }
+ };
+}
diff --git a/src/BootstrapBlazor.Server/Components/Samples/Charts/Bar.razor b/src/BootstrapBlazor.Server/Components/Samples/Charts/Bar.razor
new file mode 100644
index 000000000..cbe3e5ad7
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Samples/Charts/Bar.razor
@@ -0,0 +1,49 @@
+@page "/chart/bar"
+@inject IStringLocalizer Localizer
+
+
+
+
+
+
+
+ @Localizer["BarTypeAnimationOn"]
+
+
+
+ @Localizer["BarTypeAnimationOff"]
+
+
+
+
+
+ Utility.RandomData(BarChart)">@Localizer["BarTypeRandomData"]
+ @Localizer["BarTypeReload"]
+ Utility.AddDataSet(BarChart, ref _barDatasetCount)">@Localizer["BarTypeAddDataSet"]
+ Utility.RemoveDataSet(BarChart, ref _barDatasetCount)">@Localizer["BarTypeRemoveDataSet"]
+ Utility.AddData(BarChart, ref _barDataCount)">@Localizer["BarTypeAddData"]
+ Utility.RemoveData(BarChart, ref _barDataCount)">@Localizer["BarTypeRemoveData"]
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/BootstrapBlazor.Server/Components/Samples/Charts/Bar.razor.cs b/src/BootstrapBlazor.Server/Components/Samples/Charts/Bar.razor.cs
new file mode 100644
index 000000000..53deddaf9
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Samples/Charts/Bar.razor.cs
@@ -0,0 +1,180 @@
+// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+// Website: https://www.blazor.zone or https://argozhang.github.io/
+
+namespace BootstrapBlazor.Server.Components.Samples.Charts;
+
+///
+/// Bar 图表示例
+///
+public partial class Bar
+{
+ private Random Randomer { get; } = new Random();
+
+ private int _barDatasetCount = 2;
+ private int _barDataCount = 7;
+
+ private int BarDatasetCount { get; set; } = 2;
+
+ private int BarDataCount { get; set; } = 7;
+
+ [NotNull]
+ private Chart? BarChart { get; set; }
+
+ [NotNull]
+ private ConsoleLogger? Logger { get; set; }
+
+ ///
+ /// OnAfterRender
+ ///
+ ///
+ protected override void OnAfterRender(bool firstRender)
+ {
+ base.OnAfterRender(firstRender);
+
+ if (firstRender)
+ {
+ Logger.Log("Bar loading data ...");
+ }
+ }
+
+ private Task OnAfterInit()
+ {
+ Logger.Log("Bar initialization is complete");
+ return Task.CompletedTask;
+ }
+
+ private Task OnAfterUpdate(ChartAction action) => InvokeAsync(() => Logger.Log($"Bar Figure update data operation completed -- {action}"));
+
+ private Task OnInit(bool stacked, bool setTitle = true)
+ {
+ var ds = new ChartDataSource();
+ if (setTitle)
+ {
+ ds.Options.Title = "Bar Histogram";
+ }
+
+ ds.Options.X.Title = "days";
+ ds.Options.Y.Title = "Numerical value";
+ ds.Options.X.Stacked = stacked;
+ ds.Options.Y.Stacked = stacked;
+ ds.Labels = Enumerable.Range(1, _barDataCount).Select(i => i.ToString());
+ for (var index = 0; index < _barDatasetCount; index++)
+ {
+ ds.Data.Add(new ChartDataset() { Label = $"Set {index}", Data = Enumerable.Range(1, _barDataCount).Select(i => Randomer.Next(20, 37)).Cast() });
+ }
+
+ return Task.FromResult(ds);
+ }
+
+ private CancellationTokenSource _chartCancellationTokenSource = new();
+
+ private Task OnPlayChart()
+ {
+ _chartCancellationTokenSource = new CancellationTokenSource();
+ return Task.Run(async () =>
+ {
+ while (!_chartCancellationTokenSource.IsCancellationRequested)
+ {
+ await Task.Delay(800, _chartCancellationTokenSource.Token);
+ if (!_chartCancellationTokenSource.IsCancellationRequested)
+ {
+ await Utility.RandomData(BarChart);
+ }
+ }
+ });
+ }
+
+ private void OnStopChart() => _chartCancellationTokenSource.Cancel();
+
+ ///
+ /// 强刷控件,重新初始化控件外观
+ ///
+ private Task OnReloadChart()
+ {
+ BarDataCount = Randomer.Next(5, 15);
+ BarChart.Reload();
+ return Task.CompletedTask;
+ }
+
+ private Task OnInitTwoYAxes(bool stacked, bool setTitle = true)
+ {
+ var ds = new ChartDataSource();
+ if (setTitle)
+ {
+ ds.Options.Title = "Bar Histogram";
+ }
+ ds.Options.X.Title = "days";
+ ds.Options.Y.Title = "Numerical value";
+ ds.Options.X.Stacked = stacked;
+ ds.Options.Y.Stacked = stacked;
+ ds.Options.Y2.Title = "Y2 value";
+ ds.Options.Y2.PositionLeft = false;
+
+ ds.Labels = Enumerable.Range(1, BarDataCount).Select(i => i.ToString());
+ var index = 0;
+ ds.Data.Add(new ChartDataset()
+ {
+ Label = $"Y2 Set {index}",
+ IsAxisY2 = index == 0,
+ Data = Enumerable.Range(1, BarDataCount).Select(i => Randomer.Next(20, 7000)).Cast()
+ });
+
+ for (index = 1; index < BarDatasetCount; index++)
+ {
+ ds.Data.Add(new ChartDataset()
+ {
+ Label = $"Y Set {index}",
+ IsAxisY2 = index == 0,
+ Data = Enumerable.Range(1, BarDataCount).Select(i => Randomer.Next(20, 37)).Cast()
+ });
+ }
+ return Task.FromResult(ds);
+ }
+
+ private Task OnInitStack(bool stacked, bool setTitle = true)
+ {
+ var ds = new ChartDataSource();
+ if (setTitle)
+ {
+ ds.Options.Title = "Bar Histogram";
+ }
+ ds.Options.X.Title = "days";
+ ds.Options.Y.Title = "Numerical value";
+ ds.Options.X.Stacked = stacked;
+ ds.Options.Y.Stacked = stacked;
+ ds.Labels = Enumerable.Range(1, BarDataCount).Select(i => i.ToString());
+ for (var index = 0; index < BarDatasetCount; index++)
+ {
+ ds.Data.Add(new ChartDataset()
+ {
+ Label = $"Set {index}",
+ Data = Enumerable.Range(1, BarDataCount).Select(i => Randomer.Next(20, 37)).Cast()
+ });
+ }
+ return Task.FromResult(ds);
+ }
+
+ private Task OnInitAspectRatio(bool stacked, bool setTitle = true)
+ {
+ var ds = new ChartDataSource();
+ if (setTitle)
+ {
+ ds.Options.Title = "Bar Histogram";
+ }
+ ds.Options.X.Title = "days";
+ ds.Options.Y.Title = "Numerical value";
+ ds.Options.X.Stacked = stacked;
+ ds.Options.Y.Stacked = stacked;
+ ds.Labels = Enumerable.Range(1, BarDataCount).Select(i => i.ToString());
+ for (var index = 0; index < BarDatasetCount; index++)
+ {
+ ds.Data.Add(new ChartDataset()
+ {
+ Label = $"Set {index}",
+ Data = Enumerable.Range(1, BarDataCount).Select(i => Randomer.Next(20, 37)).Cast()
+ });
+ }
+ return Task.FromResult(ds);
+ }
+}
diff --git a/src/BootstrapBlazor.Server/Components/Samples/Charts/Bubble.razor b/src/BootstrapBlazor.Server/Components/Samples/Charts/Bubble.razor
new file mode 100644
index 000000000..2efc9b925
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Samples/Charts/Bubble.razor
@@ -0,0 +1,25 @@
+@page "/chart/bubble"
+@inject IStringLocalizer Localizer
+
+
+
+
+
+ Utility.RandomData(BubbleChart)">@Localizer["BubbleNormalRandomData"]
+ @Localizer["BubbleNormalReload"]
+ Utility.AddDataSet(BubbleChart, ref BubbleDatasetCount)">@Localizer["BubbleNormalAddDataSet"]
+ Utility.RemoveDataSet(BubbleChart, ref BubbleDatasetCount)">@Localizer["BubbleNormalRemoveDataset"]
+ Utility.AddData(BubbleChart, ref BubbleDataCount)">@Localizer["BubbleNormalAddData"]
+ Utility.RemoveData(BubbleChart, ref BubbleDataCount)">@Localizer["BubbleNormalRemoveData"]
+
+
+
+
+
+
+
+
diff --git a/src/BootstrapBlazor.Server/Components/Samples/Charts/Bubble.razor.cs b/src/BootstrapBlazor.Server/Components/Samples/Charts/Bubble.razor.cs
new file mode 100644
index 000000000..74f8fc4a8
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Samples/Charts/Bubble.razor.cs
@@ -0,0 +1,104 @@
+// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+// Website: https://www.blazor.zone or https://argozhang.github.io/
+
+namespace BootstrapBlazor.Server.Components.Samples.Charts;
+
+///
+/// Bubble 图例示例
+///
+public partial class Bubble
+{
+ private Random Randomer { get; } = new();
+
+ private int BubbleDatasetCount = 2;
+
+ private int BubbleDataCount = 7;
+
+ [NotNull]
+ private Chart? BubbleChart { get; set; }
+
+ [NotNull]
+ private ConsoleLogger? Logger { get; set; }
+
+ ///
+ ///
+ ///
+ ///
+ protected override void OnAfterRender(bool firstRender)
+ {
+ base.OnAfterRender(firstRender);
+
+ if (firstRender)
+ {
+ Logger.Log("Bubble is loading data ...");
+ }
+ }
+
+ private Task OnAfterInit()
+ {
+ Logger.Log("Bubble is initialized");
+ return Task.CompletedTask;
+ }
+
+ private Task OnAfterUpdate(ChartAction action)
+ {
+ Logger.Log($"Bubble graph update data operation completed -- {action}");
+ return Task.CompletedTask;
+ }
+
+ private Task OnInit()
+ {
+ var ds = new ChartDataSource
+ {
+ Labels = Enumerable.Range(1, BubbleDataCount).Select(i => i.ToString())
+ };
+ ds.Options.Title = "Bubble chart";
+
+ for (var index = 0; index < BubbleDatasetCount; index++)
+ {
+ ds.Data.Add(new ChartDataset()
+ {
+ Label = $"Set {index}",
+ Data = Enumerable.Range(1, BubbleDataCount).Select(i => new
+ {
+ x = Randomer.Next(10, 40),
+ y = Randomer.Next(10, 40),
+ r = Randomer.Next(1, 20)
+ })
+ });
+ }
+ return Task.FromResult(ds);
+ }
+
+ private Task OnReloadChart()
+ {
+ BubbleDataCount = Randomer.Next(5, 15);
+ BubbleChart?.Reload();
+ return Task.CompletedTask;
+ }
+
+ private Task OnInitAspectRatio()
+ {
+ var ds = new ChartDataSource
+ {
+ Labels = Enumerable.Range(1, BubbleDataCount).Select(i => i.ToString())
+ };
+ ds.Options.Title = "Bubble chart";
+
+ for (var index = 0; index < BubbleDatasetCount; index++)
+ {
+ ds.Data.Add(new ChartDataset()
+ {
+ Label = $"Set {index}",
+ Data = Enumerable.Range(1, BubbleDataCount).Select(i => new
+ {
+ x = Randomer.Next(10, 40),
+ y = Randomer.Next(10, 40),
+ r = Randomer.Next(1, 20)
+ })
+ });
+ }
+ return Task.FromResult(ds);
+ }
+}
diff --git a/src/BootstrapBlazor.Server/Components/Samples/Charts/Doughnut.razor b/src/BootstrapBlazor.Server/Components/Samples/Charts/Doughnut.razor
new file mode 100644
index 000000000..a93899b56
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Samples/Charts/Doughnut.razor
@@ -0,0 +1,27 @@
+@page "/chart/doughnut"
+@inject IStringLocalizer Localizer
+
+
+
+
+
+ Utility.RandomData(DoughnutChart)">@Localizer["DoughnutNormalRandomData"]
+ @Localizer["DoughnutNormalReload"]
+ Utility.AddDataSet(DoughnutChart, ref DoughnutDatasetCount)">@Localizer["DoughnutNormalAddDataset"]
+ Utility.RemoveDataSet(DoughnutChart, ref DoughnutDatasetCount)">@Localizer["DoughnutNormalRemoveDataset"]
+ Utility.AddData(DoughnutChart, ref DoughnutDataCount)">@Localizer["DoughnutNormalAddingData"]
+ Utility.RemoveData(DoughnutChart, ref DoughnutDataCount)">@Localizer["DoughnutNormalRemoveData"]
+ @Localizer["DoughnutNormalHalf"]
+
+
+
+
+
+
+
+
+
diff --git a/src/BootstrapBlazor.Server/Components/Samples/Charts/Doughnut.razor.cs b/src/BootstrapBlazor.Server/Components/Samples/Charts/Doughnut.razor.cs
new file mode 100644
index 000000000..ac2e05478
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Samples/Charts/Doughnut.razor.cs
@@ -0,0 +1,99 @@
+// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+// Website: https://www.blazor.zone or https://argozhang.github.io/
+
+namespace BootstrapBlazor.Server.Components.Samples.Charts;
+
+///
+/// Doughnut 图例示例
+///
+public partial class Doughnut
+{
+ private Random Randomer { get; } = new();
+
+ private int DoughnutDatasetCount = 1;
+
+ private int DoughnutDataCount = 5;
+
+ [NotNull]
+ private Chart? DoughnutChart { get; set; }
+
+ [NotNull]
+ private ConsoleLogger? Logger { get; set; }
+
+ ///
+ ///
+ ///
+ ///
+ protected override void OnAfterRender(bool firstRender)
+ {
+ base.OnAfterRender(firstRender);
+
+ if (firstRender)
+ {
+ Logger.Log("Doughnut is loading data ...");
+ }
+ }
+
+ private Task OnAfterInit()
+ {
+ Logger.Log("Doughnut is initialized");
+ return Task.CompletedTask;
+ }
+
+ private Task OnAfterUpdate(ChartAction action)
+ {
+ Logger.Log($"Doughnut graph update data operation completed -- {action}");
+ return Task.CompletedTask;
+ }
+
+ private Task OnInit()
+ {
+ var ds = new ChartDataSource();
+ ds.Options.Title = "Doughnut Donut Chart";
+ ds.Labels = Utility.Colors.Take(DoughnutDataCount);
+ for (var index = 0; index < DoughnutDatasetCount; index++)
+ {
+ ds.Data.Add(new ChartDataset()
+ {
+ Label = $"Set {index}",
+ Data = Enumerable.Range(1, DoughnutDataCount).Select(i => Randomer.Next(20, 37)).Cast()
+ });
+ }
+ return Task.FromResult(ds);
+ }
+
+ private bool IsCircle { get; set; }
+
+ private int Angle { get; set; }
+
+ private async Task ToggleCircle()
+ {
+ IsCircle = !IsCircle;
+ Angle = IsCircle ? 360 : 0;
+ await DoughnutChart.Update(ChartAction.SetAngle);
+ }
+
+ private Task OnReloadChart()
+ {
+ DoughnutDataCount = Randomer.Next(5, 15);
+ DoughnutChart?.Reload();
+ return Task.CompletedTask;
+ }
+
+ private Task OnInitAspectRatio()
+ {
+ var ds = new ChartDataSource();
+ ds.Options.Title = "Doughnut Donut Chart";
+ ds.Labels = Utility.Colors.Take(DoughnutDataCount);
+ for (var index = 0; index < DoughnutDatasetCount; index++)
+ {
+ ds.Data.Add(new ChartDataset()
+ {
+ Label = $"Set {index}",
+ Data = Enumerable.Range(1, DoughnutDataCount).Select(i => Randomer.Next(20, 37)).Cast()
+ });
+ }
+ return Task.FromResult(ds);
+ }
+}
diff --git a/src/BootstrapBlazor.Server/Components/Samples/Charts/Index.razor b/src/BootstrapBlazor.Server/Components/Samples/Charts/Index.razor
new file mode 100644
index 000000000..6ebf9d997
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Samples/Charts/Index.razor
@@ -0,0 +1,14 @@
+@page "/chart/index"
+@layout MainLayout
+@inject IStringLocalizer Localizer
+
+@Localizer["Chart"]
+@Localizer["ChartIntro"]
+
+
+
+@((MarkupString)Localizer["ChartIntro2"].Value)
+
+
+
+
diff --git a/src/BootstrapBlazor.Server/Components/Samples/Charts/Index.razor.cs b/src/BootstrapBlazor.Server/Components/Samples/Charts/Index.razor.cs
new file mode 100644
index 000000000..7827308fa
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Samples/Charts/Index.razor.cs
@@ -0,0 +1,194 @@
+// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+// Website: https://www.blazor.zone or https://argozhang.github.io/
+
+namespace BootstrapBlazor.Server.Components.Samples.Charts;
+
+///
+///
+///
+public sealed partial class Index
+{
+ ///
+ /// 获得属性列表
+ ///
+ ///
+ private static IEnumerable GetAttributes() => new AttributeItem[]
+ {
+ new() {
+ Name = "Title",
+ Description = "图表标题",
+ Type = "string",
+ ValueList = " — ",
+ DefaultValue = " — "
+ },
+ new() {
+ Name = "Height",
+ Description = "组件高度支持单位, 如: 30% , 30px , 30em , calc(30%)",
+ Type = "string",
+ ValueList = " — ",
+ DefaultValue = " — "
+ },
+ new() {
+ Name = "Width",
+ Description = "组件宽度支持单位, 如: 30% , 30px , 30em , calc(30%)",
+ Type = "string",
+ ValueList = " — ",
+ DefaultValue = " — "
+ },
+ new() {
+ Name = "Responsive",
+ Description = "设置图表所在canvas是否随其容器大小变化而变化",
+ Type = "bool",
+ ValueList = "true|false",
+ DefaultValue = "true"
+ },
+ new() {
+ Name = "MaintainAspectRatio",
+ Description = "设置是否约束图表比例",
+ Type = "bool",
+ ValueList = "true|false",
+ DefaultValue = "true"
+ },
+ new() {
+ Name = "AspectRatio",
+ Description = "设置canvas的宽高比(值为1表示canvas是正方形),如果显示定义了canvas的高度,则此属性无效",
+ Type = "int",
+ ValueList = " - ",
+ DefaultValue = "2"
+ },
+ new() {
+ Name = "ResizeDelay",
+ Description = "设置 图表尺寸延迟变化时间",
+ Type = "int",
+ ValueList = " - ",
+ DefaultValue = "0"
+ },
+ new() {
+ Name = "Angle",
+ Description = "设置 Bubble 模式下显示角度 180 为 半圆 360 为正圆",
+ Type = "int",
+ ValueList = " - ",
+ DefaultValue = " - "
+ },
+ new() {
+ Name = "LoadingText",
+ Description = "设置正在加载文本",
+ Type = "string",
+ ValueList = " - ",
+ DefaultValue = " - "
+ },
+ new() {
+ Name = "ChartType",
+ Description = "图表组件渲染类型",
+ Type = "ChartType",
+ ValueList = "Line|Bar|Pie|Doughnut|Bubble",
+ DefaultValue = "Line"
+ },
+ new() {
+ Name = "ChartAction",
+ Description = "图表组件组件方法",
+ Type = "ChartAction",
+ ValueList = "Update|AddDataset|RemoveDataset|AddData|RemoveData|SetAngle|Reload",
+ DefaultValue = "Update"
+ },
+ new() {
+ Name = "DisplayLegend",
+ Description = "是否显示图例",
+ Type = "bool",
+ ValueList = "true|false",
+ DefaultValue = "true"
+ },
+ new() {
+ Name = "LegendPosition",
+ Description = "图例显示位置",
+ Type = "ChartLegendPosition",
+ ValueList = "Top|Bottom|Left|Right",
+ DefaultValue = "Top"
+ },
+ new()
+ {
+ Name = "OnInitAsync",
+ Description="组件数据初始化委托方法",
+ Type ="Func>",
+ ValueList = " - ",
+ DefaultValue = " - "
+ },
+ new()
+ {
+ Name = "OnAfterInitAsync",
+ Description="客户端绘制图表完毕后回调此委托方法",
+ Type ="Func",
+ ValueList = " - ",
+ DefaultValue = " - "
+ },
+ new()
+ {
+ Name = "OnAfterUpdateAsync",
+ Description="客户端更新图表完毕后回调此委托方法",
+ Type ="Func",
+ ValueList = " - ",
+ DefaultValue = " - "
+ },
+ new()
+ {
+ Name = "Update",
+ Description="更新图表方法",
+ Type ="Task",
+ ValueList = " - ",
+ DefaultValue = " - "
+ },
+ new()
+ {
+ Name = "Reload",
+ Description="重新加载,强制重新渲染图表",
+ Type ="Task",
+ ValueList = " - ",
+ DefaultValue = " - "
+ }
+
+ };
+
+ ///
+ /// 获得方法列表
+ ///
+ ///
+ private static IEnumerable GetMethodAttributes() => new MethodItem[]
+ {
+ new MethodItem()
+ {
+ Name = nameof(BootstrapBlazor.Components.Chart.OnInitAsync),
+ Description = "组件数据初始化委托方法",
+ Parameters = "Func>",
+ ReturnValue = " — "
+ },
+ new MethodItem()
+ {
+ Name = nameof(BootstrapBlazor.Components.Chart.OnAfterInitAsync),
+ Description = "客户端绘制图表完毕后回调此委托方法",
+ Parameters = "Func",
+ ReturnValue = " — "
+ },
+ new MethodItem()
+ {
+ Name = nameof(BootstrapBlazor.Components.Chart.OnAfterUpdateAsync),
+ Description = "客户端更新图表完毕后回调此委托方法",
+ Parameters = "Func",
+ ReturnValue = " — "
+ },
+ new MethodItem()
+ {
+ Name = nameof(BootstrapBlazor.Components.Chart.Update),
+ Description = "更新图表方法",
+ Parameters ="Task",
+ ReturnValue = " — "
+ },
+ new MethodItem()
+ {
+ Name = nameof(BootstrapBlazor.Components.Chart.Reload),
+ Description = "重新加载,强制重新渲染图表",
+ Parameters = "Task",
+ ReturnValue = " — "
+ }
+ };
+}
diff --git a/src/BootstrapBlazor.Server/Components/Samples/Charts/Line.razor b/src/BootstrapBlazor.Server/Components/Samples/Charts/Line.razor
new file mode 100644
index 000000000..c5aacaa58
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Samples/Charts/Line.razor
@@ -0,0 +1,60 @@
+@page "/chart/line"
+@inject IStringLocalizer Localizer
+@inject CodeSnippetService CodeSnippetService
+@inherits IdComponentBase
+@implements IAsyncDisposable
+
+
+
+
+
+ Utility.RandomData(LineChart)">@Localizer["LineOnInitRandomData"]
+ @Localizer["LineOnInitReload"]
+ Utility.AddDataSet(LineChart, ref LineDatasetCount)">@Localizer["LineOnInitAddDataset"]
+ Utility.RemoveDataSet(LineChart, ref LineDatasetCount)">@Localizer["LineOnInitRemoveDataset"]
+ Utility.AddData(LineChart, ref LineDataCount)">@Localizer["LineOnInitAddingData"]
+ Utility.RemoveData(LineChart, ref LineDataCount)">@Localizer["LineOnInitRemoveData"]
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ JavaScript Code
+ @Code
+
+
diff --git a/src/BootstrapBlazor.Server/Components/Samples/Charts/Line.razor.cs b/src/BootstrapBlazor.Server/Components/Samples/Charts/Line.razor.cs
new file mode 100644
index 000000000..ed4effd60
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Samples/Charts/Line.razor.cs
@@ -0,0 +1,281 @@
+// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+// Website: https://www.blazor.zone or https://argozhang.github.io/
+
+using Microsoft.JSInterop;
+
+namespace BootstrapBlazor.Server.Components.Samples.Charts;
+
+///
+/// Line 图表示例
+///
+public partial class Line
+{
+ private Random Randomer { get; } = new();
+
+ private int LineDatasetCount = 2;
+
+ private int LineDataCount = 7;
+
+ [NotNull]
+ private Chart? LineChart { get; set; }
+
+ [NotNull]
+ private ConsoleLogger? Logger { get; set; }
+
+ private ChartPointStyle[] chartPointStyles = new[]
+ {
+ ChartPointStyle.Circle,
+ ChartPointStyle.Cross,
+ ChartPointStyle.CrossRot,
+ ChartPointStyle.Dash,
+ ChartPointStyle.Line,
+ ChartPointStyle.Rect,
+ ChartPointStyle.RectRounded,
+ ChartPointStyle.RectRot,
+ ChartPointStyle.Star,
+ ChartPointStyle.Triangle,
+ };
+
+ ///
+ ///
+ ///
+ ///
+ protected override void OnAfterRender(bool firstRender)
+ {
+ base.OnAfterRender(firstRender);
+
+ if (firstRender)
+ {
+ Logger.Log("Line loading data ...");
+ }
+ }
+
+ private Task OnAfterInit()
+ {
+ Logger.Log("Line initialization is complete");
+ return Task.CompletedTask;
+ }
+
+ private Task OnAfterUpdate(ChartAction action)
+ {
+ Logger.Log($"Line Figure update data operation completed -- {action}");
+ return Task.CompletedTask;
+ }
+
+ private Task OnInit(float tension, bool hasNull)
+ {
+ var ds = new ChartDataSource();
+ ds.Options.Title = "Line Chart";
+ ds.Options.LegendLabelsFontSize = 16;
+ ds.Options.X.Title = "days";
+ ds.Options.Y.Title = "Numerical value";
+ ds.Options.XScalesBorderColor = "red";
+ ds.Options.YScalesBorderColor = "red";
+
+ ds.Options.XScalesGridColor = "blue";
+ ds.Options.XScalesGridTickColor = "blue";
+ ds.Options.XScalesGridBorderColor = "blue";
+
+ ds.Options.YScalesGridColor = "blue";
+ ds.Options.YScalesGridTickColor = "blue";
+ ds.Options.YScalesGridBorderColor = "blue";
+
+ ds.Labels = Enumerable.Range(1, LineDataCount).Select(i => i.ToString());
+ for (var index = 0; index < LineDatasetCount; index++)
+ {
+ ds.Data.Add(new ChartDataset()
+ {
+ BorderWidth = Randomer.Next(1, 5),
+ Tension = tension,
+ Label = $"Set {index}",
+ Data = Enumerable.Range(1, LineDataCount).Select((i, index) => (index == 2 && hasNull) ? null! : (object)Randomer.Next(20, 37)),
+ ShowPointStyle = true,
+ PointStyle = chartPointStyles[Randomer.Next(0, 9)],
+ PointRadius = 5,
+ PointHoverRadius = 10
+ });
+ }
+ return Task.FromResult(ds);
+ }
+
+ private Task OnReloadChart()
+ {
+ LineDataCount = Randomer.Next(5, 15);
+ LineChart?.Reload();
+ return Task.CompletedTask;
+ }
+
+ private Task OnInitTension(float tension, bool hasNull)
+ {
+ var ds = new ChartDataSource();
+ ds.Options.Title = "Line Chart";
+ ds.Options.X.Title = "days";
+ ds.Options.Y.Title = "Numerical value";
+ ds.Labels = Enumerable.Range(1, LineDataCount).Select(i => i.ToString());
+ for (var index = 0; index < LineDatasetCount; index++)
+ {
+ ds.Data.Add(new ChartDataset()
+ {
+ Tension = tension,
+ Label = $"Set {index}",
+ Data = Enumerable.Range(1, LineDataCount).Select((i, index) => (index == 2 && hasNull) ? null! : (object)Randomer.Next(20, 37))
+ });
+ }
+ return Task.FromResult(ds);
+ }
+
+ private Task OnInitNullable(float tension, bool hasNull)
+ {
+ var ds = new ChartDataSource();
+ ds.Options.Title = "Line Chart";
+ ds.Options.X.Title = "days";
+ ds.Options.Y.Title = "Numerical value";
+ ds.Labels = Enumerable.Range(1, LineDataCount).Select(i => i.ToString());
+ for (var index = 0; index < LineDatasetCount; index++)
+ {
+ ds.Data.Add(new ChartDataset()
+ {
+ Tension = tension,
+ Label = $"Set {index}",
+ Data = Enumerable.Range(1, LineDataCount).Select((i, index) => (index == 2 && hasNull) ? null! : (object)Randomer.Next(20, 37))
+ });
+ }
+ return Task.FromResult(ds);
+ }
+
+ private Task OnInitTwoAxes(float tension, bool hasNull)
+ {
+ var ds = new ChartDataSource();
+ ds.Options.Title = "Line Chart";
+ ds.Options.X.Title = "days";
+ ds.Options.Y.Title = "Y value";
+ ds.Options.Y2.Title = "Y2 value";
+ ds.Options.Y2.PositionLeft = false;
+
+ ds.Labels = Enumerable.Range(1, LineDataCount).Select(i => i.ToString());
+ var index = 0;
+ ds.Data.Add(new ChartDataset()
+ {
+ Tension = tension,
+ Label = $"Y2 Set {index}",
+ IsAxisY2 = index == 0,
+ Data = Enumerable.Range(1, LineDataCount).Select((i, index) => (index == 2 && hasNull) ? null! : (object)Randomer.Next(20, 7000))
+ });
+
+ for (index = 1; index < LineDatasetCount; index++)
+ {
+ ds.Data.Add(new ChartDataset()
+ {
+ Tension = tension,
+ Label = $"Y Set {index}",
+ IsAxisY2 = index == 0,
+ Data = Enumerable.Range(1, LineDataCount).Select((i, index) => (index == 2 && hasNull) ? null! : (object)Randomer.Next(20, 37))
+ });
+ }
+ return Task.FromResult(ds);
+ }
+
+ private Task OnInitAspectRatio(float tension, bool hasNull)
+ {
+ var ds = new ChartDataSource();
+ ds.Options.Title = "Line Chart";
+ ds.Options.X.Title = "days";
+ ds.Options.Y.Title = "Numerical value";
+ ds.Labels = Enumerable.Range(1, LineDataCount).Select(i => i.ToString());
+ for (var index = 0; index < LineDatasetCount; index++)
+ {
+ ds.Data.Add(new ChartDataset()
+ {
+ Tension = tension,
+ Label = $"Set {index}",
+ Data = Enumerable.Range(1, LineDataCount).Select((i, index) => (index == 2 && hasNull) ? null! : (object)Randomer.Next(20, 37))
+ });
+ }
+ return Task.FromResult(ds);
+ }
+
+ [Inject]
+ [NotNull]
+ private IVersionService? JSVersionService { get; set; }
+
+ ///
+ /// JS 互操作实例
+ ///
+ private IJSObjectReference? Module { get; set; }
+
+ ///
+ /// Random 随机数生成器
+ ///
+ private Random Random { get; } = new();
+
+ ///
+ /// JS 代码段
+ /// JS Code
+ ///
+ private string? Code { get; set; }
+
+ ///
+ ///
+ ///
+ protected override async Task OnInitializedAsync()
+ {
+ await base.OnInitializedAsync();
+
+ Code = await CodeSnippetService.GetFileContentAsync("Charts\\Line.razor.js");
+ }
+
+ ///
+ ///
+ /// 动态导入JS模块,初始化Chart
+ /// Dynamically import JS module and initialize Chart
+ ///
+ ///
+ protected override async Task OnAfterRenderAsync(bool firstRender)
+ {
+ await base.OnAfterRenderAsync(firstRender);
+
+ if (firstRender)
+ {
+ Module = await JSRuntime.InvokeAsync("import", $"Components/Samples/Charts/Line.razor.js?v={JSVersionService.GetVersion()}");
+
+ //随机生成一组数据
+ //Randomly generate a set of data
+ var chartData = Enumerable.Range(1, 7).Select(_ => Random.Next(25, 85)).ToArray();
+ await Module.InvokeVoidAsync("lineChart", Id, chartData);
+ }
+ }
+
+ private async Task Randomize()
+ {
+ //随机生成一组数据
+ //Randomly generate a set of data
+ var chartData = Enumerable.Range(1, 7).Select(_ => Random.Next(25, 85));
+ if (Module != null)
+ {
+ await Module.InvokeVoidAsync("randomize", Id, chartData);
+ }
+ }
+
+ private async ValueTask Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ if (Module != null)
+ {
+ await Module.InvokeVoidAsync("dispose", Id);
+ await Module.DisposeAsync();
+ }
+ }
+ }
+
+ ///
+ /// 释放资源
+ /// DisposeAsync
+ ///
+ public async ValueTask DisposeAsync()
+ {
+ await Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+}
diff --git a/src/BootstrapBlazor.Server/Components/Samples/Charts/Line.razor.js b/src/BootstrapBlazor.Server/Components/Samples/Charts/Line.razor.js
new file mode 100644
index 000000000..c6294c2d9
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Samples/Charts/Line.razor.js
@@ -0,0 +1,68 @@
+//通过相对路径导入BootstrapBlazor.Chart的Chart.JS模块
+import '../../../../_content/BootstrapBlazor.Chart/js/chart.js'
+import Data from '../../../../_content/BootstrapBlazor/modules/data.js'
+
+export function lineChart(canvasId, chartData) {
+ const ctx = document.getElementById(canvasId);
+
+ const data = {
+ labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July'],
+ datasets: [{
+ label: 'BootStrapBlazor.Chart',
+ data: chartData,
+ fill: false,
+ borderColor: 'rgb(75, 192, 192)',
+ pointStyle: 'circle',
+ pointRadius: 5,
+ pointHoverRadius: 10
+ }]
+ };
+
+ const config = {
+ type: 'line',
+ data: data,
+ options: {
+ plugins: {
+ legend: {
+ labels: {
+ font: {
+ size: 26,
+ style: 'italic'
+ }
+ }
+ }
+ },
+ animations: {
+ tension: {
+ duration: 1000,
+ easing: 'linear',
+ from: 1,
+ to: 0,
+ loop: true
+ }
+ },
+ scales: {
+ y: {
+ min: 0,
+ max: 100
+ }
+ }
+ }
+ };
+
+ Data.set(canvasId, new Chart(ctx, config))
+}
+
+export function randomize(canvasId, chartData) {
+ const chart = Data.get(canvasId)
+ if (chart) {
+ chart.data.datasets.forEach(dataset => {
+ dataset.data = chartData;
+ });
+ chart.update();
+ }
+}
+
+export function dispose(canvasId) {
+ Data.remove(canvasId)
+}
diff --git a/src/BootstrapBlazor.Server/Components/Samples/Charts/Pie.razor b/src/BootstrapBlazor.Server/Components/Samples/Charts/Pie.razor
new file mode 100644
index 000000000..7d54eed87
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Samples/Charts/Pie.razor
@@ -0,0 +1,31 @@
+@page "/chart/pie"
+@inject IStringLocalizer Localizer
+
+
+
+
+
+ Utility.RandomData(PieChart)">@Localizer["PieNormalRandomData"]
+ @Localizer["PieNormalReload"]
+ Utility.AddDataSet(PieChart, ref PieDatasetCount)">@Localizer["PieNormalAddDataset"]
+ Utility.RemoveDataSet(PieChart, ref PieDatasetCount)">@Localizer["PieNormalRemoveDataset"]
+ Utility.AddData(PieChart, ref PieDataCount)">@Localizer["PieNormalAddingData"]
+ Utility.RemoveData(PieChart, ref PieDataCount)">@Localizer["PieNormalRemoveData"]
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/BootstrapBlazor.Server/Components/Samples/Charts/Pie.razor.cs b/src/BootstrapBlazor.Server/Components/Samples/Charts/Pie.razor.cs
new file mode 100644
index 000000000..c8fe2e155
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Samples/Charts/Pie.razor.cs
@@ -0,0 +1,105 @@
+// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+// Website: https://www.blazor.zone or https://argozhang.github.io/
+
+namespace BootstrapBlazor.Server.Components.Samples.Charts;
+
+///
+/// Pie 图表示例
+///
+public partial class Pie
+{
+ private Random Randomer { get; } = new();
+
+ private int PieDatasetCount = 1;
+
+ private int PieDataCount = 5;
+
+ [NotNull]
+ private Chart? PieChart { get; set; }
+
+ [NotNull]
+ private ConsoleLogger? Logger { get; set; }
+
+ ///
+ ///
+ ///
+ ///
+ protected override void OnAfterRender(bool firstRender)
+ {
+ base.OnAfterRender(firstRender);
+
+ if (firstRender)
+ {
+ Logger.Log("Pie loading data ...");
+ }
+ }
+
+ private Task OnAfterInit()
+ {
+ Logger.Log("Pie initialization is complete");
+ return Task.CompletedTask;
+ }
+
+ private Task OnAfterUpdate(ChartAction action)
+ {
+ Logger.Log($"Pie Figure update data operation completed -- {action}");
+ return Task.CompletedTask;
+ }
+
+ private Task OnInit()
+ {
+ var ds = new ChartDataSource();
+ ds.Options.Title = "Pie chart";
+ ds.Labels = Utility.Colors.Take(PieDataCount);
+ for (var index = 0; index < PieDatasetCount; index++)
+ {
+ ds.Data.Add(new ChartDataset()
+ {
+ Label = $"Set {index}",
+ Data = Enumerable.Range(1, PieDataCount).Select(i => Randomer.Next(20, 37)).Cast()
+ });
+ }
+ return Task.FromResult(ds);
+ }
+
+ private Task OnReloadChart()
+ {
+ PieDataCount = Randomer.Next(5, 15);
+ PieChart?.Reload();
+ return Task.CompletedTask;
+ }
+
+ private Task OnInitAspectRatio()
+ {
+ var ds = new ChartDataSource();
+ ds.Options.Title = "Pie chart";
+ ds.Labels = Utility.Colors.Take(PieDataCount);
+ for (var index = 0; index < PieDatasetCount; index++)
+ {
+ ds.Data.Add(new ChartDataset()
+ {
+ Label = $"Set {index}",
+ Data = Enumerable.Range(1, PieDataCount).Select(i => Randomer.Next(20, 37)).Cast()
+ });
+ }
+ return Task.FromResult(ds);
+ }
+
+ private Task OnInitLegendPosition()
+ {
+ var ds = new ChartDataSource();
+ ds.Options.Title = "Pie chart";
+ ds.Options.LegendPosition = ChartLegendPosition.Left;
+ ds.Labels = Utility.Colors.Take(PieDataCount);
+ for (var index = 0; index < PieDatasetCount; index++)
+ {
+ ds.Data.Add(new ChartDataset()
+ {
+ Label = $"Set {index}",
+ Data = Enumerable.Range(1, PieDataCount).Select(i => Randomer.Next(20, 37)).Cast()
+ });
+ }
+ return Task.FromResult(ds);
+ }
+}
diff --git a/src/BootstrapBlazor.Server/Components/Samples/Charts/Utility.cs b/src/BootstrapBlazor.Server/Components/Samples/Charts/Utility.cs
new file mode 100644
index 000000000..c51133d8d
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Samples/Charts/Utility.cs
@@ -0,0 +1,90 @@
+// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+// Website: https://www.blazor.zone or https://argozhang.github.io/
+
+namespace BootstrapBlazor.Server.Components.Samples.Charts;
+
+///
+/// Chart 工具类
+///
+internal static class Utility
+{
+ public static IEnumerable Colors { get; } = new List() { "Red", "Blue", "Green", "Orange", "Yellow", "Tomato", "Pink", "Violet" };
+
+ ///
+ ///
+ ///
+ ///
+ public static Task RandomData(Chart chart) => chart.Update(ChartAction.Update);
+
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static void AddDataSet(Chart chart, ref int dsCount)
+ {
+ if (dsCount < Colors.Count())
+ {
+ dsCount++;
+ _ = chart.Update(ChartAction.AddDataset);
+ }
+ }
+
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static void RemoveDataSet(Chart chart, ref int dsCount)
+ {
+ if (dsCount > 1)
+ {
+ dsCount--;
+ _ = chart.Update(ChartAction.RemoveDataset);
+ }
+ }
+
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static void AddData(Chart chart, ref int daCount)
+ {
+ var limit = chart.ChartType switch
+ {
+ ChartType.Line => 14,
+ ChartType.Bar => 14,
+ ChartType.Bubble => 14,
+ _ => Colors.Count()
+ };
+
+ if (daCount < limit)
+ {
+ daCount++;
+ _ = chart.Update(ChartAction.AddData);
+ }
+ }
+
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static void RemoveData(Chart chart, ref int daCount)
+ {
+ var limit = chart.ChartType switch
+ {
+ ChartType.Line => 7,
+ ChartType.Bar => 7,
+ ChartType.Bubble => 4,
+ _ => 2
+ };
+ if (daCount > limit)
+ {
+ daCount--;
+ _ = chart.Update(ChartAction.RemoveData);
+ }
+ }
+}
diff --git a/src/BootstrapBlazor.Server/Components/Samples/CheckboxLists.razor b/src/BootstrapBlazor.Server/Components/Samples/CheckboxLists.razor
new file mode 100644
index 000000000..b71dc1c28
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Samples/CheckboxLists.razor
@@ -0,0 +1,115 @@
+@page "/checkbox-list"
+
+@Localizer["Title"]
+
+@Localizer["CheckboxListsTip"]
+
+
+
+ @((MarkupString)Localizer["NormalTips1"].Value)
+ @((MarkupString)Localizer["NormalTips2"].Value)
+ @((MarkupString)Localizer["NormalTips3"].Value)
+
+
+
+
+
+
+ @((MarkupString)Localizer["ValidateFormTips1"].Value)
+ @((MarkupString)Localizer["ValidateFormTips2"].Value)
+ @((MarkupString)Localizer["ValidateFormTips3"].Value)
+
+
+
+
+
+
+
@Localizer["Foo.BindValue"]
+
@Dummy.Name
+
+
+
+
+
+
+ @((MarkupString)Localizer["ShowLabelTip"].Value)
+
+
+
+
+
+
@Localizer["Foo.BindValue"]
+
@(string.Join(",", ShowLabelValue1))
+
+
+ @((MarkupString)Localizer["Description"].Value)
+
+
+
+
+
+
@Localizer["Foo.BindValue"]
+
@(string.Join(",", Value2))
+
+
+
+
+
+ @((MarkupString)Localizer["EnumTip"].Value)
+
+
+
+
+
+
@Localizer["Foo.BindValue"]
+
@(string.Join(",", SelectedEnumValues))
+
+
+
+
+
+ @Localizer["NoBorderTip"]
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/BootstrapBlazor.Server/Components/Samples/CheckboxLists.razor.cs b/src/BootstrapBlazor.Server/Components/Samples/CheckboxLists.razor.cs
new file mode 100644
index 000000000..f96ab0075
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Samples/CheckboxLists.razor.cs
@@ -0,0 +1,175 @@
+// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+// Website: https://www.blazor.zone or https://argozhang.github.io/
+
+namespace BootstrapBlazor.Server.Components.Samples;
+
+///
+/// CheckboxLists
+///
+public partial class CheckboxLists
+{
+ [NotNull]
+ private IEnumerable? Items3 { get; set; }
+
+ private IEnumerable SelectedEnumValues { get; set; } = new List
+ {
+ EnumEducation.Middle, EnumEducation.Primary
+ };
+
+ enum EnumEducation
+ {
+ [Display(Name = "小学")]
+ Primary,
+ [Display(Name = "中学")]
+ Middle
+ }
+
+ [NotNull]
+ private IEnumerable? Items1 { get; set; }
+
+ [NotNull]
+ private IEnumerable? Items2 { get; set; }
+
+ private IEnumerable ShowLabelValue1 { get; set; } = new int[] { 9, 10 };
+
+ private IEnumerable Value2 { get; set; } = new string[] { "13", "15" };
+
+ private Foo Dummy { get; set; } = new Foo();
+
+ [NotNull]
+ private IEnumerable? Items4 { get; set; }
+
+ ///
+ /// OnInitialized method
+ ///
+ protected override void OnInitialized()
+ {
+ base.OnInitialized();
+
+ Items1 = new List(new List
+ {
+ new SelectedItem { Text = "Item 9", Value = "9" },
+ new SelectedItem { Text = "Item 10", Value = "10" },
+ new SelectedItem { Text = "Item 11", Value = "11" },
+ new SelectedItem { Text = "Item 12", Value = "12" },
+ });
+
+ Items2 = new List(new List
+ {
+ new SelectedItem { Text = "Item 13", Value = "13" },
+ new SelectedItem { Text = "Item 14", Value = "14" },
+ new SelectedItem { Text = "Item 15", Value = "15" },
+ new SelectedItem { Text = "Item 16", Value = "16" },
+ });
+
+ Items3 = new List(new List
+ {
+ new SelectedItem { Text = Localizer["item1"], Value = Localizer["item1"] },
+ new SelectedItem { Text = Localizer["item2"], Value = Localizer["item2"] },
+ new SelectedItem { Text = Localizer["item3"], Value = Localizer["item3"] },
+ new SelectedItem { Text = Localizer["item4"], Value = Localizer["item4"] },
+ });
+
+ Items4 = new List(new List
+ {
+ new SelectedItem { Text = Localizer["item1"], Value = Localizer["item1"] },
+ new SelectedItem { Text = Localizer["item2"], Value = Localizer["item2"] },
+ new SelectedItem { Text = Localizer["item3"], Value = Localizer["item3"] },
+ new SelectedItem { Text = Localizer["item4"], Value = Localizer["item4"] },
+ });
+
+ Dummy = new Foo() { Name = Localizer["Foo"] };
+ Model = Foo.Generate(LocalizerFoo);
+ FooItems = Foo.GenerateHobbies(LocalizerFoo);
+ }
+
+ [NotNull]
+ private Foo? Model { get; set; }
+
+ [NotNull]
+ private IEnumerable? SelectedItems { get; set; }
+
+ [NotNull]
+ private IEnumerable? FooItems { get; set; }
+
+ private string? Value { get; set; }
+
+ private string Value1 { get; set; } = "1,3";
+
+ [NotNull]
+ private ConsoleLogger? NormalLogger { get; set; }
+
+ [NotNull]
+ private IEnumerable? Items { get; set; } = new List(new List
+ {
+ new SelectedItem { Text = "Item 1", Value = "1" },
+ new SelectedItem { Text = "Item 2", Value = "2" , IsDisabled = true },
+ new SelectedItem { Text = "Item 3", Value = "3" },
+ new SelectedItem { Text = "Item 4", Value = "4" },
+ });
+
+ private Task OnSelectedChanged(IEnumerable items, string value)
+ {
+ NormalLogger.Log($"{Localizer["Header"]} {items.Count(i => i.Active)} {Localizer["Counter"]}:{value}");
+ return Task.CompletedTask;
+ }
+
+ [Inject]
+ [NotNull]
+ private IStringLocalizer? Localizer { get; set; }
+
+ [Inject]
+ [NotNull]
+ IStringLocalizer? LocalizerFoo { get; set; }
+
+ private IEnumerable GetAttributes() => new AttributeItem[]
+ {
+ new()
+ {
+ Name = "Items",
+ Description = Localizer["Att1"],
+ Type = "IEnumerable",
+ ValueList = " — ",
+ DefaultValue = " — "
+ },
+ new()
+ {
+ Name = "IsDisabled",
+ Description = Localizer["Att1"],
+ Type = "boolean",
+ ValueList = " — ",
+ DefaultValue = "false"
+ },
+ new()
+ {
+ Name = "Value",
+ Description = Localizer["Att1"],
+ Type = "TValue",
+ ValueList = " — ",
+ DefaultValue = " — "
+ },
+ new()
+ {
+ Name = "IsVertical",
+ Description = Localizer["Att1"],
+ Type = "boolean",
+ ValueList = " true / false ",
+ DefaultValue = " false "
+ }
+ };
+
+ ///
+ /// Get event method
+ ///
+ ///
+ private IEnumerable GetEvents() => new EventItem[]
+ {
+ new()
+ {
+ Name = "OnSelectedChanged",
+ Description = Localizer["Event1"],
+ Type ="Func, TValue, Task>"
+ }
+ };
+}
diff --git a/src/BootstrapBlazor.Server/Components/Samples/Checkboxs.razor b/src/BootstrapBlazor.Server/Components/Samples/Checkboxs.razor
new file mode 100644
index 000000000..07e12833e
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Samples/Checkboxs.razor
@@ -0,0 +1,145 @@
+@page "/checkbox"
+@inject IStringLocalizer Localizer
+
+@Localizer["Title"]
+
+@Localizer["Description"]
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ @((MarkupString)Localizer["ShowAfterLabelDescription"].Value)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ @((MarkupString)Localizer["ValidateFormDescription"].Value)
+
+
+
+
+
+
+
+
diff --git a/src/BootstrapBlazor.Server/Components/Samples/Checkboxs.razor.cs b/src/BootstrapBlazor.Server/Components/Samples/Checkboxs.razor.cs
new file mode 100644
index 000000000..117b409d9
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Samples/Checkboxs.razor.cs
@@ -0,0 +1,123 @@
+// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+// Website: https://www.blazor.zone or https://argozhang.github.io/
+
+using System.ComponentModel;
+
+namespace BootstrapBlazor.Server.Components.Samples;
+
+///
+/// Checkboxs
+///
+public sealed partial class Checkboxs
+{
+ private Foo Model { get; set; } = new Foo();
+
+ private class Foo
+ {
+ [DisplayName("标签文字1")]
+ public bool BindValue { get; set; }
+
+ [DisplayName("标签文字2")]
+ public bool BindValue1 { get; set; }
+ }
+
+ [NotNull]
+ private ConsoleLogger? BindStringLogger { get; set; }
+
+ private string BindString { get; set; } = "我爱 Blazor";
+
+ private Task OnItemChangedString(CheckboxState state, string value)
+ {
+ BindStringLogger.Log($"CheckboxState: {state} - Bind Value: {value}");
+ return Task.CompletedTask;
+ }
+
+ private bool BindValue { get; set; }
+
+ [NotNull]
+ private ConsoleLogger? OnStateChangedLogger { get; set; }
+
+ private Task OnItemChanged(CheckboxState state, bool value)
+ {
+ OnStateChangedLogger.Log($"CheckboxState: {state} - Bind Value: {value}");
+ return Task.CompletedTask;
+ }
+
+ [NotNull]
+ private ConsoleLogger? NormalLogger { get; set; }
+
+ private Task OnStateChanged(CheckboxState state, string value)
+ {
+ NormalLogger.Log($"Checkbox state changed State: {state}");
+ return Task.CompletedTask;
+ }
+
+ ///
+ /// GetAttributes
+ ///
+ ///
+ private IEnumerable GetAttributes() => new AttributeItem[]
+ {
+ new()
+ {
+ Name = "ShowLabel",
+ Description = Localizer["Att1"],
+ Type = "bool",
+ ValueList = "true|false",
+ DefaultValue = "false"
+ },
+ new()
+ {
+ Name = "ShowAfterLabel",
+ Description = Localizer["Att2"],
+ Type = "bool",
+ ValueList = "true|false",
+ DefaultValue = "false"
+ },
+ new()
+ {
+ Name = "DisplayText",
+ Description = Localizer["Att3"],
+ Type = "string",
+ ValueList = " — ",
+ DefaultValue = " — "
+ },
+ new(){
+ Name = "IsDisabled",
+ Description = Localizer["Att4"],
+ Type = "boolean",
+ ValueList = "true / false",
+ DefaultValue = "false"
+ },
+ new()
+
+ {
+ Name = "State",
+ Description = Localizer["Att5"],
+ Type = "CheckboxState",
+ ValueList = "Mixed / Checked / UnChecked",
+ DefaultValue = "UnChecked"
+ },
+ };
+
+ ///
+ /// 获得事件方法
+ ///
+ ///
+ private IEnumerable GetEvents() => new EventItem[]
+ {
+ new()
+ {
+ Name = "OnStateChanged",
+ Description = Localizer["Event1"],
+ Type ="Action"
+ },
+ new()
+ {
+ Name = "StateChanged",
+ Description = Localizer["Event2"],
+ Type ="EventCallback"
+ }
+ };
+}
diff --git a/src/BootstrapBlazor.Server/Components/Samples/CherryMarkdowns.razor b/src/BootstrapBlazor.Server/Components/Samples/CherryMarkdowns.razor
new file mode 100644
index 000000000..a5a2c8706
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Samples/CherryMarkdowns.razor
@@ -0,0 +1,37 @@
+@page "/cherry-markdown"
+
+@Localizer["Header"]
+@Localizer["Tip"]
+@((MarkupString)Localizer["MarkdownsNote"].Value)
+
+builder.Services.Configure<HubOptions>(option => option.MaximumReceiveMessageSize = null);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ @Localizer["InsertCheckListButtonText"]
+ @Localizer["InsertPictureButtonText"]
+
+
+
diff --git a/src/BootstrapBlazor.Server/Components/Samples/CherryMarkdowns.razor.cs b/src/BootstrapBlazor.Server/Components/Samples/CherryMarkdowns.razor.cs
new file mode 100644
index 000000000..7a36a1c75
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Samples/CherryMarkdowns.razor.cs
@@ -0,0 +1,119 @@
+// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+// Website: https://www.blazor.zone or https://argozhang.github.io/
+using Microsoft.Extensions.Options;
+
+namespace BootstrapBlazor.Server.Components.Samples;
+
+///
+/// CherryMarkdowns
+///
+public partial class CherryMarkdowns
+{
+ [NotNull]
+ private CherryMarkdown? MarkdownElement { get; set; }
+
+ private async Task InsertCheckList()
+ {
+ await MarkdownElement.DoMethodAsync("toolbar.toolbarHandlers.insert", "checklist");
+ }
+
+ private async Task InsertPicture()
+ {
+ await MarkdownElement.DoMethodAsync("insert", "![一张图片](https://i.niupic.com/images/2022/04/01/9Y6T.jpg)", false, false, true);
+ }
+
+ private string? HtmlString { get; set; }
+
+ private string? MarkdownString { get; set; } = "# test";
+
+ private EditorSettings EditorSettings { get; set; } = new EditorSettings()
+ {
+ DefaultModel = "editOnly"
+ };
+
+ private ToolbarSettings ToolbarSettings { get; set; } = new ToolbarSettings()
+ {
+ Toolbar = new List
+ {
+ "italic", new{insert = new List(){"image" } }
+ },
+ Bubble = new List()
+ {
+ "bold"
+ },
+ Float = new List()
+ {
+ "h1"
+ }
+ };
+
+ [Inject]
+ [NotNull]
+ private IOptionsMonitor? SiteOptions { get; set; }
+
+ private async Task OnFileUpload(CherryMarkdownUploadFile arg)
+ {
+ var url = Path.Combine("images", "uploader",
+ $"{Path.GetFileNameWithoutExtension(arg.FileName)}-{DateTimeOffset.Now:yyyyMMddHHmmss}{Path.GetExtension(arg.FileName)}");
+ var fileName = Path.Combine(SiteOptions.CurrentValue.WebRootPath, url);
+ var ret = await arg.SaveToFile(fileName);
+ return ret ? url : "";
+ }
+
+ [Inject]
+ [NotNull]
+ private IStringLocalizer? Localizer { get; set; }
+
+ private IEnumerable GetAttributes() => new AttributeItem[]
+ {
+ new()
+ {
+ Name = "EditorSettings",
+ Description = "编辑器设置",
+ Type = "EditorSettings",
+ ValueList = " — ",
+ DefaultValue = " — "
+ },
+ new()
+ {
+ Name = "ToolbarSettings",
+ Description = "工具栏设置",
+ Type = "ToolbarSettings",
+ ValueList = " — ",
+ DefaultValue = " — "
+ },
+ new()
+ {
+ Name = "Value",
+ Description = "组件值",
+ Type = "string",
+ ValueList = " — ",
+ DefaultValue = " — "
+ },
+ new()
+ {
+ Name = "Html",
+ Description = "组件 Html 代码",
+ Type = "string",
+ ValueList = " — ",
+ DefaultValue = " — "
+ },
+ new()
+ {
+ Name = "OnFileUpload",
+ Description = "文件上传回调方法",
+ Type = "Func>",
+ ValueList = " — ",
+ DefaultValue = " — "
+ },
+ new()
+ {
+ Name = "IsViewer",
+ Description = "组件是否为浏览器模式",
+ Type = "bool",
+ ValueList = "true/false",
+ DefaultValue = "false"
+ }
+ };
+}
diff --git a/src/BootstrapBlazor.Server/Components/Samples/Circles.razor b/src/BootstrapBlazor.Server/Components/Samples/Circles.razor
new file mode 100644
index 000000000..5379217cd
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Samples/Circles.razor
@@ -0,0 +1,60 @@
+@page "/circle"
+@inject IStringLocalizer Localizer
+
+@Localizer["Title"]
+
+@Localizer["SubTitle"]
+
+
+ @Localizer["CircleTips1"]
+ @Localizer["CircleTips2"]
+
+
+
+
+
+
+ Add(10)">
+
+ @Localizer["IncreaseSpan"] 10
+
+ Add(-10)">
+
+ @Localizer["DecreaseSpan"] 10
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
42,001,776
+
@Localizer["ChildContentP1"]
+
+ @Localizer["ChildContentSpan"]
+ 75%
+
+
+
+
+
+
diff --git a/src/BootstrapBlazor.Server/Components/Samples/Circles.razor.cs b/src/BootstrapBlazor.Server/Components/Samples/Circles.razor.cs
new file mode 100644
index 000000000..2fb91fdb8
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Samples/Circles.razor.cs
@@ -0,0 +1,76 @@
+// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+// Website: https://www.blazor.zone or https://argozhang.github.io/
+
+namespace BootstrapBlazor.Server.Components.Samples;
+
+///
+/// Circles
+///
+public sealed partial class Circles
+{
+ private int _circleValue = 0;
+
+ private void Add(int interval)
+ {
+ _circleValue += interval;
+ _circleValue = Math.Min(100, Math.Max(0, _circleValue));
+ }
+
+ ///
+ /// GetAttributes
+ ///
+ ///
+ private IEnumerable GetAttributes() => new AttributeItem[]
+ {
+ new()
+ {
+ Name = "Width",
+ Description = Localizer["Width"],
+ Type = "int",
+ ValueList = "",
+ DefaultValue = "120"
+ },
+ new()
+ {
+ Name = "StrokeWidth",
+ Description = Localizer["StrokeWidth"],
+ Type = "int",
+ ValueList = "",
+ DefaultValue = "2"
+ },
+ new()
+ {
+ Name = "Value",
+ Description = Localizer["Value"],
+ Type = "int",
+ ValueList = "0-100",
+ DefaultValue = "0"
+ },
+ new()
+ {
+ Name = "Color",
+ Description = Localizer["Color"],
+ Type = "Color",
+ ValueList = "Primary / Secondary / Success / Danger / Warning / Info / Dark",
+ DefaultValue = "Primary"
+ },
+ new()
+ {
+ Name = "ShowProgress",
+ Description = Localizer["ShowProgress"],
+ Type = "bool",
+ ValueList = "true / false",
+ DefaultValue = "true"
+ },
+ new()
+ {
+ Name = "ChildContent",
+ Description = Localizer["ChildContent"],
+ Type = "RenderFragment",
+ ValueList = "",
+ DefaultValue = ""
+ }
+ };
+}
+
diff --git a/src/BootstrapBlazor.Server/Components/Samples/Circles.razor.css b/src/BootstrapBlazor.Server/Components/Samples/Circles.razor.css
new file mode 100644
index 000000000..0e89c1ba3
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Samples/Circles.razor.css
@@ -0,0 +1,16 @@
+.circle-demo {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ flex-flow: column;
+}
+
+ .circle-demo h1 {
+ font-size: 26px;
+ font-weight: 400;
+ }
+
+ .circle-demo i {
+ font-style: normal;
+ color: #3f414d;
+ }
diff --git a/src/BootstrapBlazor.Server/Components/Samples/Client.razor b/src/BootstrapBlazor.Server/Components/Samples/Client.razor
new file mode 100644
index 000000000..9a1acda26
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Samples/Client.razor
@@ -0,0 +1,81 @@
+@page "/client"
+@inject IStringLocalizer Localizer
+
+@Localizer["Title"]
+
+@Localizer["SubTitle"]
+
+
+ @Localizer["BasicUsageP1"]
+
+
@((MarkupString)Localizer["BasicUsageP2"].Value)
+
public void Configure(IApplicationBuilder app)
+{
+ // ...
+ // 增加下面这一行
+ app.UseBootstrapBlazor();
+ app.UseEndpoints(endpoints =>
+ {
+ endpoints.MapDefaultControllerRoute();
+ endpoints.MapBlazorHub();
+ endpoints.MapFallbackToPage("/_Host");
+ });
+}
+
+
+
+ @((MarkupString)Localizer["BasicUsageTips"].Value)
+
+
+
+
@((MarkupString)Localizer["BasicUsageP3"].Value)
+
[Inject]
+[NotNull]
+private WebClientService? ClientService { get; set; }
+
+private ClientInfo? ClientInfo { get; set; }
+
+protected override async Task OnAfterRenderAsync(bool firstRender)
+{
+ await base.OnAfterRenderAsync(firstRender);
+
+ if (firstRender)
+ {
+ ClientInfo = await ClientService.GetClientInfo();
+ StateHasChanged();
+ }
+}
+
+
+
+
+
+
diff --git a/src/BootstrapBlazor.Server/Components/Samples/Client.razor.cs b/src/BootstrapBlazor.Server/Components/Samples/Client.razor.cs
new file mode 100644
index 000000000..b7fd18ff1
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Samples/Client.razor.cs
@@ -0,0 +1,27 @@
+namespace BootstrapBlazor.Server.Components.Samples;
+
+///
+/// Client 组件示例
+///
+public partial class Client
+{
+ [Inject]
+ [NotNull]
+ private WebClientService? ClientService { get; set; }
+ private ClientInfo ClientInfo { get; set; } = new ClientInfo();
+
+ ///
+ /// OnAfterRenderAsync
+ ///
+ ///
+ ///
+ protected override async Task OnAfterRenderAsync(bool firstRender)
+ {
+ await base.OnAfterRenderAsync(firstRender);
+ if (firstRender)
+ {
+ ClientInfo = await ClientService.GetClientInfo();
+ StateHasChanged();
+ }
+ }
+}
diff --git a/src/BootstrapBlazor.Server/Components/Samples/Clipboards.razor b/src/BootstrapBlazor.Server/Components/Samples/Clipboards.razor
new file mode 100644
index 000000000..e5b31843a
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Samples/Clipboards.razor
@@ -0,0 +1,19 @@
+@page "/clipboard-service"
+@inject IStringLocalizer Localizer
+
+
+ [Inject]
+[NotNull]
+private ClipboardService? ClipboardService { get; set; }
+
+private void Copy()
+{
+ ClipboardService.Copy(content);
+}
+
+
+
+
+
+
+
diff --git a/src/BootstrapBlazor.Server/Components/Samples/Clipboards.razor.cs b/src/BootstrapBlazor.Server/Components/Samples/Clipboards.razor.cs
new file mode 100644
index 000000000..b1eb17e9c
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Samples/Clipboards.razor.cs
@@ -0,0 +1,39 @@
+// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+// Website: https://www.blazor.zone or https://argozhang.github.io/
+
+namespace BootstrapBlazor.Server.Components.Samples;
+
+///
+/// 剪切板示例
+///
+public partial class Clipboards
+{
+ [Inject]
+ [NotNull]
+ private ClipboardService? ClipboardService { get; set; }
+
+ [Inject]
+ [NotNull]
+ private ToastService? ToastService { get; set; }
+
+ private string content { get; set; } = "Hello BootstrapBlazor";
+
+ private async Task Copy()
+ {
+ await ClipboardService.Copy(content);
+
+ await ToastService.Success("Clipboard", Localizer["ClipboardMessage", content]);
+ }
+
+ private IEnumerable GetMethods() => new MethodItem[]
+ {
+ new()
+ {
+ Name = "Copy",
+ Description = Localizer["ClipboardIntro"],
+ Parameters = " — ",
+ ReturnValue = "Task"
+ }
+ };
+}
diff --git a/src/BootstrapBlazor.Server/Components/Samples/CodeEditors.razor b/src/BootstrapBlazor.Server/Components/Samples/CodeEditors.razor
new file mode 100644
index 000000000..d58dd892c
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Samples/CodeEditors.razor
@@ -0,0 +1,38 @@
+@page "/code-editors"
+@inject IStringLocalizer Localizer
+
+@Localizer["Title"]
+
+
+
+
+
+
+
+
diff --git a/src/BootstrapBlazor.Server/Components/Samples/CodeEditors.razor.cs b/src/BootstrapBlazor.Server/Components/Samples/CodeEditors.razor.cs
new file mode 100644
index 000000000..1702b8351
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Samples/CodeEditors.razor.cs
@@ -0,0 +1,148 @@
+// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+// Website: https://www.blazor.zone or https://argozhang.github.io/
+
+namespace BootstrapBlazor.Server.Components.Samples;
+
+///
+/// CodeEditor 示例
+///
+public partial class CodeEditors
+{
+ [NotNull]
+ private ConsoleLogger? Logger { get; set; }
+
+ [NotNull]
+ private string? Code { get; set; }
+
+ [NotNull]
+ private string? Language { get; set; }
+
+ [NotNull]
+ private string? Theme { get; set; }
+
+ private Task OnSelectedItemChanged(SelectedItem item)
+ {
+ if (item.Text == "JavaScript")
+ {
+ Language = "javascript";
+ Code = """
+function main() {
+ console.log('Hello World!')
+}
+""";
+ }
+
+ if (item.Text == "CSharp")
+ {
+ Language = "csharp";
+ Code = """
+using System;
+
+void Main()
+{
+ Console.WriteLine(""Hello World"");
+}
+""";
+ }
+
+ if (item.Text == "Json")
+ {
+ Language = "json";
+ Code = """
+{
+ "name": "Hello World",
+ "age": 25
+}
+""";
+ }
+
+ if (item.Text == "Razor")
+ {
+ Language = "razor";
+ Code = """
+
+
+ SelectOption>
+ SelectOption >
+ SelectOption >
+ SelectOption >
+
+
+""";
+ }
+ StateHasChanged();
+ return Task.CompletedTask;
+ }
+
+ private Task OnValueChanged(string? value)
+ {
+ if (!string.IsNullOrEmpty(value))
+ {
+ Logger.Log(value);
+ }
+ return Task.CompletedTask;
+ }
+
+ private Task OnThemeSelectedItemChanged(SelectedItem item)
+ {
+ if (item.Value == "vs-dark")
+ {
+ Theme = item.Value;
+ }
+
+ if (item.Value == "vs")
+ {
+ Theme = item.Value;
+ }
+
+ if (item.Value == "hc-black")
+ {
+ Theme = item.Value;
+ }
+ StateHasChanged();
+ return Task.CompletedTask;
+ }
+
+ private IEnumerable GetAttributeItems()
+ {
+ return new List()
+ {
+ new AttributeItem()
+ {
+ Name = nameof(CodeEditor.Value),
+ Type = "string",
+ DefaultValue = "-",
+ Description = Localizer["Value"]
+ },
+ new AttributeItem()
+ {
+ Name = nameof(CodeEditor.Theme),
+ Type = "string",
+ DefaultValue = "vs",
+ Description = Localizer["Theme"]
+ },
+ new AttributeItem()
+ {
+ Name = nameof(CodeEditor.Language),
+ Type = "string",
+ DefaultValue = "csharp",
+ Description = Localizer["Language"]
+ },
+ new AttributeItem()
+ {
+ Name = nameof(CodeEditor.ValueChanged),
+ Type = "EventCallback",
+ DefaultValue = "-",
+ Description = Localizer["ValueChanged"]
+ },
+ new AttributeItem()
+ {
+ Name = nameof(CodeEditor.OnValueChanged),
+ Type = "Func",
+ DefaultValue = "-",
+ Description = Localizer["ValueChanged"]
+ },
+ };
+ }
+}
diff --git a/src/BootstrapBlazor.Server/Components/Samples/Collapses.razor b/src/BootstrapBlazor.Server/Components/Samples/Collapses.razor
new file mode 100644
index 000000000..d27d37ae5
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Samples/Collapses.razor
@@ -0,0 +1,143 @@
+@page "/collapse"
+@inject IStringLocalizer Localizer
+
+@Localizer["Title"]
+
+@Localizer["SubTitle"]
+
+
+
+
+
+ @Localizer["ConsistencyItem1"]
+ @Localizer["ConsistencyItem2"]
+
+
+ @Localizer["FeedbackItem1"]
+ @Localizer["FeedbackItem2"]
+
+
+ @Localizer["EfficiencyItem1"]
+ @Localizer["EfficiencyItem2"]
+ @Localizer["EfficiencyItem3"]
+
+
+ @Localizer["ControllabilityItem1"]
+ @Localizer["ControllabilityItem2"]
+
+
+
+
+
+
+
+
+
+
+ @Localizer["ConsistencyItem1"]
+ @Localizer["ConsistencyItem2"]
+
+
+ @Localizer["FeedbackItem1"]
+ @Localizer["FeedbackItem2"]
+
+
+ @Localizer["EfficiencyItem1"]
+ @Localizer["EfficiencyItem2"]
+ @Localizer["EfficiencyItem3"]
+
+
+ @Localizer["ControllabilityItem1"]
+ @Localizer["ControllabilityItem2"]
+
+
+
+
+
+
+
+
+
+ @Localizer["ConsistencyItem1"]
+ @Localizer["ConsistencyItem2"]
+
+
+ @Localizer["FeedbackItem1"]
+ @Localizer["FeedbackItem2"]
+
+
+ @Localizer["EfficiencyItem1"]
+ @Localizer["EfficiencyItem2"]
+ @Localizer["EfficiencyItem3"]
+
+
+ @Localizer["ControllabilityItem1"]
+ @Localizer["ControllabilityItem2"]
+
+
+
+
+
+
+
+
+ @if (State)
+ {
+
+ @Localizer["ConsistencyItem1"]
+ @Localizer["ConsistencyItem2"]
+
+
+ @Localizer["FeedbackItem1"]
+ @Localizer["FeedbackItem2"]
+
+ }
+ else
+ {
+
+
+
+ @Localizer["ConsistencyItem1"]
+ @Localizer["ConsistencyItem2"]
+
+
+ @Localizer["FeedbackItem1"]
+ @Localizer["FeedbackItem2"]
+
+
+ @Localizer["EfficiencyItem1"]
+ @Localizer["EfficiencyItem2"]
+ @Localizer["EfficiencyItem3"]
+
+
+ @Localizer["ControllabilityItem1"]
+ @Localizer["ControllabilityItem2"]
+
+
+
+ }
+
+
+
+
+
+
+
+
+
+ @Localizer["ConsistencyItem1"]
+ @Localizer["ConsistencyItem2"]
+
+
+ @Localizer["FeedbackItem1"]
+ @Localizer["FeedbackItem2"]
+
+
+ @Localizer["ControllabilityItem1"]
+ @Localizer["ControllabilityItem2"]
+
+
+
+
+
+
diff --git a/src/BootstrapBlazor.Server/Components/Samples/Collapses.razor.cs b/src/BootstrapBlazor.Server/Components/Samples/Collapses.razor.cs
new file mode 100644
index 000000000..3e7562843
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Samples/Collapses.razor.cs
@@ -0,0 +1,59 @@
+// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+// Website: https://www.blazor.zone or https://argozhang.github.io/
+
+namespace BootstrapBlazor.Server.Components.Samples;
+
+///
+/// Collapses
+///
+public sealed partial class Collapses
+{
+ [NotNull]
+ private ConsoleLogger? NormalLogger { get; set; }
+
+ private Task OnChanged(CollapseItem item)
+ {
+ NormalLogger.Log($"{item.Text}: {item.IsCollapsed}");
+ return Task.CompletedTask;
+ }
+
+ private bool State { get; set; }
+
+ private void OnToggle()
+ {
+ State = !State;
+ }
+
+ ///
+ /// 获得属性方法
+ ///
+ ///
+ private IEnumerable GetAttributes() => new AttributeItem[]
+ {
+ new()
+ {
+ Name = "CollapseItems",
+ Description = Localizer["CollapseItems"],
+ Type = "RenderFragment",
+ ValueList = " — ",
+ DefaultValue = " — "
+ },
+ new()
+ {
+ Name = "IsAccordion",
+ Description = Localizer["IsAccordion"],
+ Type = "bool",
+ ValueList = "true|false",
+ DefaultValue = "false"
+ },
+ new()
+ {
+ Name = "OnCollapseChanged",
+ Description = Localizer["OnCollapseChanged"],
+ Type = "Func",
+ ValueList = " — ",
+ DefaultValue = " — "
+ }
+ };
+}
diff --git a/src/BootstrapBlazor.Server/Components/Samples/ColorPickers.razor b/src/BootstrapBlazor.Server/Components/Samples/ColorPickers.razor
new file mode 100644
index 000000000..5151b787c
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Samples/ColorPickers.razor
@@ -0,0 +1,37 @@
+@page "/color-picker"
+@inject IStringLocalizer Localizer
+
+@Localizer["Title"]
+
+@Localizer["Description"]
+
+
+
+
+
+
+
+ @((MarkupString)Localizer["ValueDescription"].Value)
+
+
+
+
+
+ Value: @Value
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/BootstrapBlazor.Server/Components/Samples/ColorPickers.razor.cs b/src/BootstrapBlazor.Server/Components/Samples/ColorPickers.razor.cs
new file mode 100644
index 000000000..1824ed196
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Samples/ColorPickers.razor.cs
@@ -0,0 +1,41 @@
+// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+// Website: https://www.blazor.zone or https://argozhang.github.io/
+namespace BootstrapBlazor.Server.Components.Samples;
+
+///
+/// ColorPickers
+///
+public partial class ColorPickers
+{
+ ///
+ /// Foo 类为Demo测试用,如有需要请自行下载源码查阅
+ /// Foo class is used for Demo test, please download the source code if necessary
+ /// https://gitee.com/LongbowEnterprise/BootstrapBlazor/blob/main/src/BootstrapBlazor.Server/Data/Foo.cs
+ ///
+ [NotNull]
+ private Foo? Dummy { get; set; } = new Foo() { Name = "#dddddd" };
+
+ private string Value { get; set; } = "#FFFFFF";
+
+ [NotNull]
+ private ConsoleLogger? NormalLogger { get; set; }
+
+ private Task OnColorChanged(string color)
+ {
+ NormalLogger.Log($"Selected color: {color}");
+ return Task.CompletedTask;
+ }
+
+ private IEnumerable GetAttributes() => new AttributeItem[]
+ {
+ new()
+ {
+ Name = "OnValueChanged",
+ Description = Localizer["Event1"],
+ Type = "Func",
+ ValueList = "",
+ DefaultValue = ""
+ }
+ };
+}
diff --git a/src/BootstrapBlazor.Server/Components/Samples/Consoles.razor b/src/BootstrapBlazor.Server/Components/Samples/Consoles.razor
new file mode 100644
index 000000000..aa67b5568
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Samples/Consoles.razor
@@ -0,0 +1,33 @@
+@page "/console"
+@using System.Collections.Concurrent
+@implements IDisposable
+
+@Localizer["Title"]
+
+@Localizer["Description"]
+
+
+
+
+
+
+
+
+
+
+ @((MarkupString)Localizer["IsAutoScrollDescription"].Value)
+
+
+
+
+
+
+
+
+ @((MarkupString)Localizer["ShowAutoScrollDescription"].Value)
+
+
+
+
+
+
diff --git a/src/BootstrapBlazor.Server/Components/Samples/Consoles.razor.cs b/src/BootstrapBlazor.Server/Components/Samples/Consoles.razor.cs
new file mode 100644
index 000000000..7fe5cc041
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Samples/Consoles.razor.cs
@@ -0,0 +1,269 @@
+// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+// Website: https://www.blazor.zone or https://argozhang.github.io/
+
+using System.Collections.Concurrent;
+
+namespace BootstrapBlazor.Server.Components.Samples;
+
+///
+/// Consoles
+///
+public sealed partial class Consoles
+{
+ private ConcurrentQueue Messages { get; set; } = new();
+
+ private ConcurrentQueue ColorMessages { get; set; } = new();
+
+ private readonly AutoResetEvent _locker = new(true);
+
+ private CancellationTokenSource? CancelTokenSource { get; set; }
+
+ ///
+ /// OnClear
+ ///
+ private void OnClear()
+ {
+ _locker.WaitOne();
+ while (!Messages.IsEmpty)
+ {
+ Messages.TryDequeue(out var _);
+ }
+ _locker.Set();
+ }
+
+ ///
+ /// GetColor
+ ///
+ ///
+ private static Color GetColor()
+ {
+ var second = DateTime.Now.Second;
+ return (second % 3) switch
+ {
+ 1 => Color.Danger,
+ 2 => Color.Info,
+ _ => Color.None
+ };
+ }
+
+ ///
+ /// OnAfterRender
+ ///
+ ///
+ protected override void OnAfterRender(bool firstRender)
+ {
+ if (firstRender)
+ {
+ Task.Run(async () =>
+ {
+ CancelTokenSource ??= new();
+ while (CancelTokenSource != null && !CancelTokenSource.IsCancellationRequested)
+ {
+ _locker.WaitOne();
+
+ Messages.Enqueue(new ConsoleMessageItem { Message = $"{DateTimeOffset.Now}: Dispatch Message" });
+
+ if (Messages.Count > 8)
+ {
+ Messages.TryDequeue(out var _);
+ }
+
+ ColorMessages.Enqueue(new ConsoleMessageItem { Message = $"{DateTimeOffset.Now}: Dispatch Message", Color = GetColor() });
+
+ if (ColorMessages.Count > 12)
+ {
+ ColorMessages.TryDequeue(out var _);
+ }
+
+ await InvokeAsync(StateHasChanged);
+ _locker.Set();
+
+ try
+ {
+ if (CancelTokenSource != null)
+ {
+ await Task.Delay(2000, CancelTokenSource.Token);
+ }
+ }
+ catch { }
+ }
+ });
+ }
+ }
+
+ ///
+ /// Dispose
+ ///
+ ///
+ private void Dispose(bool disposing)
+ {
+ if (disposing && CancelTokenSource != null)
+ {
+ CancelTokenSource.Cancel();
+ CancelTokenSource.Dispose();
+ CancelTokenSource = null;
+ }
+ }
+
+ ///
+ /// Dispose
+ ///
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ [Inject]
+ [NotNull]
+ private IStringLocalizer? Localizer { get; set; }
+
+ ///
+ /// GetItemAttributes
+ ///
+ ///
+ private static IEnumerable GetItemAttributes() => new AttributeItem[]
+ {
+ new(){
+ Name = "Message",
+ Description = "控制台输出消息",
+ Type = "string",
+ ValueList = " — ",
+ DefaultValue = " — "
+ },
+ new(){
+ Name = "Color",
+ Description = "消息颜色",
+ Type = "Color",
+ ValueList = "None / Active / Primary / Secondary / Success / Danger / Warning / Info / Light / Dark / Link",
+ DefaultValue = "None"
+ }
+ };
+
+ ///
+ /// GetAttributes
+ ///
+ ///
+ private static IEnumerable GetAttributes() => new AttributeItem[]
+ {
+ new()
+ {
+ Name = nameof(BootstrapBlazor.Components.Console.Items),
+ Description = "组件数据源",
+ Type = "IEnumerable",
+ ValueList = " — ",
+ DefaultValue = " — "
+ },
+ new()
+ {
+ Name = "Height",
+ Description = "组件高度",
+ Type = "int",
+ ValueList = " — ",
+ DefaultValue = "0"
+ },
+ new()
+ {
+ Name = nameof(BootstrapBlazor.Components.Console.IsAutoScroll),
+ Description = "是否自动滚屏",
+ Type = "bool",
+ ValueList = "true|false",
+ DefaultValue = "true"
+ },
+ new(){
+ Name = "ShowAutoScroll",
+ Description = "是否显示自动滚屏选项",
+ Type = "bool",
+ ValueList = "true|false",
+ DefaultValue = "false"
+ },
+ new()
+ {
+ Name = "OnClear",
+ Description = "组件清屏回调方法",
+ Type = "int",
+ ValueList = " — ",
+ DefaultValue = "0"
+ },
+ new()
+ {
+ Name = "HeaderText",
+ Description = "Header 显示文字",
+ Type = "string",
+ ValueList = " — ",
+ DefaultValue = "系统监控"
+ },
+ new()
+ {
+ Name = "HeaderTemplate",
+ Description = "Header 模板",
+ Type = "RenderFragment",
+ ValueList = " — ",
+ DefaultValue = " — "
+ },
+ new(){
+ Name = "LightTitle",
+ Description = "指示灯 Title",
+ Type = "string",
+ ValueList = " — ",
+ DefaultValue = "通讯指示灯"
+ },
+ new()
+ {
+ Name = "IsFlashLight",
+ Description = "指示灯是否闪烁",
+ Type = "bool",
+ ValueList = "true/false",
+ DefaultValue = "true"
+ },
+ new()
+ {
+ Name = "LightColor",
+ Description = "指示灯颜色",
+ Type = "Color",
+ ValueList = " — ",
+ DefaultValue = "Color.Success"
+ },
+ new()
+ {
+ Name = "ShowLight",
+ Description = "是否显示指示灯",
+ Type = "bool",
+ ValueList = "true/false",
+ DefaultValue = "true"
+ },
+ new()
+ {
+ Name = "ClearButtonText",
+ Description = "按钮显示文字",
+ Type = "string",
+ ValueList = " — ",
+ DefaultValue = "清屏"
+ },
+ new()
+ {
+ Name = "ClearButtonIcon",
+ Description = "按钮显示图标",
+ Type = "string",
+ ValueList = " — ",
+ DefaultValue = "fa-fw fa-solid fa-xmark"
+ },
+ new()
+ {
+ Name = "ClearButtonColor",
+ Description = "按钮颜色",
+ Type = "Color",
+ ValueList = "None / Active / Primary / Secondary / Success / Danger / Warning / Info / Light / Dark / Link",
+ DefaultValue = "Secondary"
+ },
+ new()
+ {
+ Name = "FooterTemplate",
+ Description = "Footer 模板",
+ Type = "RenderFragment",
+ ValueList = " — ",
+ DefaultValue = " — "
+ }
+ };
+}
diff --git a/src/BootstrapBlazor.Server/Components/Samples/ContextMenus.razor b/src/BootstrapBlazor.Server/Components/Samples/ContextMenus.razor
new file mode 100644
index 000000000..ad70bd22c
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Samples/ContextMenus.razor
@@ -0,0 +1,55 @@
+@page "/context-menu"
+@inject IStringLocalizer Localizer
+@inject IStringLocalizer LocalizerFoo
+
+@Localizer["ContextMenuTitle"]
+
+@Localizer["ContextMenuDescription"]
+
+
+
+
+ @Foo.Name - @Foo.Address
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/BootstrapBlazor.Server/Components/Samples/ContextMenus.razor.cs b/src/BootstrapBlazor.Server/Components/Samples/ContextMenus.razor.cs
new file mode 100644
index 000000000..4333decc7
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Samples/ContextMenus.razor.cs
@@ -0,0 +1,34 @@
+namespace BootstrapBlazor.Server.Components.Samples;
+
+///
+/// ContextMenu 组件示例
+///
+public partial class ContextMenus
+{
+ private List> TreeItems { get; set; } = TreeFoo.GetTreeItems();
+
+ private static Task OnCopy(ContextMenuItem item, object value)
+ {
+ return Task.CompletedTask;
+ }
+
+ private static Task OnPaste(ContextMenuItem item, object value)
+ {
+ return Task.CompletedTask;
+ }
+
+ [NotNull]
+ private List? Items { get; set; }
+
+ [NotNull]
+ private Foo? Foo { get; set; }
+
+ ///
+ /// OnInitialized
+ ///
+ protected override void OnInitialized()
+ {
+ Foo = Foo.Generate(LocalizerFoo);
+ Items = Foo.GenerateFoo(LocalizerFoo);
+ }
+}
diff --git a/src/BootstrapBlazor.Server/Components/Samples/CountButtons.razor b/src/BootstrapBlazor.Server/Components/Samples/CountButtons.razor
new file mode 100644
index 000000000..018204060
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Samples/CountButtons.razor
@@ -0,0 +1,16 @@
+@page "/count-button"
+@inject IStringLocalizer Localizer
+
+@Localizer["Title"]
+
+@Localizer["Description"]
+
+
+
+
+
+
+
+
+
+
diff --git a/src/BootstrapBlazor.Server/Components/Samples/CountButtons.razor.cs b/src/BootstrapBlazor.Server/Components/Samples/CountButtons.razor.cs
new file mode 100644
index 000000000..9ddb624b6
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Samples/CountButtons.razor.cs
@@ -0,0 +1,43 @@
+// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+// Website: https://www.blazor.zone or https://argozhang.github.io/
+
+namespace BootstrapBlazor.Server.Components.Samples;
+
+///
+/// 倒计时按钮组件
+///
+public partial class CountButtons
+{
+ private Task OnClick() => Task.Delay(2000);
+
+ private string CountTextCallback(int count) => Localizer["CountButtonText", count];
+
+ private IEnumerable GetAttributes() => new AttributeItem[]
+ {
+ new()
+ {
+ Name = nameof(CountButton.Count),
+ Description = Localizer["Count"],
+ Type = "TValue",
+ ValueList = " — ",
+ DefaultValue = " — "
+ },
+ new()
+ {
+ Name = nameof(CountButton.CountText),
+ Description = Localizer["CountText"],
+ Type = "CountOption",
+ ValueList = " — ",
+ DefaultValue = " — "
+ },
+ new()
+ {
+ Name = nameof(CountButton.CountTextCallback),
+ Description = Localizer["CountTextCallback"],
+ Type = "Func",
+ ValueList = " — ",
+ DefaultValue = " — "
+ }
+ };
+}
diff --git a/src/BootstrapBlazor.Server/Components/Samples/CountUps.razor b/src/BootstrapBlazor.Server/Components/Samples/CountUps.razor
new file mode 100644
index 000000000..041ff8743
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Samples/CountUps.razor
@@ -0,0 +1,109 @@
+@page "/count-up"
+@inject IStringLocalizer Localizer
+
+@Localizer["Title"]
+
+@Localizer["Description"]
+
+
+
+
+
+ 更改配置后,改变 Value 值后生效
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/BootstrapBlazor.Server/Components/Samples/CountUps.razor.cs b/src/BootstrapBlazor.Server/Components/Samples/CountUps.razor.cs
new file mode 100644
index 000000000..aa7d86b04
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Samples/CountUps.razor.cs
@@ -0,0 +1,219 @@
+// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+// Website: https://www.blazor.zone or https://argozhang.github.io/
+
+namespace BootstrapBlazor.Server.Components.Samples;
+
+///
+/// CountUps
+///
+public partial class CountUps
+{
+ private static readonly CountUpOption _option = new() { DecimalPlaces = 2 };
+
+ private double Value2 { get; set; }
+
+ private double Value { get; set; }
+
+ private ConsoleLogger? _logger;
+
+ private bool _useOnCompleted;
+
+ private List _items = new();
+
+ ///
+ protected override void OnInitialized()
+ {
+ _items.Add(new SelectedItem("", "Default (\"1234\")"));
+ _items.Add(new SelectedItem("1", "Eastern Arabic (\"١٢٣٤\")"));
+ OnUpdate();
+ }
+
+ private void OnUpdate()
+ {
+ Value = Value2;
+ }
+
+ private Task OnCompleted()
+ {
+ if (_useOnCompleted)
+ {
+ _logger?.Log($"{DateTime.Now}: from {_option.StartValue} to {Value2}");
+ }
+ return Task.CompletedTask;
+ }
+
+ private Task OnSelectedItemChanged(SelectedItem item)
+ {
+ var index = _items.IndexOf(item);
+ if (index == 0)
+ {
+ _option.Numerals = null;
+ }
+ else if (index == 1)
+ {
+ _option.Numerals = new char[] { '٠', '١', '٢', '٣', '٤', '٥', '٦', '٧', '٨', '٩' };
+ }
+ return Task.CompletedTask;
+ }
+
+ private IEnumerable GetAttributes() => new AttributeItem[]
+ {
+ new()
+ {
+ Name = "Value",
+ Description = Localizer["Value"],
+ Type = "TValue",
+ ValueList = " — ",
+ DefaultValue = " — "
+ },
+ new()
+ {
+ Name = "Option",
+ Description = Localizer["CountOption"],
+ Type = "CountOption",
+ ValueList = " — ",
+ DefaultValue = " — "
+ },
+ new()
+ {
+ Name = "OnCompleted",
+ Description = Localizer["OnCompleted"],
+ Type = "Func",
+ ValueList = " — ",
+ DefaultValue = " — "
+ }
+ };
+
+ private IEnumerable GetOptionAttributes() => new AttributeItem[]
+ {
+ new()
+ {
+ Name = nameof(CountUpOption.StartValue),
+ Description = Localizer["StartValue"],
+ Type = "decimal",
+ ValueList = " — ",
+ DefaultValue = "0"
+ },
+ new()
+ {
+ Name = nameof(CountUpOption.Duration),
+ Description = Localizer["Duration"],
+ Type = "float",
+ ValueList = " — ",
+ DefaultValue = "0"
+ },
+ new()
+ {
+ Name = nameof(CountUpOption.UseEasing),
+ Description = Localizer["UseEasing"],
+ Type = "boolean",
+ ValueList = " — ",
+ DefaultValue = "true"
+ },
+ new()
+ {
+ Name = nameof(CountUpOption.DecimalPlaces),
+ Description = Localizer["DecimalPlaces"],
+ Type = "int",
+ ValueList = " — ",
+ DefaultValue = "0"
+ },
+ new()
+ {
+ Name = nameof(CountUpOption.Decimal),
+ Description = Localizer["Decimal"],
+ Type = "string",
+ ValueList = " — ",
+ DefaultValue = " — "
+ },
+ new()
+ {
+ Name = nameof(CountUpOption.UseGrouping),
+ Description = Localizer["UseGrouping"],
+ Type = "boolean",
+ ValueList = " — ",
+ DefaultValue = "true"
+ },
+ new()
+ {
+ Name = nameof(CountUpOption.UseIndianSeparators),
+ Description = Localizer["UseIndianSeparators"],
+ Type = "boolean",
+ ValueList = " — ",
+ DefaultValue = "false"
+ },
+ new()
+ {
+ Name = nameof(CountUpOption.Separator),
+ Description = Localizer["Separator"],
+ Type = "string",
+ ValueList = " — ",
+ DefaultValue = " — "
+ },
+ new()
+ {
+ Name = nameof(CountUpOption.Prefix),
+ Description = Localizer["Prefix"],
+ Type = "string",
+ ValueList = " — ",
+ DefaultValue = " — "
+ },
+ new()
+ {
+ Name = nameof(CountUpOption.Suffix),
+ Description = Localizer["Suffix"],
+ Type = "string",
+ ValueList = " — ",
+ DefaultValue = " — "
+ },
+ new()
+ {
+ Name = nameof(CountUpOption.SmartEasingAmount),
+ Description = Localizer["SmartEasingAmount"],
+ Type = "int",
+ ValueList = " — ",
+ DefaultValue = " — "
+ },
+ new()
+ {
+ Name = nameof(CountUpOption.SmartEasingThreshold),
+ Description = Localizer["SmartEasingThreshold"],
+ Type = "int",
+ ValueList = " — ",
+ DefaultValue = " — "
+ },
+ new()
+ {
+ Name = nameof(CountUpOption.EnableScrollSpy),
+ Description = Localizer["EnableScrollSpy"],
+ Type = "boolean",
+ ValueList = " — ",
+ DefaultValue = "false"
+ },
+ new()
+ {
+ Name = nameof(CountUpOption.ScrollSpyDelay),
+ Description = Localizer["ScrollSpyDelay"],
+ Type = "int",
+ ValueList = " — ",
+ DefaultValue = "200"
+ },
+ new()
+ {
+ Name = nameof(CountUpOption.ScrollSpyOnce),
+ Description = Localizer["ScrollSpyOnce"],
+ Type = "boolean",
+ ValueList = " — ",
+ DefaultValue = "false"
+ },
+ new()
+ {
+ Name = nameof(CountUpOption.Numerals),
+ Description = Localizer["Numerals"],
+ Type = "char[]",
+ ValueList = " — ",
+ DefaultValue = " — "
+ }
+ };
+}
diff --git a/src/BootstrapBlazor.Server/Components/Samples/CountUps.razor.css b/src/BootstrapBlazor.Server/Components/Samples/CountUps.razor.css
new file mode 100644
index 000000000..d331bd55e
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Samples/CountUps.razor.css
@@ -0,0 +1,3 @@
+[ignore] ::deep .input-group-text {
+ width: 120px;
+}
diff --git a/src/BootstrapBlazor.Server/Components/Samples/DateTimePickers.razor b/src/BootstrapBlazor.Server/Components/Samples/DateTimePickers.razor
new file mode 100644
index 000000000..e6052e4d1
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Samples/DateTimePickers.razor
@@ -0,0 +1,153 @@
+@page "/datetime-picker"
+
+@Localizer["Title"]
+
+@Localizer["Description"]
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ @((MarkupString)Localizer["ViewModeTip"].Value)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ @((MarkupString)Localizer["NullValueTip"].Value)
+
+
+
+
+ @((MarkupString)Localizer["ShowLabelTip1"].Value)
+ @((MarkupString)Localizer["ShowLabelTip2"].Value)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/BootstrapBlazor.Server/Components/Samples/DateTimePickers.razor.cs b/src/BootstrapBlazor.Server/Components/Samples/DateTimePickers.razor.cs
new file mode 100644
index 000000000..1e04ccc5f
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Samples/DateTimePickers.razor.cs
@@ -0,0 +1,168 @@
+// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+// Website: https://www.blazor.zone or https://argozhang.github.io/
+
+namespace BootstrapBlazor.Server.Components.Samples;
+
+///
+/// DateTimePickers
+///
+public sealed partial class DateTimePickers
+{
+ [NotNull]
+ private ConsoleLogger? NormalLogger { get; set; }
+
+ private DateTime Value { get; set; } = DateTime.Today;
+
+ private Task NormalOnConfirm()
+ {
+ NormalLogger.Log($"Value: {Value:yyyy-MM-dd}");
+ return Task.CompletedTask;
+ }
+
+ [NotNull]
+ private ConsoleLogger? ValueChangedLogger { get; set; }
+
+ private TimeSpan ValueChangedValue { get; set; } = DateTime.Now - DateTime.Today;
+
+ private void ValueChangedOnConfirm()
+ {
+ ValueChangedLogger.Log($"Value: {ValueChangedValue:hh\\:mm\\:ss}");
+ }
+
+ ///
+ /// ModelValidateValue
+ ///
+ [Required]
+ public DateTime? ValidateFormValue { get; set; }
+
+ private DateTimeOffset? DateTimeOffsetValue { get; set; } = DateTimeOffset.Now;
+
+ private TimeSpan TimeValue { get; set; } = DateTime.Now - DateTime.Today;
+
+ private TimeSpan SpanValue { get; set; } = DateTime.Now.Subtract(DateTime.Today);
+
+ private static string FormatterSpanString(TimeSpan ts)
+ {
+ return ts.ToString("hh\\:mm\\:ss");
+ }
+
+ private DateTime? BindNullValue { get; set; }
+
+ private string GetNullValueString => BindNullValue.HasValue ? BindNullValue.Value.ToString("yyyy-MM-dd") : "";
+
+ private DateTime? ShowLabelValue { get; set; }
+
+ private bool IsDisabled { get; set; } = true;
+
+ private DateTime? BindValue { get; set; } = DateTime.Today;
+
+ private string BindValueString
+ {
+ get => BindValue.HasValue ? BindValue.Value.ToString("yyyy-MM-dd") : "";
+ set => BindValue = DateTime.TryParse(value, out var d) ? d : null;
+ }
+
+ [Inject]
+ [NotNull]
+ private IStringLocalizer? Localizer { get; set; }
+
+ ///
+ /// 获得事件方法
+ ///
+ ///
+ private IEnumerable GetEvents() => new EventItem[]
+ {
+ new EventItem()
+ {
+ Name = "OnClickConfirm",
+ Description = Localizer["Event1"],
+ Type ="Action"
+ },
+ new EventItem()
+ {
+ Name = "ValueChanged",
+ Description = Localizer["Event2"],
+ Type ="EventCallback"
+ }
+ };
+
+ ///
+ /// 获得属性方法
+ ///
+ ///
+ private IEnumerable GetAttributes() => new AttributeItem[]
+ {
+ new()
+ {
+ Name = "ShowLabel",
+ Description = Localizer["Att1"],
+ Type = "bool",
+ ValueList = "true|false",
+ DefaultValue = "true"
+ },
+ new()
+ {
+ Name = "ShowSidebar",
+ Description = Localizer["Att2"],
+ Type = "bool",
+ ValueList = "true|false",
+ DefaultValue = "false"
+ },
+ new()
+ {
+ Name = "DisplayText",
+ Description = Localizer["Att3"],
+ Type = "string",
+ ValueList = " — ",
+ DefaultValue = " — "
+ },
+ new()
+ {
+ Name = "Format",
+ Description = Localizer["Att4"],
+ Type = "string",
+ ValueList = " — ",
+ DefaultValue = "yyyy-MM-dd"
+ },
+ new()
+ {
+ Name = "IsShown",
+ Description = Localizer["Att5"],
+ Type = "boolean",
+ ValueList = "",
+ DefaultValue = "false"
+ },
+ new()
+ {
+ Name = "IsDisabled",
+ Description = Localizer["Att6"],
+ Type = "bool",
+ ValueList = "true|false",
+ DefaultValue = "false"
+ },
+ new()
+ {
+ Name = "Value",
+ Description = Localizer["Att8"],
+ Type = "TValue",
+ ValueList = "DateTime | DateTime?",
+ DefaultValue = " — "
+ },
+ new()
+ {
+ Name = "ViewMode",
+ Description = Localizer["Att9"],
+ Type = "DatePickerViewMode",
+ ValueList = " Date / DateTime / Year / Month",
+ DefaultValue = "Date"
+ },
+ new() {
+ Name = "AutoClose",
+ Description = Localizer["AttrAutoClose"],
+ Type = "bool",
+ ValueList = "true/false",
+ DefaultValue = "false"
+ }
+ };
+}
diff --git a/src/BootstrapBlazor.Server/Components/Samples/DateTimeRanges.razor b/src/BootstrapBlazor.Server/Components/Samples/DateTimeRanges.razor
new file mode 100644
index 000000000..b59f19799
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Samples/DateTimeRanges.razor
@@ -0,0 +1,89 @@
+@page "/datetime-range"
+@inject IStringLocalizer Localizer
+
+@Localizer["Title"]
+
+@Localizer["Description"]
+
+
+
+
+
+
+
+