Components based on Bootstrap4 for Sections and TabStrip to increase productivity and promote uniformity in Module UIs (#333)
* upgrade to .NET Core 3.2 Preview 3 and fixes for issues created by #314 * Components based on Bootstrap4 for Sections and TabStrip to increase productivity and promote uniformity in Module UIs
This commit is contained in:
		| @ -5,80 +5,62 @@ | ||||
| @inject IModuleService ModuleService | ||||
| @inject IPageService PageService | ||||
|  | ||||
| <div class="container-fluid"> | ||||
|     <div class="form-group"> | ||||
|  | ||||
|         <ul class="nav nav-tabs" role="tablist"> | ||||
|             <li class="nav-item"> | ||||
|                 <a class="nav-link active" data-toggle="tab" href="#Pages" role="tab"> | ||||
|                     Pages | ||||
|                 </a> | ||||
|             </li> | ||||
|             <li class="nav-item"> | ||||
|                 <a class="nav-link" data-toggle="tab" href="#Modules" role="tab"> | ||||
|                     Modules | ||||
|                 </a> | ||||
|             </li> | ||||
|         </ul> | ||||
|  | ||||
|         <div class="tab-content"> | ||||
|             <div id="Pages" class="tab-pane fade show active" role="tabpanel"> | ||||
|                 @if (_pages == null) | ||||
|                 { | ||||
|                     <br /> | ||||
|                     <p>No Deleted Pages</p> | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     <Pager Items="@_pages"> | ||||
|                         <Header> | ||||
|                             <th> </th> | ||||
|                             <th> </th> | ||||
|                             <th>Name</th> | ||||
|                             <th>Deleted By</th> | ||||
|                             <th>Deleted On</th> | ||||
|                         </Header> | ||||
|                         <Row> | ||||
|                             <td><button @onclick="@(() => RestorePage(context))" class="btn btn-info" title="Restore">Restore</button></td> | ||||
|                             <td><ActionDialog Header="Delete Page" Message="@("Are You Sure You Wish To Permanently Delete The " + context.Name + " Page?")" Action="Delete" Security="SecurityAccessLevel.Admin" Class="btn btn-danger" OnClick="@(async () => await DeletePage(context))" /></td> | ||||
|                             <td>@context.Name</td> | ||||
|                             <td>@context.DeletedBy</td> | ||||
|                             <td>@context.DeletedOn</td> | ||||
|                         </Row> | ||||
|                     </Pager> | ||||
|                 } | ||||
|             </div> | ||||
|             <div id="Modules" class="tab-pane fade" role="tabpanel"> | ||||
|                 @if (_modules == null) | ||||
|                 { | ||||
|                     <br /> | ||||
|                     <p>No Deleted Modules</p> | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     <Pager Items="@_modules"> | ||||
|                         <Header> | ||||
|                             <th> </th> | ||||
|                             <th> </th> | ||||
|                             <th>Page</th> | ||||
|                             <th>Module</th> | ||||
|                             <th>Deleted By</th> | ||||
|                             <th>Deleted On</th> | ||||
|                         </Header> | ||||
|                         <Row> | ||||
|                             <td><button @onclick="@(() => RestoreModule(context))" class="btn btn-info" title="Restore">Restore</button></td> | ||||
|                             <td><ActionDialog Header="Delete Module" Message="@("Are You Sure You Wish To Permanently Delete The " + context.Title + " Module?")" Action="Delete" Security="SecurityAccessLevel.Admin" Class="btn btn-danger" OnClick="@(async () => await DeleteModule(context))" /></td> | ||||
|                             <td>@PageState.Pages.Find(item => item.PageId == context.PageId).Name</td> | ||||
|                             <td>@context.Title</td> | ||||
|                             <td>@context.DeletedBy</td> | ||||
|                             <td>@context.DeletedOn</td> | ||||
|                         </Row> | ||||
|                     </Pager> | ||||
|                 } | ||||
|             </div> | ||||
|         </div> | ||||
|     </div> | ||||
| </div> | ||||
| <TabStrip> | ||||
|     <TabPanel Name="Pages"> | ||||
|         @if (_pages == null) | ||||
|         { | ||||
|             <br /> | ||||
|             <p>No Deleted Pages</p> | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             <Pager Items="@_pages"> | ||||
|                 <Header> | ||||
|                     <th> </th> | ||||
|                     <th> </th> | ||||
|                     <th>Name</th> | ||||
|                     <th>Deleted By</th> | ||||
|                     <th>Deleted On</th> | ||||
|                 </Header> | ||||
|                 <Row> | ||||
|                     <td><button @onclick="@(() => RestorePage(context))" class="btn btn-info" title="Restore">Restore</button></td> | ||||
|                     <td><ActionDialog Header="Delete Page" Message="@("Are You Sure You Wish To Permanently Delete The " + context.Name + " Page?")" Action="Delete" Security="SecurityAccessLevel.Admin" Class="btn btn-danger" OnClick="@(async () => await DeletePage(context))" /></td> | ||||
|                     <td>@context.Name</td> | ||||
|                     <td>@context.DeletedBy</td> | ||||
|                     <td>@context.DeletedOn</td> | ||||
|                 </Row> | ||||
|             </Pager> | ||||
|         } | ||||
|     </TabPanel> | ||||
|     <TabPanel Name="Modules"> | ||||
|         @if (_modules == null) | ||||
|         { | ||||
|             <br /> | ||||
|             <p>No Deleted Modules</p> | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             <Pager Items="@_modules"> | ||||
|                 <Header> | ||||
|                     <th> </th> | ||||
|                     <th> </th> | ||||
|                     <th>Page</th> | ||||
|                     <th>Module</th> | ||||
|                     <th>Deleted By</th> | ||||
|                     <th>Deleted On</th> | ||||
|                 </Header> | ||||
|                 <Row> | ||||
|                     <td><button @onclick="@(() => RestoreModule(context))" class="btn btn-info" title="Restore">Restore</button></td> | ||||
|                     <td><ActionDialog Header="Delete Module" Message="@("Are You Sure You Wish To Permanently Delete The " + context.Title + " Module?")" Action="Delete" Security="SecurityAccessLevel.Admin" Class="btn btn-danger" OnClick="@(async () => await DeleteModule(context))" /></td> | ||||
|                     <td>@PageState.Pages.Find(item => item.PageId == context.PageId).Name</td> | ||||
|                     <td>@context.Title</td> | ||||
|                     <td>@context.DeletedBy</td> | ||||
|                     <td>@context.DeletedOn</td> | ||||
|                 </Row> | ||||
|             </Pager> | ||||
|         } | ||||
|     </TabPanel> | ||||
| </TabStrip> | ||||
|  | ||||
| @code { | ||||
|     private List<Page> _pages; | ||||
|  | ||||
| @ -123,10 +123,7 @@ | ||||
|         </tr> | ||||
|     </table> | ||||
|  | ||||
|     <a data-toggle="collapse" class="app-link-unstyled" href="#SMTP" aria-expanded="false" aria-controls="SMTP"> | ||||
|         <h5><i class="oi oi-chevron-bottom"></i> SMTP Settings</h5><hr class="app-rule" /> | ||||
|     </a> | ||||
|     <div class="collapse" id="SMTP"> | ||||
|     <Section Name="SMTP" Heading="SMTP Settings"> | ||||
|         <table class="table table-borderless"> | ||||
|             <tr> | ||||
|                 <td> | ||||
| @ -169,12 +166,8 @@ | ||||
|                 </td> | ||||
|             </tr> | ||||
|         </table> | ||||
|     </div> | ||||
|  | ||||
|     <a data-toggle="collapse" class="app-link-unstyled" href="#PWA" aria-expanded="false" aria-controls="PWA"> | ||||
|         <h5><i class="oi oi-chevron-bottom"></i> Progressive Web Application Settings</h5><hr class="app-rule" /> | ||||
|     </a> | ||||
|     <div class="collapse" id="PWA"> | ||||
|     </Section> | ||||
|     <Section Name="PWA" Heading="Progressive Web Application Settings"> | ||||
|         <table class="table table-borderless"> | ||||
|             <tr> | ||||
|                 <td> | ||||
| @ -203,9 +196,8 @@ | ||||
|                     <FileManager FileId="@_pwasplashiconfileid.ToString()" Filter="png" @ref="_pwasplashiconfilemanager" /> | ||||
|                 </td> | ||||
|             </tr> | ||||
|  | ||||
|         </table> | ||||
|     </div> | ||||
|     </Section> | ||||
|  | ||||
|     <br /> | ||||
|     <button type="button" class="btn btn-success" @onclick="SaveSite">Save</button> | ||||
|  | ||||
| @ -15,7 +15,7 @@ else | ||||
|     private string _closeLabel = "</label>"; | ||||
|  | ||||
|     [Parameter] | ||||
|     public RenderFragment ChildContent { get; set; } // required - the title of the label | ||||
|     public RenderFragment ChildContent { get; set; }  | ||||
|  | ||||
|     [Parameter] | ||||
|     public string For { get; set; } // optional - the id of the associated input control for accessibility | ||||
|  | ||||
							
								
								
									
										44
									
								
								Oqtane.Client/Modules/Controls/Section.razor
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								Oqtane.Client/Modules/Controls/Section.razor
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,44 @@ | ||||
| @namespace Oqtane.Modules.Controls | ||||
| @inherits ModuleBase | ||||
|  | ||||
| <div class="d-flex"> | ||||
|     <div> | ||||
|         <a data-toggle="collapse" class="app-link-unstyled" href="#@Name" aria-expanded="@_expanded" aria-controls="@Name"> | ||||
|             <h5>@_heading</h5> | ||||
|         </a> | ||||
|     </div> | ||||
|     <div class="ml-auto"> | ||||
|         <a data-toggle="collapse" class="app-link-unstyled float-right" href="#@Name" aria-expanded="@_expanded" aria-controls="@Name"> | ||||
|             <i class="oi oi-chevron-bottom"></i>  | ||||
|         </a> | ||||
|     </div> | ||||
| </div> | ||||
| <div class="d-flex"> | ||||
|     <hr class="app-rule" /> | ||||
| </div> | ||||
| <div class="collapse" id="@Name"> | ||||
|     @ChildContent | ||||
| </div> | ||||
|  | ||||
| @code { | ||||
|     private string _heading = string.Empty; | ||||
|     private string _expanded = string.Empty; | ||||
|  | ||||
|     [Parameter] | ||||
|     public RenderFragment ChildContent { get; set; } | ||||
|  | ||||
|     [Parameter] | ||||
|     public string Name { get; set; } // required - the name of the section | ||||
|  | ||||
|     [Parameter] | ||||
|     public string Heading { get; set; } // optional - will default to Name if not provided | ||||
|  | ||||
|     [Parameter] | ||||
|     public string Expanded { get; set; } // optional - will default to false if not provided | ||||
|  | ||||
|     protected override void OnInitialized() | ||||
|     { | ||||
|         _heading = (!string.IsNullOrEmpty(Heading)) ? Heading : Name; | ||||
|         _expanded = (!string.IsNullOrEmpty(Expanded)) ? Expanded : "false"; | ||||
|     } | ||||
| } | ||||
| @ -1,44 +0,0 @@ | ||||
| @namespace Oqtane.Modules.Controls | ||||
| @inherits ModuleBase | ||||
|  | ||||
| <CascadingValue Value="this"> | ||||
|     <div> | ||||
|         @foreach (TabPanel tabPanel in _tabPanels) | ||||
|         { | ||||
|             <button type="button" | ||||
|                     class="btn @GetButtonClass(tabPanel)" | ||||
|                     @onclick=@( () => ActivateTabPanel(tabPanel) )> | ||||
|                 @tabPanel.Text | ||||
|             </button> | ||||
|         } | ||||
|     </div> | ||||
|     @ChildContent | ||||
| </CascadingValue> | ||||
|  | ||||
| @code { | ||||
|     private List<TabPanel> _tabPanels = new List<TabPanel>(); | ||||
|  | ||||
|     // Next line is needed so we are able to add <TabPanel> components inside | ||||
|     [Parameter] | ||||
|     public RenderFragment ChildContent { get; set; } | ||||
|  | ||||
|     public TabPanel ActiveTabPanel { get; set; } | ||||
|  | ||||
|     internal void AddTabPanel(TabPanel tabPanel) | ||||
|     { | ||||
|         _tabPanels.Add(tabPanel); | ||||
|         if (_tabPanels.Count == 1) | ||||
|             ActiveTabPanel = tabPanel; | ||||
|         StateHasChanged(); | ||||
|     } | ||||
|  | ||||
|     private string GetButtonClass(TabPanel tabPanel) | ||||
|         => tabPanel == ActiveTabPanel | ||||
|         ? "btn-primary" | ||||
|         : "btn-secondary"; | ||||
|  | ||||
|     private void ActivateTabPanel(TabPanel tabPanel) | ||||
|     { | ||||
|         ActiveTabPanel = tabPanel; | ||||
|     } | ||||
| } | ||||
| @ -1,27 +1,35 @@ | ||||
| @namespace Oqtane.Modules.Controls | ||||
| @inherits ModuleBase | ||||
|  | ||||
| @if (Parent.ActiveTabPanel == (TabPanel)(object)this) | ||||
| @if (Name == Parent.ActiveTab) | ||||
| { | ||||
|     @ChildContent | ||||
|     <div id="@Name" class="tab-pane fade show active" role="tabpanel"> | ||||
|         @ChildContent | ||||
|     </div> | ||||
| } | ||||
| else | ||||
| { | ||||
|     <div id="@Name" class="tab-pane fade" role="tabpanel"> | ||||
|         @ChildContent | ||||
|     </div> | ||||
| } | ||||
|  | ||||
| @code { | ||||
|     [CascadingParameter] | ||||
|     private TabControl Parent { get; set; } | ||||
|     private TabStrip Parent { get; set; } | ||||
|  | ||||
|     [Parameter] | ||||
|     public RenderFragment ChildContent { get; set; } | ||||
|  | ||||
|     [Parameter] | ||||
|     public string Text { get; set; } | ||||
|     public string Name { get; set; } // required - name of the TabPanel | ||||
|  | ||||
|     [Parameter] | ||||
|     public string Heading { get; set; } // optional - defaults to name if not specified | ||||
|  | ||||
|     protected override void OnInitialized() | ||||
|     { | ||||
|         if (Parent == null) | ||||
|             throw new ArgumentNullException(nameof(Parent), "TabPanel must exist within a TabControl"); | ||||
|  | ||||
|         base.OnInitialized(); | ||||
|         Parent.AddTabPanel((TabPanel)(object)this); | ||||
|         Parent.AddTabPanel((TabPanel)this); | ||||
|     } | ||||
| } | ||||
|  | ||||
							
								
								
									
										56
									
								
								Oqtane.Client/Modules/Controls/TabStrip.razor
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								Oqtane.Client/Modules/Controls/TabStrip.razor
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,56 @@ | ||||
| @namespace Oqtane.Modules.Controls | ||||
| @inherits ModuleBase | ||||
|  | ||||
| <CascadingValue Value="this"> | ||||
|     <div class="container-fluid"> | ||||
|         <div class="form-group"> | ||||
|             <ul class="nav nav-tabs" role="tablist"> | ||||
|                 @foreach (TabPanel tabPanel in _tabPanels) | ||||
|                 { | ||||
|                     <li class="nav-item"> | ||||
|                         @if (tabPanel.Name == ActiveTab) | ||||
|                         { | ||||
|                             <a class="nav-link active" data-toggle="tab" href="#@tabPanel.Name" role="tab"> | ||||
|                                 @DisplayHeading(tabPanel.Name, tabPanel.Heading) | ||||
|                             </a> | ||||
|                         } | ||||
|                         else | ||||
|                         { | ||||
|                             <a class="nav-link" data-toggle="tab" href="#@tabPanel.Name" role="tab"> | ||||
|                                 @DisplayHeading(tabPanel.Name, tabPanel.Heading) | ||||
|                             </a> | ||||
|                         } | ||||
|                     </li> | ||||
|                 } | ||||
|             </ul> | ||||
|             <div class="tab-content"> | ||||
|                 <br /> | ||||
|                 @ChildContent | ||||
|             </div> | ||||
|         </div> | ||||
|     </div> | ||||
| </CascadingValue> | ||||
|  | ||||
| @code { | ||||
|     private List<TabPanel> _tabPanels = new List<TabPanel>(); | ||||
|  | ||||
|     [Parameter] | ||||
|     public RenderFragment ChildContent { get; set; } // contains the TabPanels | ||||
|  | ||||
|     [Parameter] | ||||
|     public string ActiveTab { get; set; } // optional - defaults to first TabPanel if not specified | ||||
|  | ||||
|     internal void AddTabPanel(TabPanel tabPanel) | ||||
|     { | ||||
|         _tabPanels.Add(tabPanel); | ||||
|         if (string.IsNullOrEmpty(ActiveTab)) | ||||
|         { | ||||
|             ActiveTab = tabPanel.Name; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private string DisplayHeading(string Name, string Heading) | ||||
|     { | ||||
|         return (string.IsNullOrEmpty(Heading)) ? Name : Heading; | ||||
|     } | ||||
| } | ||||
		Reference in New Issue
	
	Block a user
	 Shaun Walker
					Shaun Walker