diff --git a/docs/en/Blog-Posts/2023-04-17-How-to-Optimize-Your-ASP.NET-Application-for-Improved-Performance/post.md b/docs/en/Blog-Posts/2023-04-17-How-to-Optimize-Your-ASP.NET-Application-for-Improved-Performance/post.md new file mode 100644 index 0000000000..261621933a --- /dev/null +++ b/docs/en/Blog-Posts/2023-04-17-How-to-Optimize-Your-ASP.NET-Application-for-Improved-Performance/post.md @@ -0,0 +1,118 @@ +# 💻 How to Optimize Your ASP.NET Application for Improved Performance 🚀 + +If you want your ASP.NET application to perform well, you need to optimize it for speed, responsiveness, and user experience. Performance optimization is critical for factors like fast page load times, improved response efficiency, and happy users. In this article, I'll provide several tips and tricks to help you optimize performance in ASP.NET Core. + +## 🚀 Use Response Compression in Your ASP.NET Application +You can use ASP.NET Core's built-in response compression middleware to compress the response data and reduce the amount of data that needs to be transferred over the network. To use response compression, add the following code to your application's Startup.cs file: + +```csharp +services.AddResponseCompression(options => +{ + options.EnableForHttps = true; +}); + +app.UseResponseCompression(); +``` + +## 🖼️ Optimize Images in Your ASP.NET Application: + +Images can be a major contributor to page bloat and slow load times. Here are some tips to optimize images: + +🖌️ Use a tool like ImageOptim or Kraken.io to compress and optimize images. + +🖼️ Specify the width and height of images in HTML so the browser can allocate space for them before they load. + +📝 Use alt attributes to provide descriptive text for images, which can improve accessibility and also help with SEO. + +📜 Use lazy loading for images that are below the fold, meaning they're not visible on the initial screen view. You can use libraries like Vanilla LazyLoad to implement lazy loading. + +📱 Use responsive images to serve different image sizes to different devices. This can improve page load times by reducing the size of images that are displayed on smaller devices. + +💻 Example: + +```html + + + + Image + +``` + +```javascript +var lazyLoadInstance = new LazyLoad(); +``` + +## 🧱 Optimize HTML in Your ASP.NET Application: + +The structure and organization of HTML can affect the page speed. Here are some tips to optimize HTML: + +📝 Use the heading tags (h1, h2, h3, etc.) in a logical and sequential order. + +🔩 Use the "defer" attribute for script tags that don't need to be executed immediately. This can improve the page load times by delaying the execution of scripts until after the page has rendered. + +🔩 Use the "async" attribute for script tags that can be executed asynchronously. This can further improve the page load times by allowing scripts to be downloaded and executed simultaneously. + +🧱 Use semantic HTML elements (like nav, section, and article) to provide additional structure and meaning to the page. + +## 🎨 Optimize CSS and JavaScript in Your ASP.NET Application: + +CSS and JavaScript files can be a major contributor to the page load times. Here are some tips to optimize CSS and JavaScript in your ASP.NET application: + +🔨 Minify and concatenate CSS and JavaScript files to reduce their size. + +🔩 Use the "defer" or "async" attributes for script tags to delay or asynchronously load scripts. + +## 🔡 Use system fonts in Your ASP.NET Application: + +Loading custom fonts can be slow and increase page load times. Using system fonts can improve page speed by allowing the browser to use fonts that are already installed on the user's device. + +## 🖼️ Use Placeholders and Progress Indicators in Your ASP.NET Application: + +To improve the perceived performance of your website, you can use placeholders and progress indicators for slow-loading sections of your page. You can use JavaScript to load these sections after the initial page load. + +💻 Example: + +```html + +
+

Loading...

+
+``` + +```javascript +const placeholder = document.querySelector('#placeholder'); + fetch(placeholder.dataset.url) + .then(response => response.text()) + .then(html => placeholder.innerHTML = html); +``` + +## 🔗 Use the Appropriate Link Text and ARIA Labels: + +When using links, use appropriate link texts that accurately describe the content of the linked page. This can improve the accessibility and also help with SEO. + +ARIA labels should also be used to provide additional context for links. This can also improve the accessibility and help with SEO. + +💻 Example: + +```html +Example +Another Example +``` + +## 🌐 Optimize the Third-party Resources in Your ASP.NET Application: + +Third-party resources like social media widgets and advertising scripts can slow down the page load times. Here are some tips to optimize third-party resources: + +🔩 Use asynchronous scripts when possible. + +🔍 Only load third-party resources that are necessary for the page. + +By following these optimization techniques, you can significantly improve the page speed of your ASP.NET Core web application. + +## What is ABP Framework? + +ABP Framework offers an opinionated architecture to build enterprise software solutions with ASP.NET Core best practices on top of the .NET and the ASP.NET Core platforms. It provides the fundamental web application infrastructure, production-ready dotnet startup templates, modules, asp.net core ui themes, tooling, guides and documentation to implement that ASP.NET core architecture properly and automate the details and repetitive work as much as possible. + +If you are starting a new ASP.NET Core project, try [abp.io](https://abp.io/) now... + +**IT IS FREE AND OPEN-SOURCE!** \ No newline at end of file diff --git a/docs/en/Community-Articles/2023-04-15-Converting-Create-Edit-Modal-To-Page/POST.md b/docs/en/Community-Articles/2023-04-15-Converting-Create-Edit-Modal-To-Page/POST.md new file mode 100644 index 0000000000..a8f1aeadfa --- /dev/null +++ b/docs/en/Community-Articles/2023-04-15-Converting-Create-Edit-Modal-To-Page/POST.md @@ -0,0 +1,325 @@ +# Convert Create/Edit Modals to Page + +In this document we will explain how to convert the BookStore's Books create & edit modals to regular Angular component pages. + +## Before + +![bookstore-crud-before](images/old.gif) + +## After + +![bookstore-crud-after](images/new.gif) + +# BooksComponent + +This is the main component of the books management. The create & update operations are done in this page. So we'll remove the create & update operations from this page and move a separate angular component for each operation. Each component will be a page. + +- Remove the Create & Update modal on template + + ![remove-modal](images/books-remove-modals.png) + +- Modify the **NewBook** button with a link to the **CreateBookComponent** page. + + ```html + + ``` + +- Modify the **Edit** button with a link to the **EditBookComponent** page. + + ```html + + ``` + +- Remove all unused methods and variables in the `BookComponent` except the **book** variable, the **ngOnInit** and **delete** methods. + + + ![bookstore-remove-unsued](images/books-remove-unused.png) + +- Also we can clear unncessary imports + + ![bookstore-remove-unsued-imports](images/books-remove-unused-imports.png) + + + +# CreateBookComponent Page + +Create a new component by the name `create-book` in your project. +```bash + yarn ng g c book/create-book --skip-tests --style=none +``` + +- `create-book.component.html` + +```html +
+
+
+
+ * + +
+ +
+ * + +
+ +
+ * + +
+ +
+ * + +
+ +
+ * + +
+ +
+ + + +
+
+
+
+``` + +- `create-book.component.ts` + +```ts +import { Component, inject } from '@angular/core'; +import { Router } from '@angular/router'; +import { FormBuilder, FormGroup, Validators } from '@angular/forms'; +import { map } from 'rxjs'; +import { NgbDateNativeAdapter, NgbDateAdapter } from '@ng-bootstrap/ng-bootstrap'; +import { BookService, bookTypeOptions } from '@proxy/books'; + +const { required } = Validators; + +@Component({ + selector: 'app-create-book', + templateUrl: './create-book.component.html', + providers: [{ provide: NgbDateAdapter, useClass: NgbDateNativeAdapter }], +}) +export class CreateBookComponent { + //inject() function came with Angular v14, detail: https://angular.io/api/core/inject + private readonly router = inject(Router); + private readonly fb = inject(FormBuilder); + private readonly bookService = inject(BookService); + + form: FormGroup; + authors$ = this.bookService.getAuthorLookup().pipe(map(({ items }) => items)); + bookTypes = bookTypeOptions; + + private buildForm() { + this.form = this.fb.group({ + authorId: [null, required], + name: [null, required], + type: [null, required], + publishDate: [undefined, required], + price: [null, required], + }); + } + + constructor() { + this.buildForm(); + } + + save() { + if (this.form.invalid) return; + + this.bookService.create(this.form.value).subscribe(() => { + this.router.navigate(['/books']); + }); + } +} +``` + +# EditBookComponent Page + +Create a new component by the name **edit-book** in your project. + +```bash + yarn ng g c book/edit-book --skip-tests --style=none +``` + +- `edit-book.component.html` + +```html +
+
+
+
+ * + +
+ +
+ * + +
+ +
+ * + +
+ +
+ * + +
+ +
+ * + +
+ +
+ + + +
+
+
+
+``` + +- `edit-book.component.ts` + +```ts +import { Component, inject } from '@angular/core'; +import { ActivatedRoute, Router } from '@angular/router'; +import { FormBuilder, FormGroup, Validators } from '@angular/forms'; +import { filter, map, switchMap, tap } from 'rxjs'; +import { NgbDateNativeAdapter, NgbDateAdapter } from '@ng-bootstrap/ng-bootstrap'; +import { BookDto, BookService, bookTypeOptions } from '@proxy/books'; + +const { required } = Validators; + +@Component({ + selector: 'app-edit-book', + templateUrl: './edit-book.component.html', + providers: [{ provide: NgbDateAdapter, useClass: NgbDateNativeAdapter }], +}) +export class EditBookComponent { + //inject() function came with Angular v14, detail: https://angular.io/api/core/inject + private readonly router = inject(Router); + private readonly activatedRoute = inject(ActivatedRoute); + private readonly fb = inject(FormBuilder); + private readonly bookService = inject(BookService); + + id: string; + form: FormGroup; + authors$ = this.bookService.getAuthorLookup().pipe(map(({ items }) => items)); + bookTypes = bookTypeOptions; + + private buildForm(book: BookDto): void { + this.form = this.fb.group({ + authorId: [book.authorId, required], + name: [book.name, required], + type: [book.type, required], + publishDate: [new Date(book.publishDate), required], + price: [book.price, required], + }); + } + + constructor() { + this.activatedRoute.params + .pipe( + filter(params => params.id), + tap(({ id }) => (this.id = id)), + switchMap(({ id }) => this.bookService.get(id)), + tap(book => this.buildForm(book)) + ) + .subscribe(); + } + + save(): void { + if (this.form.invalid) return; + + this.bookService.update(this.id, this.form.value).subscribe(() => { + this.router.navigate(['/books']); + }); + } +} +``` + +# Update BookRoutingModule +Finally add 2 items to the routes array in the `book-routing.module.ts` +```ts +import { CreateBookComponent } from './create-book/create-book.component'; +import { EditBookComponent } from './edit-book/edit-book.component'; + +const routes: Routes = [ + { path: '', component: BookComponent, canActivate: [AuthGuard, PermissionGuard] }, + { path: 'create', component: CreateBookComponent }, + { path: 'edit/:id', component: EditBookComponent }, +]; +``` + + +You can check the following commit for more details: https://github.com/abpframework/abp-samples/commit/351ad5e093036702edbb15169968935496afea0e diff --git a/docs/en/Community-Articles/2023-04-15-Converting-Create-Edit-Modal-To-Page/images/books-remove-modals.png b/docs/en/Community-Articles/2023-04-15-Converting-Create-Edit-Modal-To-Page/images/books-remove-modals.png new file mode 100644 index 0000000000..4396819fcd Binary files /dev/null and b/docs/en/Community-Articles/2023-04-15-Converting-Create-Edit-Modal-To-Page/images/books-remove-modals.png differ diff --git a/docs/en/Community-Articles/2023-04-15-Converting-Create-Edit-Modal-To-Page/images/books-remove-unused-imports.png b/docs/en/Community-Articles/2023-04-15-Converting-Create-Edit-Modal-To-Page/images/books-remove-unused-imports.png new file mode 100644 index 0000000000..198db3f243 Binary files /dev/null and b/docs/en/Community-Articles/2023-04-15-Converting-Create-Edit-Modal-To-Page/images/books-remove-unused-imports.png differ diff --git a/docs/en/Community-Articles/2023-04-15-Converting-Create-Edit-Modal-To-Page/images/books-remove-unused.png b/docs/en/Community-Articles/2023-04-15-Converting-Create-Edit-Modal-To-Page/images/books-remove-unused.png new file mode 100644 index 0000000000..f95c90c44d Binary files /dev/null and b/docs/en/Community-Articles/2023-04-15-Converting-Create-Edit-Modal-To-Page/images/books-remove-unused.png differ diff --git a/docs/en/Community-Articles/2023-04-15-Converting-Create-Edit-Modal-To-Page/images/new.gif b/docs/en/Community-Articles/2023-04-15-Converting-Create-Edit-Modal-To-Page/images/new.gif new file mode 100644 index 0000000000..a2e15e9c8d Binary files /dev/null and b/docs/en/Community-Articles/2023-04-15-Converting-Create-Edit-Modal-To-Page/images/new.gif differ diff --git a/docs/en/Community-Articles/2023-04-15-Converting-Create-Edit-Modal-To-Page/images/old.gif b/docs/en/Community-Articles/2023-04-15-Converting-Create-Edit-Modal-To-Page/images/old.gif new file mode 100644 index 0000000000..499af9f28c Binary files /dev/null and b/docs/en/Community-Articles/2023-04-15-Converting-Create-Edit-Modal-To-Page/images/old.gif differ diff --git a/docs/en/Themes/LeptonXLite/AspNetCore.md b/docs/en/Themes/LeptonXLite/AspNetCore.md index b134135a04..1c6baeddf9 100644 --- a/docs/en/Themes/LeptonXLite/AspNetCore.md +++ b/docs/en/Themes/LeptonXLite/AspNetCore.md @@ -29,7 +29,7 @@ dotnet add package Volo.Abp.AspNetCore.Mvc.UI.Theme.LeptonXLite --prerelease )] ``` -- Replace `BasicThemeBundles` with `LeptonXLiteThemeBundles` in AbpBundlingOptions +- Replace `BasicThemeBundles` with `LeptonXLiteThemeBundles` in `AbpBundlingOptions`: ```diff Configure(options => @@ -51,7 +51,7 @@ Configure(options => ### Layouts -LeptonX Lite Mvc provides **layouts** for your **user interface** based [ABP Framework Theming](https://docs.abp.io/en/abp/latest/UI/AspNetCore/Theming). You can use **layouts** to **organize your user interface**. +LeptonX Lite MVC provides **layouts** for your **user interface** based [ABP Framework Theming](https://docs.abp.io/en/abp/latest/UI/AspNetCore/Theming). You can use **layouts** to **organize your user interface**. The main responsibility of a theme is to **provide** the layouts. There are **three pre-defined layouts that must be implemented by all the themes:** @@ -61,11 +61,12 @@ The main responsibility of a theme is to **provide** the layouts. There are **th * **Empty:** The **Minimal** layout that **has no layout components** at all. -**Layout names** are **constants** defined in the `LeptonXLiteTheme` class in the **Mvc** project **root**. +**Layout names** are **constants** defined in the `LeptonXLiteTheme` class in the **MVC** project **root**. > The layout pages define under the `Themes/LeptonXLite/Layouts` folder and you can **override it** by creating a file with the **same name** and **under** the **same folder**. ### Toolbars + LeptonX Lite includes separeted toolbars for desktop & mobile. You can manage toolbars independently. Toolbar names can be accessible in the **LeptonXLiteToolbars** class. - `LeptonXLiteToolbars.Main` @@ -88,23 +89,28 @@ public class MyProjectNameMainToolbarContributor : IToolbarContributor } } ``` -# LeptonX Lite Mvc Components -Abp **helps** you make **highly customizable UI**. You can easily **customize** your themes to fit your needs. **The Virtual File System** makes it possible to **manage files** that **do not physically** exist on the **file system** (disk). It's mainly used to embed **(js, css, image..)** files into assemblies and **use them like** physical files at runtime. An application (or another module) can **override** a **virtual file of a module** just like placing a file with the **same name** and **extension** into the **same folder** of the **virtual file**. +# LeptonX Lite MVC Components + +ABP **helps** you make **highly customizable UI**. You can easily **customize** your themes to fit your needs. **The Virtual File System** makes it possible to **manage files** that **do not physically** exist on the **file system** (disk). It's mainly used to embed **(js, css, image..)** files into assemblies and **use them like** physical files at runtime. An application (or another module) can **override** a **virtual file of a module** just like placing a file with the **same name** and **extension** into the **same folder** of the **virtual file**. -LeptonX Lite is built on the [Abp Framework](https://abp.io/), so you can **easily** customize your Asp.Net Core Mvc user interface by following [Abp Mvc UI Customization](https://docs.abp.io/en/abp/latest/UI/AspNetCore/Customization-xUser-Interface). +LeptonX Lite is built on the [Abp Framework](https://abp.io/), so you can **easily** customize your Asp.Net Core MVC user interface by following [Abp Mvc UI Customization](https://docs.abp.io/en/abp/latest/UI/AspNetCore/Customization-xUser-Interface). -## Brand Component +## Branding Component -The **brand component** is a simple component that can be used to display your brand. It contains a **logo** and a **company name**. +The **branding component** is a simple component that can be used to display your brand. It contains a **logo** and a **company name**. ![Brand component](../../images/leptonxlite-brand-component.png) -### How to override the Brand Component in LeptonX Lite Mvc +### How to override the Branding Component in LeptonX Lite MVC + +* The **branding component page (.cshtml file)** is defined in the `Themes/LeptonXLite/Components/Brand/Default.cshtml` file and you can **override it** by creating a file with the **same name** and **under** the **same folder**. + +* The **branding component (C# file)** is defined in the `Themes/LeptonXLite/Components/Brand/MainNavbarBrandViewComponent.cs` file and you can **override it** by creating a file with the **same name** and under the **same folder**. -* The **brand component page (.cshtml file)** is defined in the `Themes/LeptonXLite/Components/Brand/Default.cshtml` file and you can **override it** by creating a file with the **same name** and **under** the **same folder**. +### How to override the favicon in LeptonX Lite MVC -* The **brand component (C# file)** is defined in the `Themes/LeptonXLite/Components/Brand/MainNavbarBrandViewComponent.cs` file and you can **override it** by creating a file with the **same name** and under the **same folder**. +You can add a new favicon to the `~/wwwroot/favicon.svg` and `~/wwwroot/favicon.ico` paths to override the current favicon. ## Breadcrumb Component @@ -112,7 +118,7 @@ On websites that have a lot of pages, **breadcrumb navigation** can greatly **en ![Breadcrumb component](../../images/leptonxlite-breadcrumb-component.png) -### How to override the Breadcrumb Component in LeptonX Lite Mvc +### How to override the Breadcrumb Component in LeptonX Lite MVC * The **breadcrumb component page (.cshtml file)** is defined in the `Themes/LeptonXLite/Components/Breadcrumbs/Default.cshtml` file and you can **override it** by creating a file with the **same name** and **under** the **same folder**. @@ -124,7 +130,7 @@ Sidebar menus have been used as **a directory for Related Pages** to a **Service ![Sidebar menu component](../../images/leptonxlite-sidebar-menu-component.png) -### How to override the Sidebar Menu Component in LeptonX Lite Mvc +### How to override the Sidebar Menu Component in LeptonX Lite MVC * **Sidebar menu page (.cshtml)** is defined in the `Themes/LeptonXLite/Components/Menu/Default.cshtml` file and you can **override it** by creating a file with the **same name** and **under** the **same folder**. @@ -138,7 +144,7 @@ Provides contextual **feedback messages** for typical user actions with the hand ![Page alerts component](../../images/leptonxlite-page-alerts-component.png) -### How to override the Page Alerts Component in LeptonX Lite Mvc +### How to override the Page Alerts Component in LeptonX Lite MVC * The **page alerts component page (.cshtml file)** is defined in the `Themes/LeptonXLite/Components/PageAlerts/Default.cshtml` file and you can **override it** by creating a file with the **same name** and **under** the **same folder**. @@ -148,7 +154,7 @@ Provides contextual **feedback messages** for typical user actions with the hand Toolbar items are used to add **extra functionality to the toolbar**. The toolbar is a **horizontal bar** that **contains** a group of **toolbar items**. -### How to override the Toolbar Component in LeptonX Lite Mvc +### How to override the Toolbar Component in LeptonX Lite MVC * The **toolbar component page (.cshtml file)** is defined in the `Themes/LeptonXLite/Components/Toolbar/Default.cshtml` file and you can **override it** by creating a file with the **same name** and **under** the **same folder**. @@ -158,7 +164,7 @@ Toolbar items are used to add **extra functionality to the toolbar**. The toolba The toolbar item is a **single item** that **contains** a **link**, an **icon**, a **label** etc.. -### How to override the Toolbar Item Component in LeptonX Lite Mvc +### How to override the Toolbar Item Component in LeptonX Lite MVC * The **toolbar item component page (.cshtml file)** is defined in the `Themes/LeptonXLite/Components/ToolbarItems/Default.cshtml` file and you can **override it** by creating a file with the **same name** and **under** the **same folder**. @@ -172,7 +178,7 @@ Think about a **multi-lingual** website and the first thing that could **hit you ![Language switch component](../../images/leptonxlite-language-switch-component.png) -### How to override the Language Switch Component in LeptonX Lite Mvc +### How to override the Language Switch Component in LeptonX Lite MVC * The **language switch component page (.cshtml file)** is defined in the `Themes/LeptonXLite/Components/LanguageSwitch/Default.cshtml` file and you can **override it** by creating a file with the **same name** and **under** the **same folder**. @@ -184,7 +190,7 @@ The **mobile** **language switch component** is used to switch the language of t ![Mobil language switch component](../../images/leptonxlite-mobile-language-switch-component.png) -### How to override the Mobile Language Switch Component in LeptonX Lite Mvc +### How to override the Mobile Language Switch Component in LeptonX Lite MVC * The **mobile language switch component page (.cshtml file)** is defined in the `Themes/LeptonXLite/Components/MobileLanguageSwitch/Default.cshtml` file and you can **override it** by creating a file with the **same name** and **under** the **same folder**. @@ -196,7 +202,7 @@ The **User Menu** is the **menu** that **drops down** when you **click your name ![User menu component](../../images/leptonxlite-user-menu-component.png) -### How to override the User Menu Component in LeptonX Lite Mvc +### How to override the User Menu Component in LeptonX Lite MVC * The **user menu component page (.cshtml file)** is defined in the `Themes/LeptonXLite/Components/UserMenu/Default.cshtml` file and you can **override it** by creating a file with the **same name** and **under** the **same folder**. @@ -208,7 +214,7 @@ The **mobile user menu component** is used to display the **user menu on mobile ![Mobile user menu component](../../images/leptonxlite-mobile-user-menu-component.png) -### How to override the Mobile User Menu Component in LeptonX Lite Mvc +### How to override the Mobile User Menu Component in LeptonX Lite MVC * The **mobile user menu component page (.cshtml file)** is defined in the `Themes/LeptonXLite/Components/MobileUserMenu/Default.cshtml` file and you can **override it** by creating a file with the **same name** and **under** the **same folder**. diff --git a/docs/en/Themes/LeptonXLite/Blazor.md b/docs/en/Themes/LeptonXLite/Blazor.md index 0e32aa9825..80207fdff2 100644 --- a/docs/en/Themes/LeptonXLite/Blazor.md +++ b/docs/en/Themes/LeptonXLite/Blazor.md @@ -154,6 +154,7 @@ namespace LeptonXLite.DemoApp.Blazor.MyComponents > Don't forget to remove the repeated attributes from the razor page! ### Toolbars + LeptonX Lite includes separeted toolbars for desktop & mobile. You can manage toolbars independently. Toolbar names can be accessible in the **LeptonXLiteToolbars** class. - `LeptonXLiteToolbars.Main` @@ -188,9 +189,9 @@ LeptonX Blazor is built on the basis of components. You can use the components i ### Branding Component -The **brand component** is a simple component that can be used to display your brand. It contains a **logo** and a **company name**. +The **branding component** is a simple component that can be used to display your brand. It contains a **logo** and a **company name**. - +![](../../images/leptonxlite-brand-component.png) #### How to Override Branding Component @@ -219,11 +220,15 @@ namespace LeptonXLite.DemoApp.Blazor.MyComponents } ``` +### How to override the favicon + +Startup templates contain `favicon.ico` files under the `wwwroot` folder of the Blazor application. You can change this file to override the current favicon. + ### Breadcrumb Component On websites that have a lot of pages, **breadcrumb navigation** can greatly **enhance the way users find their way** around. In terms of **usability**, breadcrumbs reduce the number of actions a website **visitor** needs to take in order to get to a **higher-level page**, and they **improve** the **findability** of **website sections** and **pages**. - +![](../../images/leptonxlite-breadcrumb-component.png) #### How to Override the BreadCrumb Component @@ -241,6 +246,7 @@ On websites that have a lot of pages, **breadcrumb navigation** can greatly **en ``` * If you prefer to use a code-behind file for the C# code of your component, create a razor component, like `MyBreadcrumbsComponent.razor.cs`, in your blazor application as shown below: +* ```csharp using Volo.Abp.AspNetCore.Components.Web.LeptonXLiteTheme.Themes.LeptonXLite; using Volo.Abp.DependencyInjection; @@ -260,7 +266,7 @@ namespace LeptonXLite.DemoApp.Blazor.MyComponents Sidebar menus have been used as **a directory for Related Pages** for a **Service** offering, **Navigation** items for a **specific service** or topic and even just as **Links** the user may be interested in. - +![](../../images/leptonxlite-sidebar-menu-component.png) #### How to Override the Main Menu Component @@ -278,6 +284,7 @@ Sidebar menus have been used as **a directory for Related Pages** for a **Servic ``` * If you prefer to use a code-behind file for the C# code of your component, create a razor component, like `MyMainMenu.razor.cs`, in your blazor application as shown below: + ```csharp using Volo.Abp.AspNetCore.Components.Web.LeptonXLiteTheme.Themes.LeptonXLite.Navigation; using Volo.Abp.DependencyInjection; @@ -315,6 +322,7 @@ Toolbar items are used to add **extra functionality to the toolbar**. The toolba ``` * If you prefer to use a code-behind file for the C# code of your component, create a razor component, like `MyToolbarItemsComponent.razor.cs`, in your blazor application as shown below: + ```csharp using Volo.Abp.AspNetCore.Components.Web.LeptonXLiteTheme.Themes.LeptonXLite; using Volo.Abp.DependencyInjection; @@ -334,7 +342,7 @@ namespace LeptonXLite.DemoApp.Blazor.MyComponents Think about a **multi-lingual** website and the first thing that could **hit your mind** is **the language switch component**. A **navigation bar** is a **great place** to **embed a language switch**. By embedding the language switch in the navigation bar of your website, you would **make it simpler** for users to **find it** and **easily** switch the **language** **without trying to locate it across the website.** - +![](../../images/leptonxlite-language-switch-component.png) #### How to Override the Language Switch Component @@ -352,6 +360,7 @@ Think about a **multi-lingual** website and the first thing that could **hit you ``` * If you prefer to use a code-behind file for the C# code of your component, create a razor component, like `MyLanguageSwitchComponent.razor.cs`, in your blazor application as shown below: + ```csharp using Volo.Abp.AspNetCore.Components.Web.LeptonXLiteTheme.Themes.LeptonXLite.Toolbar; using Volo.Abp.DependencyInjection; @@ -371,7 +380,7 @@ namespace LeptonXLite.DemoApp.Blazor.MyComponents The **mobile** **language switch component** is used to switch the language of the website **on mobile devices**. The mobile language switch component is a **dropdown menu** that **contains all the languages** of the website. - +![](../../images/leptonxlite-mobile-language-switch-component.png) #### How to Override the Mobile Language Switch Component @@ -389,6 +398,7 @@ The **mobile** **language switch component** is used to switch the language of t ``` * If you prefer to use a code-behind file for the C# code of your component, create a razor component, like `MyMobilLanguageSwitchComponent.razor.cs`, in your blazor application as shown below: + ```csharp using Volo.Abp.AspNetCore.Components.Web.LeptonXLiteTheme.Themes.LeptonXLite.Toolbar; using Volo.Abp.DependencyInjection; @@ -408,7 +418,7 @@ namespace LeptonXLite.DemoApp.Blazor.MyComponents The **User Menu** is the **menu** that **drops down** when you **click your name** or **profile picture** in the **upper right corner** of your page (**in the toolbar**). It drops down options such as **Settings**, **Logout**, etc. - +![](../../images/leptonxlite-user-menu-component.png) #### How to Override the User Menu Component @@ -426,6 +436,7 @@ The **User Menu** is the **menu** that **drops down** when you **click your name ``` * If you prefer to use a code-behind file for the C# code of your component, create a razor component, like `MyUserMenuComponent.razor.cs`, in your blazor application as shown below: + ```csharp using Volo.Abp.AspNetCore.Components.Server.LeptonXLiteTheme.Themes.LeptonXLite.Toolbar; using Volo.Abp.DependencyInjection; @@ -445,7 +456,7 @@ namespace LeptonXLite.DemoApp.Blazor.MyComponents The **mobile user menu component** is used to display the **user menu on mobile devices**. The mobile user menu component is a **dropdown menu** that contains all the **options** of the **user menu**. - +![](../../images/leptonxlite-mobile-user-menu-component.png) #### How to override the Mobile User Menu Component @@ -463,6 +474,7 @@ The **mobile user menu component** is used to display the **user menu on mobile ``` * If you prefer to use a code-behind file for the C# code of your component, create a razor component, like `MyMobileUserMenuComponent.razor.cs`, in your blazor application as shown below: + ```csharp using Volo.Abp.AspNetCore.Components.Server.LeptonXLiteTheme.Themes.LeptonXLite.Toolbar; using Volo.Abp.DependencyInjection; diff --git a/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/DatePicker.cshtml b/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/DatePicker.cshtml new file mode 100644 index 0000000000..b1c6bd3626 --- /dev/null +++ b/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/DatePicker.cshtml @@ -0,0 +1,790 @@ +@page +@model Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo.Pages.Components.DatePickerModel + +@section styles { + + + +} + + + + + +

Date Picker & Date Range Picker

+ + +
+
+ +
+
+ + +

+public class DatePickerModel : PageModel
+{
+    [BindProperty]
+    public DateTime DateTime { get; set; }
+
+    public void OnGet()
+    {
+        DateTime = DateTime == default ? DateTime.Now : DateTime;
+    }
+}
+
+
+ +

+<abp-date-picker placeholder="New" single-open-and-clear-button="false" week-numbers="Iso" time-picker="true" required today-button-classes="btn-primary" picker-id="testPicker" asp-for="DateTime"/>
+
+
+ +

+<div class="mb-3">
+    <label class="form-label" for="DateTime">DateTime</label><span> * </span>
+    <abp-date-picker placeholder="New" required="" data-show-i-s-o-week-numbers="true" data-time-picker="true" data-today-button-classes="btn-primary" id="testPicker" data-single-open-and-clear-button="false" data-date="2023-04-12T17:56:33.1115260+03:00">
+        <div class="input-group">
+            <input placeholder="New" required="" type="text" autocomplete="off" class="form-control">
+            <button type="button" tabindex="-1" data-type="open" class="btn btn-outline-secondary" data-busy-text="Processing...">
+                <i class="fa fa-calendar"></i>
+            </button>
+            <button type="button" tabindex="-1" data-type="clear" class="btn btn-outline-secondary" data-busy-text="Processing...">
+                <i class="fa fa-times"></i>
+            </button>
+        </div><span class="text-danger col-auto field-validation-valid" data-valmsg-for="DateTime" data-valmsg-replace="true"></span><input data-date="true" type="hidden" data-val="true" data-val-required="The DateTime field is required." id="DateTime" name="DateTime" value="Wed Apr 12 2023 17:56:33 GMT+0300">
+    </abp-date-picker>
+</div>
+
+
+
+
+
+ +
+
+ @section scripts { + + } +
+
+ + +

+var newPicker = abp.libs.bootstrapDateRangePicker.createDateRangePicker(
+            {
+                label: "New JavaScript Picker",
+                startDate: "2020-01-01",
+                endDate: "2020-01-02",
+                singleOpenAndClearButton: false,
+                placeholder: "New Picker",
+            });
+
+
+ +

+<div class="mb-3">
+    <label class="form-label">New JavaScript Picker</label>
+    <abp-date-range-picker>
+        <div class="input-group">
+            <input type="text" autocomplete="off" class="form-control" placeholder="New Picker">
+            <button type="button" class="btn btn-outline-secondary" tabindex="-1" data-type="open">
+                <i class="fa fa-calendar"></i>
+            </button>
+            <button type="button" class="btn btn-outline-secondary" tabindex="-1" data-type="clear">
+                <i class="fa fa-times"></i>
+            </button>
+        </div>
+    </abp-date-range-picker>
+</div>
+
+
+
+
+
+ +
+
+ +
+
+ + +

+public class DatePickerModel : PageModel
+{
+    [BindProperty]
+    public DateTime StartDate { get; set; }
+
+    [BindProperty]
+    public DateTime EndDate { get; set; }
+
+    public void OnGet()
+    {
+        EndDate = EndDate == default ? DateTime.Now : EndDate;
+        DateTime = DateTime == default ? DateTime.Now : DateTime;
+    }
+}
+
+
+ +

+<abp-date-range-picker time-picker="true" asp-for-end="EndDate" asp-for-start="StartDate"/>
+
+
+ +

+<div class="mb-3">
+    <label class="form-label" for="StartDate">StartDate</label>
+    <abp-date-range-picker data-time-picker="true" data-start-date="0001-01-01T00:00:00.0000000" data-end-date="2023-04-12T18:02:13.2033440+03:00">
+        <div class="input-group">
+            <input type="text" autocomplete="off" class="form-control">
+            <button type="button" tabindex="-1" data-type="clear" class="d-none btn btn-outline-secondary" data-busy-text="Processing...">
+                <i class="fa fa-times"></i>
+            </button>
+            <button type="button" tabindex="-1" data-type="open" class="btn btn-outline-secondary" data-busy-text="Processing...">
+                <i class="fa fa-calendar"></i>
+            </button>
+        </div><span class="text-danger col-auto field-validation-valid" data-valmsg-for="StartDate" data-valmsg-replace="true"></span><span class="text-danger col-auto field-validation-valid" data-valmsg-for="EndDate" data-valmsg-replace="true"></span><input data-start-date="true" type="hidden" data-val="true" data-val-required="The StartDate field is required." id="StartDate" name="StartDate" value="Mon Jan 01 0001 00:00:00 GMT+0155"><input data-end-date="true" type="hidden" data-val="true" data-val-required="The EndDate field is required." id="EndDate" name="EndDate" value="Wed Apr 12 2023 18:02:13 GMT+0300">
+    </abp-date-range-picker>
+</div>
+
+
+
+
+
+ +
+
+ +
+
+ + +

+public class DatePickerModel : PageModel
+{
+    [BindProperty]
+    public DateTime? NullableDateTime { get; set; }
+}
+
+
+ +

+<abp-date-picker auto-update-input="true" today-button-classes="btn-primary" asp-for="NullableDateTime"/>
+
+
+ +

+<div class="mb-3">
+    <label class="form-label" for="NullableDateTime">NullableDateTime</label>
+    <abp-date-picker data-today-button-classes="btn-primary" data-auto-update-input="true">
+        <div class="input-group">
+            <input type="text" autocomplete="off" class="form-control">
+            <button type="button" tabindex="-1" data-type="open" class="btn btn-outline-secondary d-none" data-busy-text="Processing...">
+                <i class="fa fa-calendar"></i>
+            </button>
+            <button type="button" tabindex="-1" data-type="clear" class="btn btn-outline-secondary" data-busy-text="Processing...">
+                <i class="fa fa-times"></i>
+            </button>
+        </div><span class="text-danger col-auto field-validation-valid" data-valmsg-for="NullableDateTime" data-valmsg-replace="true"></span><input data-date="true" type="hidden" id="NullableDateTime" name="NullableDateTime" value="2023-04-12">
+    </abp-date-picker>
+</div>
+
+
+
+
+
+ +
+
+ +
+
+ + +

+public class DatePickerModel : PageModel
+{
+    [BindProperty]
+    public DateTime? NullableStartDate { get; set; }
+        
+    [BindProperty]
+    public DateTime? NullableEndDate { get; set; }
+}
+
+
+ +

+<abp-date-picker auto-update-input="true" today-button-classes="btn-primary" asp-for="NullableDateTime"/>
+
+
+ +

+<div class="mb-3">
+    <label class="form-label" for="NullableStartDate">NullableStartDate</label>
+    <abp-date-range-picker>
+        <div class="input-group">
+            <input type="text" autocomplete="off" class="form-control">
+            <button type="button" tabindex="-1" data-type="open" class="btn btn-outline-secondary" data-busy-text="Processing...">
+                <i class="fa fa-calendar"></i>
+            </button>
+        </div><span class="text-danger col-auto field-validation-valid" data-valmsg-for="NullableStartDate" data-valmsg-replace="true"></span><span class="text-danger col-auto field-validation-valid" data-valmsg-for="NullableEndDate" data-valmsg-replace="true"></span><input data-start-date="true" type="hidden" id="NullableStartDate" name="NullableStartDate" value=""><input data-end-date="true" type="hidden" id="NullableEndDate" name="NullableEndDate" value="">
+    </abp-date-range-picker>
+</div>
+
+
+
+
+
+ +
+
+ +
+
+ + +

+public class DatePickerModel : PageModel
+{
+    [BindProperty]
+    public DateTimeOffset DateTimeDateTimeOffset { get; set; }
+
+    public void OnGet()
+    {
+        DateTimeDateTimeOffset = DateTimeDateTimeOffset == default ? DateTimeOffset.Now : DateTimeDateTimeOffset;
+    }
+}
+
+
+ +

+<abp-date-picker auto-update-input="true" today-button-classes="btn-primary" asp-for="DateTimeDateTimeOffset"/>
+
+
+ +

+<div class="mb-3">
+    <label class="form-label" for="DateTimeDateTimeOffset">DateTimeDateTimeOffset</label>
+    <abp-date-picker data-today-button-classes="btn-primary" data-auto-update-input="true" data-date="2023-04-12T18:10:05.6171150+03:00">
+        <div class="input-group">
+            <input type="text" autocomplete="off" class="form-control">
+            <button type="button" tabindex="-1" data-type="open" class="btn btn-outline-secondary d-none" data-busy-text="Processing...">
+                <i class="fa fa-calendar"></i>
+            </button>
+            <button type="button" tabindex="-1" data-type="clear" class="btn btn-outline-secondary" data-busy-text="Processing...">
+                <i class="fa fa-times"></i>
+            </button>
+        </div><span class="text-danger col-auto field-validation-valid" data-valmsg-for="DateTimeDateTimeOffset" data-valmsg-replace="true"></span><input data-date="true" type="hidden" data-val="true" data-val-required="The DateTimeDateTimeOffset field is required." id="DateTimeDateTimeOffset" name="DateTimeDateTimeOffset" value="2023-04-12">
+    </abp-date-picker>
+</div>
+
+
+
+
+
+ +
+
+ +
+
+ + +

+public class DatePickerModel : PageModel
+{
+    [BindProperty]
+    public DateTimeOffset StartDateTimeOffset { get; set; }
+        
+    [BindProperty]
+    public DateTimeOffset EndDateTimeOffset { get; set; }
+
+    public void OnGet()
+    {
+        StartDateTimeOffset = StartDateTimeOffset == default ? DateTimeOffset.Now : StartDateTimeOffset;
+        EndDateTimeOffset = EndDateTimeOffset == default ? DateTimeOffset.Now : EndDateTimeOffset;
+    }
+}
+
+
+ +

+<abp-date-range-picker clear-button="false" asp-for-end="EndDateTimeOffset" asp-for-start="StartDateTimeOffset"/>
+
+
+ +

+<div class="mb-3">
+    <label class="form-label" for="StartDateTimeOffset">StartDateTimeOffset</label>
+    <abp-date-range-picker data-start-date="2023-04-12T18:11:50.9560980+03:00" data-end-date="2023-04-12T18:11:50.9560980+03:00">
+        <div class="input-group">
+            <input type="text" autocomplete="off" class="form-control">
+            <button type="button" tabindex="-1" data-type="open" class="btn btn-outline-secondary" data-busy-text="Processing...">
+                <i class="fa fa-calendar"></i>
+            </button>
+        </div><span class="text-danger col-auto field-validation-valid" data-valmsg-for="StartDateTimeOffset" data-valmsg-replace="true"></span><span class="text-danger col-auto field-validation-valid" data-valmsg-for="EndDateTimeOffset" data-valmsg-replace="true"></span><input data-start-date="true" type="hidden" data-val="true" data-val-required="The StartDateTimeOffset field is required." id="StartDateTimeOffset" name="StartDateTimeOffset" value="Wed Apr 12 2023 18:11:50 GMT+0300"><input data-end-date="true" type="hidden" data-val="true" data-val-required="The EndDateTimeOffset field is required." id="EndDateTimeOffset" name="EndDateTimeOffset" value="Wed Apr 12 2023 18:11:50 GMT+0300">
+    </abp-date-range-picker>
+</div>
+
+
+
+
+
+ +
+
+ +
+
+ + +

+public class DatePickerModel : PageModel
+{
+    [BindProperty]
+    public DateTimeOffset DateTimeDateTimeOffset { get; set; }
+}
+
+
+ +

+<abp-date-picker auto-update-input="true" today-button-classes="btn-primary" asp-for="NullableDateTimeDateTimeOffset"/>
+
+
+ +

+<div class="mb-3">
+    <label class="form-label" for="NullableDateTimeDateTimeOffset">NullableDateTimeDateTimeOffset</label>
+    <abp-date-picker data-today-button-classes="btn-primary" data-auto-update-input="true">
+        <div class="input-group">
+            <input type="text" autocomplete="off" class="form-control">
+            <button type="button" tabindex="-1" data-type="open" class="btn btn-outline-secondary d-none" data-busy-text="Processing...">
+                <i class="fa fa-calendar"></i>
+            </button>
+            <button type="button" tabindex="-1" data-type="clear" class="btn btn-outline-secondary" data-busy-text="Processing...">
+                <i class="fa fa-times"></i>
+            </button>
+        </div><span class="text-danger col-auto field-validation-valid" data-valmsg-for="NullableDateTimeDateTimeOffset" data-valmsg-replace="true"></span><input data-date="true" type="hidden" id="NullableDateTimeDateTimeOffset" name="NullableDateTimeDateTimeOffset" value="2023-04-12">
+    </abp-date-picker>
+</div>
+
+
+
+
+
+ +
+
+ +
+
+ + +

+public class DatePickerModel : PageModel
+{
+    [BindProperty]
+    public DateTimeOffset? NullableStartDateTimeOffset { get; set; }
+        
+    [BindProperty]
+    public DateTimeOffset? NullableEndDateTimeOffset { get; set; }
+}
+
+
+ +

+<abp-date-range-picker clear-button="false" asp-for-end="NullableEndDateTimeOffset" asp-for-start="NullableStartDateTimeOffset"/>
+
+
+ +

+<div class="mb-3">
+    <label class="form-label" for="NullableStartDateTimeOffset">NullableStartDateTimeOffset</label>
+    <abp-date-range-picker>
+        <div class="input-group">
+            <input type="text" autocomplete="off" class="form-control">
+            <button type="button" tabindex="-1" data-type="open" class="btn btn-outline-secondary" data-busy-text="Processing...">
+                <i class="fa fa-calendar"></i>
+            </button>
+        </div><span class="text-danger col-auto field-validation-valid" data-valmsg-for="NullableStartDateTimeOffset" data-valmsg-replace="true"></span><span class="text-danger col-auto field-validation-valid" data-valmsg-for="NullableEndDateTimeOffset" data-valmsg-replace="true"></span><input data-start-date="true" type="hidden" id="NullableStartDateTimeOffset" name="NullableStartDateTimeOffset" value=""><input data-end-date="true" type="hidden" id="NullableEndDateTimeOffset" name="NullableEndDateTimeOffset" value="">
+    </abp-date-range-picker>
+</div>
+
+
+
+
+
+ +
+
+ +
+
+ + +

+public class DatePickerModel : PageModel
+{
+    [BindProperty]
+    public string StringDate { get; set; }
+}
+
+
+ +

+<abp-date-picker auto-update-input="true" today-button-classes="btn-primary" asp-for="StringDate"/>
+
+
+ +

+<div class="mb-3">
+    <label class="form-label" for="StringDate">StringDate</label>
+    <abp-date-picker data-today-button-classes="btn-primary" data-auto-update-input="true">
+        <div class="input-group">
+            <input type="text" autocomplete="off" class="form-control">
+            <button type="button" tabindex="-1" data-type="open" class="btn btn-outline-secondary d-none" data-busy-text="Processing...">
+                <i class="fa fa-calendar"></i>
+            </button>
+            <button type="button" tabindex="-1" data-type="clear" class="btn btn-outline-secondary" data-busy-text="Processing...">
+                <i class="fa fa-times"></i>
+            </button>
+        </div><span class="text-danger col-auto field-validation-valid" data-valmsg-for="StringDate" data-valmsg-replace="true"></span><input data-date="true" type="hidden" id="StringDate" name="StringDate" value="2023-04-12">
+    </abp-date-picker>
+</div>
+
+
+
+
+
+ +
+
+ +
+
+ + +

+public class DatePickerModel : PageModel
+{
+   [BindProperty]
+    public string StringStartDate { get; set; }
+       
+    [BindProperty]
+    public string StringEndDate { get; set; }
+}
+
+
+ +

+<abp-date-range-picker clear-button="false" asp-for-end="StringEndDate" asp-for-start="StringStartDate"></abp-date-range-picker>
+
+
+ +

+<div class="mb-3">
+    <label class="form-label" for="StringStartDate">StringStartDate</label>
+    <abp-date-range-picker>
+        <div class="input-group">
+            <input type="text" autocomplete="off" class="form-control">
+            <button type="button" tabindex="-1" data-type="open" class="btn btn-outline-secondary" data-busy-text="Processing...">
+                <i class="fa fa-calendar"></i>
+            </button>
+        </div><span class="text-danger col-auto field-validation-valid" data-valmsg-for="StringStartDate" data-valmsg-replace="true"></span><span class="text-danger col-auto field-validation-valid" data-valmsg-for="StringEndDate" data-valmsg-replace="true"></span><input data-start-date="true" type="hidden" id="StringStartDate" name="StringStartDate" value=""><input data-end-date="true" type="hidden" id="StringEndDate" name="StringEndDate" value="">
+    </abp-date-range-picker>
+</div>
+
+
+
+
+
+ +

Dynamic Form

+ + +
+
+ + +
+
+ + +

+public class DatePickerModel : PageModel
+{
+   public class DynamicForm
+   {
+       [BindProperty]
+       [DateRangePicker("MyPicker",true)]
+       public DateTime StartDate { get; set; }
+       
+       [BindProperty]
+       [DateRangePicker("MyPicker",false)]
+       [DatePickerOptions(nameof(DatePickerOptions))]
+       public DateTime EndDate { get; set; }
+       
+       [BindProperty]
+       [DatePickerOptions(nameof(DatePickerOptions))]
+       public DateTime DateTime { get; set; }
+       
+       [BindProperty]
+       [DatePickerOptions(nameof(DatePickerOptions))]
+       [DateRangePicker("MyPicker2",true)]
+       public DateTime? NullableStartDate { get; set; }
+       [BindProperty]
+       [DateRangePicker("MyPicker2")]
+       public DateTime? NullableEndDate { get; set; }
+       
+       [BindProperty]
+       [DatePickerOptions(nameof(DatePickerOptions))]
+       public DateTime? NullableDateTime { get; set; }
+       
+       [BindProperty]
+       [DatePickerOptions(nameof(DatePickerOptions))]
+       [DateRangePicker("MyPicker3",true)]
+       public DateTimeOffset StartDateTimeOffset { get; set; }
+       
+       [BindProperty]
+       [DatePickerOptions(nameof(DatePickerOptions))]
+       [DateRangePicker("MyPicker3")]
+       public DateTimeOffset EndDateTimeOffset { get; set; }
+       
+       [BindProperty]
+       [DatePickerOptions(nameof(DatePickerOptions))]
+       public DateTimeOffset DateTimeDateTimeOffset { get; set; }
+       
+       [BindProperty]
+       [DatePickerOptions(nameof(DatePickerOptions))]
+       [DateRangePicker("MyPicker4",true)]
+       public DateTimeOffset? NullableStartDateTimeOffset { get; set; }
+       
+       [BindProperty]
+       [DatePickerOptions(nameof(DatePickerOptions))]
+       [DateRangePicker("MyPicker4")]
+       public DateTimeOffset? NullableEndDateTimeOffset { get; set; }
+       
+       [BindProperty]
+       [DatePickerOptions(nameof(DatePickerOptions))]
+       public DateTimeOffset? NullableDateTimeDateTimeOffset { get; set; }
+       
+       [BindProperty]
+       [DatePickerOptions(nameof(DatePickerOptions))]
+       [DateRangePicker("MyPicker5",true)]
+       public string StringStartDate { get; set; }
+       
+       [BindProperty]
+       [DatePickerOptions(nameof(DatePickerOptions))]
+       [DateRangePicker("MyPicker5")]
+       public string StringEndDate { get; set; }
+       
+       [BindProperty]
+       [DatePickerOptions(nameof(DatePickerOptions))]
+       [DatePicker]
+       public string StringDate { get; set; }
+   }
+   
+   public AbpDatePickerOptions DatePickerOptions { get; set; }
+   
+   [BindProperty]
+   public DynamicForm DynamicFormExample { get; set; }
+
+   public void OnGet()
+   {
+       DynamicFormExample ??= new DynamicForm
+       {
+           StartDate = DateTime.Now,
+           EndDate = DateTime.Now,
+           DateTime = DateTime.Now,
+           
+           StartDateTimeOffset = DateTimeOffset.Now,
+           EndDateTimeOffset = DateTimeOffset.Now,
+           DateTimeDateTimeOffset = DateTimeOffset.Now,
+       };
+
+       DatePickerOptions = new AbpDatePickerOptions();
+       DatePickerOptions.LinkedCalendars = false;
+       DatePickerOptions.Ranges = new List<AbpDatePickerRange>();
+       DatePickerOptions.Ranges.Add(new AbpDatePickerRange("Today", DateTime.Now, DateTime.Now));
+   }
+   
+   public void OnPost()
+   {
+       return;
+   }
+}
+
+
+ +

+<abp-dynamic-form abp-model="DynamicFormExample">
+</abp-dynamic-form>
+
+
+ +

+<form method="post" novalidate="novalidate">
+    <div class="row">
+        <div class="mb-3">
+            <label class="form-label" for="DynamicFormExample_StartDate">Start Date - End Date</label>
+            <abp-date-range-picker id="MyPicker" data-linked-calendars="false" data-ranges="{"Today":["2023-04-17T15:21:46.6586240+03:00","2023-04-17T15:21:46.6586240+03:00"]}" data-start-date="2023-04-17T15:21:46.6569460+03:00" data-end-date="2023-04-17T15:21:46.6570750+03:00">
+                <div class="input-group">
+                    <input type="text" autocomplete="off" class="form-control">
+                    <button type="button" tabindex="-1" data-type="clear" class="d-none btn btn-outline-secondary" data-busy-text="İşleniyor...">
+                        <ti class="fa fa-times"></i>
+                    </button>
+                    <button type="button" tabindex="-1" data-type="open" class="btn btn-outline-secondary" data-busy-text="İşleniyor...">
+                        <i class="fa fa-calendar"></i>
+                    </button>
+                </div><span class="text-danger col-auto field-validation-valid" data-valmsg-for="DynamicFormExample.StartDate" data-valmsg-replace="true"></span><span class="text-danger col-auto field-validation-valid" data-valmsg-for="DynamicFormExample.EndDate" data-valmsg-replace="true"></span><input data-start-date="true" type="hidden" data-val="true" data-val-required="The Start Date - End Date field is required." id="DynamicFormExample_StartDate" name="DynamicFormExample.StartDate" value="Mon Apr 17 2023 15:21:46 GMT+0300"><input data-end-date="true" type="hidden" data-val="true" data-val-required="The EndDate field is required." id="DynamicFormExample_EndDate" name="DynamicFormExample.EndDate" value="Mon Apr 17 2023 15:21:46 GMT+0300">
+            </abp-date-range-picker>
+        </div>
+        <div class="mb-3">
+            <label class="form-label" for="DynamicFormExample_NullableStartDate">Nullable Start Date - Nullable End Date</label>
+            <abp-date-range-picker id="MyPicker2" data-linked-calendars="false" data-ranges="{"Today":["2023-04-17T15:21:46.6586240+03:00","2023-04-17T15:21:46.6586240+03:00"]}">
+                <div class="input-group">
+                    <input type="text" autocomplete="off" class="form-control">
+                    <button type="button" tabindex="-1" data-type="clear" class="d-none btn btn-outline-secondary" data-busy-text="İşleniyor...">
+                        <i class="fa fa-times"></i>
+                    </button>
+                    <button type="button" tabindex="-1" data-type="open" class="btn btn-outline-secondary" data-busy-text="İşleniyor...">
+                        <i class="fa fa-calendar"></i>
+                    </button>
+                </div><span class="text-danger col-auto field-validation-valid" data-valmsg-for="DynamicFormExample.NullableStartDate" data-valmsg-replace="true"></span><span class="text-danger col-auto field-validation-valid" data-valmsg-for="DynamicFormExample.NullableEndDate" data-valmsg-replace="true"></span><input data-start-date="true" type="hidden" id="DynamicFormExample_NullableStartDate" name="DynamicFormExample.NullableStartDate" value=""><input data-end-date="true" type="hidden" id="DynamicFormExample_NullableEndDate" name="DynamicFormExample.NullableEndDate" value="">
+            </abp-date-range-picker>
+        </div>
+        <div class="mb-3">
+            <label class="form-label" for="DynamicFormExample_StartDateTimeOffset">Start DateTime Offset - End DateTime Offset</label>
+            <abp-date-range-picker id="MyPicker3" data-linked-calendars="false" data-ranges="{"Today":["2023-04-17T15:21:46.6586240+03:00","2023-04-17T15:21:46.6586240+03:00"]}" data-start-date="2023-04-17T15:21:46.6573400+03:00" data-end-date="2023-04-17T15:21:46.6574650+03:00">
+                <div class="input-group">
+                    <input type="text" autocomplete="off" class="form-control">
+                    <button type="button" tabindex="-1" data-type="clear" class="d-none btn btn-outline-secondary" data-busy-text="İşleniyor...">
+                        <i class="fa fa-times"></i>
+                    </button>
+                    <button type="button" tabindex="-1" data-type="open" class="btn btn-outline-secondary" data-busy-text="İşleniyor...">
+                        <i class="fa fa-calendar"></i>
+                    </button>
+                </div><span class="text-danger col-auto field-validation-valid" data-valmsg-for="DynamicFormExample.StartDateTimeOffset" data-valmsg-replace="true"></span><span class="text-danger col-auto field-validation-valid" data-valmsg-for="DynamicFormExample.EndDateTimeOffset" data-valmsg-replace="true"></span><input data-start-date="true" type="hidden" data-val="true" data-val-required="The Start DateTime Offset - End DateTime Offset field is required." id="DynamicFormExample_StartDateTimeOffset" name="DynamicFormExample.StartDateTimeOffset" value="Mon Apr 17 2023 15:21:46 GMT+0300"><input data-end-date="true" type="hidden" data-val="true" data-val-required="The EndDateTimeOffset field is required." id="DynamicFormExample_EndDateTimeOffset" name="DynamicFormExample.EndDateTimeOffset" value="Mon Apr 17 2023 15:21:46 GMT+0300">
+            </abp-date-range-picker>
+        </div>
+        <div class="mb-3">
+            <label class="form-label" for="DynamicFormExample_NullableStartDateTimeOffset">Nullable Start DateTime Offset - Nullable End DateTime Offset</label>
+            <abp-date-range-picker id="MyPicker4" data-linked-calendars="false" data-ranges="{"Today":["2023-04-17T15:21:46.6586240+03:00","2023-04-17T15:21:46.6586240+03:00"]}">
+                <div class="input-group">
+                    <input type="text" autocomplete="off" class="form-control">
+                    <button type="button" tabindex="-1" data-type="clear" class="d-none btn btn-outline-secondary" data-busy-text="İşleniyor...">
+                        <i class="fa fa-times"></i>
+                    </button>
+                    <button type="button" tabindex="-1" data-type="open" class="btn btn-outline-secondary" data-busy-text="İşleniyor...">
+                        <i class="fa fa-calendar"></i>
+                    </button>
+                </div><span class="text-danger col-auto field-validation-valid" data-valmsg-for="DynamicFormExample.NullableStartDateTimeOffset" data-valmsg-replace="true"></span><span class="text-danger col-auto field-validation-valid" data-valmsg-for="DynamicFormExample.NullableEndDateTimeOffset" data-valmsg-replace="true"></span><input data-start-date="true" type="hidden" id="DynamicFormExample_NullableStartDateTimeOffset" name="DynamicFormExample.NullableStartDateTimeOffset" value=""><input data-end-date="true" type="hidden" id="DynamicFormExample_NullableEndDateTimeOffset" name="DynamicFormExample.NullableEndDateTimeOffset" value="">
+            </abp-date-range-picker>
+        </div>
+        <div class="mb-3">
+            <label class="form-label" for="DynamicFormExample_StringStartDate">String Start Date - String End Date</label>
+            <abp-date-range-picker id="MyPicker5" data-linked-calendars="false" data-ranges="{"Today":["2023-04-17T15:21:46.6586240+03:00","2023-04-17T15:21:46.6586240+03:00"]}">
+                <div class="input-group">
+                    <input type="text" autocomplete="off" class="form-control">
+                    <button type="button" tabindex="-1" data-type="clear" class="d-none btn btn-outline-secondary" data-busy-text="İşleniyor...">
+                        <i class="fa fa-times"></i>
+                    </button>
+                    <button type="button" tabindex="-1" data-type="open" class="btn btn-outline-secondary" data-busy-text="İşleniyor...">
+                        <i class="fa fa-calendar"></i>
+                    </button>
+                </div><span class="text-danger col-auto field-validation-valid" data-valmsg-for="DynamicFormExample.StringStartDate" data-valmsg-replace="true"></span><span class="text-danger col-auto field-validation-valid" data-valmsg-for="DynamicFormExample.StringEndDate" data-valmsg-replace="true"></span><input data-start-date="true" type="hidden" id="DynamicFormExample_StringStartDate" name="DynamicFormExample.StringStartDate" value=""><input data-end-date="true" type="hidden" id="DynamicFormExample_StringEndDate" name="DynamicFormExample.StringEndDate" value="">
+            </abp-date-range-picker>
+        </div>
+        <div class="mb-3">
+            <label class="form-label" for="DynamicFormExample_DateTime">DateTime</label>
+            <abp-date-picker data-linked-calendars="false" data-ranges="{"Today":["2023-04-17T15:21:46.6586240+03:00","2023-04-17T15:21:46.6586240+03:00"]}" data-date="2023-04-17T15:21:46.6572040+03:00">
+                <div class="input-group">
+                    <input type="text" autocomplete="off" class="form-control">
+                    <button type="button" tabindex="-1" data-type="clear" class="d-none btn btn-outline-secondary" data-busy-text="İşleniyor...">
+                        <i class="fa fa-times"></i>
+                    </button>
+                    <button type="button" tabindex="-1" data-type="open" class="btn btn-outline-secondary" data-busy-text="İşleniyor...">
+                        <i class="fa fa-calendar"></i>
+                    </button>
+                </div><span class="text-danger col-auto field-validation-valid" data-valmsg-for="DynamicFormExample.DateTime" data-valmsg-replace="true"></span><input data-date="true" type="hidden" data-val="true" data-val-required="The DateTime field is required." id="DynamicFormExample_DateTime" name="DynamicFormExample.DateTime" value="Mon Apr 17 2023 15:21:46 GMT+0300">
+            </abp-date-picker>
+        </div>
+        <div class="mb-3">
+            <label class="form-label" for="DynamicFormExample_NullableDateTime">Nullable DateTime</label>
+            <abp-date-picker data-linked-calendars="false" data-ranges="{"Today":["2023-04-17T15:21:46.6586240+03:00","2023-04-17T15:21:46.6586240+03:00"]}">
+                <div class="input-group">
+                    <input type="text" autocomplete="off" class="form-control">
+                    <button type="button" tabindex="-1" data-type="clear" class="d-none btn btn-outline-secondary" data-busy-text="İşleniyor...">
+                        <i class="fa fa-times"></i>
+                    </button>
+                    <button type="button" tabindex="-1" data-type="open" class="btn btn-outline-secondary" data-busy-text="İşleniyor...">
+                        <i class="fa fa-calendar"></i>
+                    </button>
+                </div><span class="text-danger col-auto field-validation-valid" data-valmsg-for="DynamicFormExample.NullableDateTime" data-valmsg-replace="true"></span><input data-date="true" type="hidden" id="DynamicFormExample_NullableDateTime" name="DynamicFormExample.NullableDateTime" value="">
+            </abp-date-picker>
+        </div>
+        <div class="mb-3">
+            <label class="form-label" for="DynamicFormExample_DateTimeDateTimeOffset">DateTime DateTime Offset</label>
+            <abp-date-picker data-linked-calendars="false" data-ranges="{"Today":["2023-04-17T15:21:46.6586240+03:00","2023-04-17T15:21:46.6586240+03:00"]}" data-date="2023-04-17T15:21:46.6575990+03:00">
+                <div class="input-group">
+                    <input type="text" autocomplete="off" class="form-control">
+                    <button type="button" tabindex="-1" data-type="clear" class="d-none btn btn-outline-secondary" data-busy-text="İşleniyor...">
+                        <i class="fa fa-times"></i>
+                    </button>
+                    <button type="button" tabindex="-1" data-type="open" class="btn btn-outline-secondary" data-busy-text="İşleniyor...">
+                        <i class="fa fa-calendar"></i>
+                    </button>
+                </div><span class="text-danger col-auto field-validation-valid" data-valmsg-for="DynamicFormExample.DateTimeDateTimeOffset" data-valmsg-replace="true"></span><input data-date="true" type="hidden" data-val="true" data-val-required="The DateTime DateTime Offset field is required." id="DynamicFormExample_DateTimeDateTimeOffset" name="DynamicFormExample.DateTimeDateTimeOffset" value="Mon Apr 17 2023 15:21:46 GMT+0300">
+            </abp-date-picker>
+        </div>
+        <div class="mb-3">
+            <label class="form-label" for="DynamicFormExample_NullableDateTimeDateTimeOffset">Nullable DateTime DateTime Offset</label>
+            <abp-date-picker data-linked-calendars="false" data-ranges="{"Today":["2023-04-17T15:21:46.6586240+03:00","2023-04-17T15:21:46.6586240+03:00"]}">
+                <div class="input-group">
+                    <input type="text" autocomplete="off" class="form-control">
+                    <button type="button" tabindex="-1" data-type="clear" class="d-none btn btn-outline-secondary" data-busy-text="İşleniyor...">
+                        <i class="fa fa-times"></i>
+                    </button>
+                    <button type="button" tabindex="-1" data-type="open" class="btn btn-outline-secondary" data-busy-text="İşleniyor...">
+                        <i class="fa fa-calendar"></i>
+                    </button>
+                </div><span class="text-danger col-auto field-validation-valid" data-valmsg-for="DynamicFormExample.NullableDateTimeDateTimeOffset" data-valmsg-replace="true"></span><input data-date="true" type="hidden" id="DynamicFormExample_NullableDateTimeDateTimeOffset" name="DynamicFormExample.NullableDateTimeDateTimeOffset" value="">
+            </abp-date-picker>
+        </div>
+        <div class="mb-3">
+            <label class="form-label" for="DynamicFormExample_StringDate">String Date</label>
+            <abp-date-picker data-linked-calendars="false" data-ranges="{"Today":["2023-04-17T15:21:46.6586240+03:00","2023-04-17T15:21:46.6586240+03:00"]}">
+                <div class="input-group">
+                    <input type="text" autocomplete="off" class="form-control">
+                    <button type="button" tabindex="-1" data-type="clear" class="d-none btn btn-outline-secondary" data-busy-text="İşleniyor...">
+                        <i class="fa fa-times"></i>
+                    </button>
+                    <button type="button" tabindex="-1" data-type="open" class="btn btn-outline-secondary" data-busy-text="İşleniyor...">
+                        <i class="fa fa-calendar"></i>
+                    </button>
+                </div><span class="text-danger col-auto field-validation-valid" data-valmsg-for="DynamicFormExample.StringDate" data-valmsg-replace="true"></span><input data-date="true" type="hidden" id="DynamicFormExample_StringDate" name="DynamicFormExample.StringDate" value="">
+            </abp-date-picker>
+        </div>
+    </div>
+</form>
+
+
+
+
+
+ + + diff --git a/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/DatePicker.cshtml.cs b/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/DatePicker.cshtml.cs new file mode 100644 index 0000000000..c16bb876f4 --- /dev/null +++ b/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/DatePicker.cshtml.cs @@ -0,0 +1,182 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.RazorPages; +using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form.DatePicker; + +namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo.Pages.Components; + +public class DatePickerModel : PageModel +{ + + [BindProperty] + [DisplayName("Start Date - End Date")] + public DateTime StartDate { get; set; } + [BindProperty] + public DateTime EndDate { get; set; } + + [BindProperty] + public DateTime DateTime { get; set; } + + [BindProperty] + [DisplayName("Nullable Start Date - Nullable End Date")] + public DateTime? NullableStartDate { get; set; } + + [BindProperty] + public DateTime? NullableEndDate { get; set; } + + [BindProperty] + [DisplayName("Nullable DateTime")] + public DateTime? NullableDateTime { get; set; } + + [BindProperty] + [DisplayName("Start DateTime Offset - End DateTime Offset")] + public DateTimeOffset StartDateTimeOffset { get; set; } + + [BindProperty] + public DateTimeOffset EndDateTimeOffset { get; set; } + + [BindProperty] + [DisplayName("DateTime DateTime Offset")] + public DateTimeOffset DateTimeDateTimeOffset { get; set; } + + [BindProperty] + [DisplayName("Nullable Start DateTime Offset - Nullable End DateTime Offset")] + public DateTimeOffset? NullableStartDateTimeOffset { get; set; } + + [BindProperty] + public DateTimeOffset? NullableEndDateTimeOffset { get; set; } + + [BindProperty] + [DisplayName("Nullable DateTime DateTime Offset")] + public DateTimeOffset? NullableDateTimeDateTimeOffset { get; set; } + + [BindProperty] + [DisplayName("String Start Date - String End Date")] + public string StringStartDate { get; set; } + + [BindProperty] + public string StringEndDate { get; set; } + + [BindProperty] + [DisplayName("String Date")] + public string StringDate { get; set; } + + public class DynamicForm + { + [BindProperty] + [DateRangePicker("MyPicker",true)] + [DisplayName("Start Date - End Date")] + public DateTime StartDate { get; set; } + + [BindProperty] + [DateRangePicker("MyPicker",false)] + [DatePickerOptions(nameof(DatePickerOptions))] + public DateTime EndDate { get; set; } + + [BindProperty] + [DatePickerOptions(nameof(DatePickerOptions))] + public DateTime DateTime { get; set; } + + [BindProperty] + [DatePickerOptions(nameof(DatePickerOptions))] + [DateRangePicker("MyPicker2",true)] + [DisplayName("Nullable Start Date - Nullable End Date")] + public DateTime? NullableStartDate { get; set; } + [BindProperty] + [DateRangePicker("MyPicker2")] + public DateTime? NullableEndDate { get; set; } + + [BindProperty] + [DatePickerOptions(nameof(DatePickerOptions))] + [DisplayName("Nullable DateTime")] + public DateTime? NullableDateTime { get; set; } + + [BindProperty] + [DatePickerOptions(nameof(DatePickerOptions))] + [DateRangePicker("MyPicker3",true)] + [DisplayName("Start DateTime Offset - End DateTime Offset")] + public DateTimeOffset StartDateTimeOffset { get; set; } + + [BindProperty] + [DatePickerOptions(nameof(DatePickerOptions))] + [DateRangePicker("MyPicker3")] + public DateTimeOffset EndDateTimeOffset { get; set; } + + [BindProperty] + [DatePickerOptions(nameof(DatePickerOptions))] + [DisplayName("DateTime DateTime Offset")] + public DateTimeOffset DateTimeDateTimeOffset { get; set; } + + [BindProperty] + [DatePickerOptions(nameof(DatePickerOptions))] + [DateRangePicker("MyPicker4",true)] + [DisplayName("Nullable Start DateTime Offset - Nullable End DateTime Offset")] + public DateTimeOffset? NullableStartDateTimeOffset { get; set; } + + [BindProperty] + [DatePickerOptions(nameof(DatePickerOptions))] + [DateRangePicker("MyPicker4")] + public DateTimeOffset? NullableEndDateTimeOffset { get; set; } + + [BindProperty] + [DatePickerOptions(nameof(DatePickerOptions))] + [DisplayName("Nullable DateTime DateTime Offset")] + public DateTimeOffset? NullableDateTimeDateTimeOffset { get; set; } + + [BindProperty] + [DatePickerOptions(nameof(DatePickerOptions))] + [DateRangePicker("MyPicker5",true)] + [DisplayName("String Start Date - String End Date")] + public string StringStartDate { get; set; } + + [BindProperty] + [DatePickerOptions(nameof(DatePickerOptions))] + [DateRangePicker("MyPicker5")] + public string StringEndDate { get; set; } + + [BindProperty] + [DatePickerOptions(nameof(DatePickerOptions))] + [DatePicker] + [DisplayName("String Date")] + public string StringDate { get; set; } + } + + public AbpDatePickerOptions DatePickerOptions { get; set; } + + [BindProperty] + public DynamicForm DynamicFormExample { get; set; } + + public void OnGet() + { + StartDate = StartDate == default ? DateTime.Now : StartDate; + EndDate = EndDate == default ? DateTime.Now : EndDate; + DateTime = DateTime == default ? DateTime.Now : DateTime; + + StartDateTimeOffset = StartDateTimeOffset == default ? DateTimeOffset.Now : StartDateTimeOffset; + EndDateTimeOffset = EndDateTimeOffset == default ? DateTimeOffset.Now : EndDateTimeOffset; + DateTimeDateTimeOffset = DateTimeDateTimeOffset == default ? DateTimeOffset.Now : DateTimeDateTimeOffset; + + + DynamicFormExample ??= new DynamicForm { + StartDate = DateTime.Now, + EndDate = DateTime.Now, + DateTime = DateTime.Now, + StartDateTimeOffset = DateTimeOffset.Now, + EndDateTimeOffset = DateTimeOffset.Now, + DateTimeDateTimeOffset = DateTimeOffset.Now, + }; + + + DatePickerOptions = new AbpDatePickerOptions(); + DatePickerOptions.LinkedCalendars = false; + DatePickerOptions.Ranges = new List(); + DatePickerOptions.Ranges.Add(new AbpDatePickerRange("Today", DateTime.Now, DateTime.Now)); + } + + public void OnPost() + { + return; + } +} \ No newline at end of file diff --git a/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Index.cshtml b/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Index.cshtml index 6888267210..83c3847adb 100644 --- a/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Index.cshtml +++ b/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Index.cshtml @@ -17,6 +17,7 @@
  • Cards
  • Carousel
  • Collapse
  • +
  • Date Picker & Date Range Picker
  • Dropdowns
  • Dynamic Forms
  • Form Elements
  • diff --git a/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Menus/BootstrapDemoMenuContributor.cs b/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Menus/BootstrapDemoMenuContributor.cs index b6fce0dce0..ec707f1187 100644 --- a/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Menus/BootstrapDemoMenuContributor.cs +++ b/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Menus/BootstrapDemoMenuContributor.cs @@ -32,6 +32,7 @@ public class BootstrapDemoMenuContributor : IMenuContributor new ApplicationMenuItem(BootstrapDemoMenus.Components.Cards, "Cards", url: "/Components/Cards"), new ApplicationMenuItem(BootstrapDemoMenus.Components.Carousel, "Carousel", url: "/Components/Carousel"), new ApplicationMenuItem(BootstrapDemoMenus.Components.Collapse, "Collapse", url: "/Components/Collapse"), + new ApplicationMenuItem(BootstrapDemoMenus.Components.DatePicker, "Date Picker & Date Range Picker", url: "/Components/DatePicker"), new ApplicationMenuItem(BootstrapDemoMenus.Components.Dropdowns, "Dropdowns", url: "/Components/Dropdowns"), new ApplicationMenuItem(BootstrapDemoMenus.Components.DynamicForms, "Dynamic Forms", url: "/Components/DynamicForms"), new ApplicationMenuItem(BootstrapDemoMenus.Components.FormElements, "Form Elements", url: "/Components/FormElements"), diff --git a/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Menus/BootstrapDemoMenus.cs b/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Menus/BootstrapDemoMenus.cs index 4227c807c6..2f381221ed 100644 --- a/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Menus/BootstrapDemoMenus.cs +++ b/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Menus/BootstrapDemoMenus.cs @@ -17,6 +17,7 @@ public class BootstrapDemoMenus public const string Cards = Root + ".Cards"; public const string Carousel = Root + ".Carousel"; public const string Collapse = Root + ".Collapse"; + public const string DatePicker = Root + ".DatePicker"; public const string Dropdowns = Root + ".Dropdowns"; public const string DynamicForms = Root + ".DynamicForms"; public const string FormElements = Root + ".FormElements";