Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/BootstrapBlazor.Server/BootstrapBlazor.Server.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
<PackageReference Include="BootstrapBlazor.BaiduOcr" Version="9.0.0" />
<PackageReference Include="BootstrapBlazor.BarCode" Version="9.0.0" />
<PackageReference Include="BootstrapBlazor.BarcodeGenerator" Version="9.0.0" />
<PackageReference Include="BootstrapBlazor.BootstrapIcon" Version="9.0.1" />
<PackageReference Include="BootstrapBlazor.BootstrapIcon" Version="9.0.2" />
<PackageReference Include="BootstrapBlazor.Chart" Version="9.0.0" />
<PackageReference Include="BootstrapBlazor.CherryMarkdown" Version="9.0.0" />
<PackageReference Include="BootstrapBlazor.Dock" Version="9.0.0" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
</div>

<div class="tabs-coms">
<Tab IsBorderCard="true" IsLazyLoadTabItem="true" ShowFullScreen="true" TabStyle="TabStyle.Chrome" @ref="Tab">
<Tab IsBorderCard="true" IsLazyLoadTabItem="true" ShowFullScreen="true" TabStyle="TabStyle.Chrome" ShowToolbar="true" @ref="Tab">
<TabItem Text="Example" Icon="fa-solid fa-desktop">
<CascadingValue Value="@RazorFileName" Name="RazorFileName">
@Body
Expand Down
21 changes: 18 additions & 3 deletions src/BootstrapBlazor.Server/Components/Samples/Tabs.razor
Original file line number Diff line number Diff line change
Expand Up @@ -423,7 +423,21 @@ private void Navigation()
</DemoBlock>

<DemoBlock Title="@Localizer["TabsDragTitle"]" Introduction="@Localizer["TabsDragIntro"]" Name="AllowDrag">
<Tab IsBorderCard="true" AllowDrag="true">
<Tab IsBorderCard="true" AllowDrag="true" ShowToolbar="true">
<TabItem Text="@Localizer["TabItem1Text"]">
<div>@Localizer["TabItem1Content"]</div>
</TabItem>
<TabItem Text="@Localizer["TabItem2Text"]">
<div>@Localizer["TabItem2Content"]</div>
</TabItem>
<TabItem Text="@Localizer["TabItem3Text"]">
<div>@Localizer["TabItem3Content"]</div>
</TabItem>
</Tab>
</DemoBlock>

<DemoBlock Title="@Localizer["TabsDragTitle"]" Introduction="@Localizer["TabsDragIntro"]" Name="AllowDrag">
<Tab IsBorderCard="true" AllowDrag="true" ShowToolbar="true">
<TabItem Text="@Localizer["TabItem1Text"]">
<div>@Localizer["TabItem1Content"]</div>
</TabItem>
Expand All @@ -437,7 +451,7 @@ private void Navigation()
</DemoBlock>

<DemoBlock Title="@Localizer["TabsChromeStyleTitle"]" Introduction="@Localizer["TabsChromeStyleIntro"]" Name="Chrome">
<Tab IsCard="true" ShowClose="true" TabStyle="TabStyle.Chrome" AllowDrag="true">
<Tab IsCard="true" ShowClose="true" TabStyle="TabStyle.Chrome" AllowDrag="true" ShowToolbar="true">
<TabItem Text="@Localizer["TabItem1Text"]" Icon="fa-solid fa-user">
<div>@Localizer["TabItem1Content"]</div>
</TabItem>
Expand All @@ -454,9 +468,10 @@ private void Navigation()
</DemoBlock>

<DemoBlock Title="@Localizer["TabsCapsuleStyleTitle"]" Introduction="@Localizer["TabsCapsuleStyleIntro"]" Name="Capsule">
<Tab IsCard="true" ShowClose="true" TabStyle="TabStyle.Capsule" AllowDrag="true">
<Tab IsCard="true" ShowClose="true" TabStyle="TabStyle.Capsule" AllowDrag="true" ShowToolbar="true">
<TabItem Text="@Localizer["TabItem1Text"]" Icon="fa-solid fa-user">
<div>@Localizer["TabItem1Content"]</div>
<Counter></Counter>
</TabItem>
<TabItem Text="@Localizer["TabItem2Text"]" Icon="fa-solid fa-gauge-high">
<div>@Localizer["TabItem2Content"]</div>
Expand Down
2 changes: 1 addition & 1 deletion src/BootstrapBlazor/BootstrapBlazor.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk.Razor">

<PropertyGroup>
<Version>9.5.0-beta10</Version>
<Version>9.5.0-beta11</Version>
</PropertyGroup>

<ItemGroup>
Expand Down
35 changes: 25 additions & 10 deletions src/BootstrapBlazor/Components/Tab/Tab.razor
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,11 @@ else
}
else if (item.IsDisabled)
{
@RenderDisabledHeader(item)
@RenderDisabledHeaderItem(item)
}
else
{
@RenderHeader(item)
@RenderHeaderItem(item)
}
}
@if (IsCard || IsBorderCard)
Expand All @@ -73,6 +73,23 @@ else
{
@ButtonTemplate
}
@if (ShowToolbar)
{
<div class="tabs-nav-toolbar">
@if (ShowRefreshToolbarButton)
{
<div class="tabs-nav-toolbar-button tabs-nav-toolbar-refresh">
<TabToolbarRefreshButton Icon="@RefreshToolbarButtonIcon" OnClickAsync="OnRefreshAsync"></TabToolbarRefreshButton>
</div>
}
@if (ShowFullscreenToolbarButton)
{
<div class="tabs-nav-toolbar-button tabs-nav-toolbar-fs">
<FullScreenButton TargetId="@Id"></FullScreenButton>
</div>
}
</div>
}
@if (ShowNavigatorButtons)
{
<div class="nav-link-bar right" @onclick="@ClickNextTab"><i class="@NextIcon"></i></div>
Expand Down Expand Up @@ -108,9 +125,7 @@ else
{
foreach (var item in Items)
{
<div @key="@item" class="@GetContentClassString(item)" id="@GetIdByTabItem(item)">
@RenderTabItem(item)
</div>
@RenderTabItem(item)
}
}
</CascadingValue>
Expand All @@ -124,10 +139,10 @@ else
@RenderTabItemContent(item)
</CascadingValue>;

RenderFragment RenderDisabledHeader(TabItem item) =>
RenderFragment RenderDisabledHeaderItem(TabItem item) =>
@<div @key="@item" class="@GetItemWrapClassString(item)">
<div role="tab" class="@GetClassString(item)">
@RenderHeaderContent(item)
@RenderHeaderItemContent(item)
</div>
@if (TabStyle == TabStyle.Chrome)
{
Expand All @@ -136,10 +151,10 @@ else
}
</div>;

RenderFragment RenderHeader(TabItem item) =>
RenderFragment RenderHeaderItem(TabItem item) =>
@<div @key="@item" class="@GetItemWrapClassString(item)" draggable="@DraggableString">
<a href="@item.Url" role="tab" tabindex="-1" class="@GetClassString(item)" @onclick="@(() => OnClickTabItem(item))" @onclick:preventDefault="@(!ClickTabToNavigation)">
@RenderHeaderContent(item)
@RenderHeaderItemContent(item)
</a>
@if (TabStyle == TabStyle.Chrome)
{
Expand All @@ -148,7 +163,7 @@ else
}
</div>;

RenderFragment RenderHeaderContent(TabItem item) =>
RenderFragment RenderHeaderItemContent(TabItem item) =>
@<div class="tabs-item-body">
@if (!string.IsNullOrEmpty(item.Icon))
{
Expand Down
68 changes: 53 additions & 15 deletions src/BootstrapBlazor/Components/Tab/Tab.razor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,22 +10,18 @@
namespace BootstrapBlazor.Components;

/// <summary>
/// Tab 组件
/// Tab component
/// </summary>
public partial class Tab : IHandlerException
{
private bool FirstRender { get; set; } = true;

private static string? GetContentClassString(TabItem item) => CssBuilder.Default("tabs-body-content")
.AddClass("d-none", !item.IsActive)
.Build();

private string? WrapClassString => CssBuilder.Default("tabs-nav-wrap")
.AddClass("extend", ShouldShowExtendButtons())
.Build();

private static string? GetItemWrapClassString(TabItem item) => CssBuilder.Default("tabs-item-wrap")
.AddClass("active", item.IsActive && !item.IsDisabled)
.AddClass("active", item is { IsActive: true, IsDisabled: false })
.Build();

private string? GetClassString(TabItem item) => CssBuilder.Default("tabs-item")
Expand Down Expand Up @@ -58,25 +54,25 @@ public partial class Tab : IHandlerException
private readonly List<TabItem> _draggedItems = new(50);

/// <summary>
/// 获得/设置 TabItem 集合
/// Gets the collection of tab items.
/// </summary>
public IEnumerable<TabItem> Items => TabItems;

private List<TabItem> TabItems => _dragged ? _draggedItems : _items;

/// <summary>
/// 获得/设置 是否为排除地址 默认 false
/// Gets or sets the excluded link. Default is false.
/// </summary>
private bool Excluded { get; set; }

/// <summary>
/// 获得/设置 是否为卡片样式 默认 false
/// Gets or sets whether card style. Default is false.
/// </summary>
[Parameter]
public bool IsCard { get; set; }

/// <summary>
/// 获得/设置 是否为带边框卡片样式 默认 false
/// Gets or sets whether border card style. Default is false.
/// </summary>
[Parameter]
public bool IsBorderCard { get; set; }
Expand Down Expand Up @@ -294,6 +290,30 @@ public partial class Tab : IHandlerException
[Parameter]
public TabStyle TabStyle { get; set; }

/// <summary>
/// Gets or sets whether show the toolbar. Default is false.
/// </summary>
[Parameter]
public bool ShowToolbar { get; set; }

/// <summary>
/// Gets or sets whether show the full screen button. Default is true.
/// </summary>
[Parameter]
public bool ShowFullscreenToolbarButton { get; set; } = true;

/// <summary>
/// Gets or sets whether show the full screen button. Default is true.
/// </summary>
[Parameter]
public bool ShowRefreshToolbarButton { get; set; } = true;

/// <summary>
/// Gets or sets the refresh toolbar button icon string. Default is null.
/// </summary>
[Parameter]
public string? RefreshToolbarButtonIcon { get; set; }

[CascadingParameter]
private Layout? Layout { get; set; }

Expand Down Expand Up @@ -330,6 +350,8 @@ public partial class Tab : IHandlerException

private string? DraggableString => AllowDrag ? "true" : null;

private readonly ConcurrentDictionary<TabItem, TabItemContent> _cache = [];

/// <summary>
/// <inheritdoc/>
/// </summary>
Expand Down Expand Up @@ -360,8 +382,16 @@ protected override void OnParametersSet()
NextIcon ??= IconTheme.GetIconByKey(ComponentIcons.TabNextIcon);
DropdownIcon ??= IconTheme.GetIconByKey(ComponentIcons.TabDropdownIcon);
CloseIcon ??= IconTheme.GetIconByKey(ComponentIcons.TabCloseIcon);
RefreshToolbarButtonIcon ??= IconTheme.GetIconByKey(ComponentIcons.TabRefreshButtonIcon);

AdditionalAssemblies ??= new[] { Assembly.GetEntryAssembly()! };
if (AdditionalAssemblies is null)
{
var entryAssembly = Assembly.GetEntryAssembly();
if (entryAssembly is not null)
{
AdditionalAssemblies = [entryAssembly];
}
}

if (Placement != Placement.Top && TabStyle == TabStyle.Chrome)
{
Expand Down Expand Up @@ -805,7 +835,7 @@ public void SetDisabledItem(TabItem item, bool disabled)
}
if (TabItems.Any(i => i.IsActive) == false)
{
TabItems.Where(i => !i.IsDisabled).FirstOrDefault()?.SetActive(true);
TabItems.FirstOrDefault(i => !i.IsDisabled)?.SetActive(true);
}
StateHasChanged();
}
Expand All @@ -819,15 +849,15 @@ private RenderFragment RenderTabItemContent(TabItem item) => builder =>

if (item.IsActive)
{
builder.AddContent(0, item.ChildContent);
builder.AddContent(0, item.RenderContent(_cache));
if (IsLazyLoadTabItem)
{
LazyTabCache.AddOrUpdate(item, _ => true, (_, _) => true);
}
}
else if (!IsLazyLoadTabItem || item.AlwaysLoad || LazyTabCache.TryGetValue(item, out var init) && init)
{
builder.AddContent(0, item.ChildContent);
builder.AddContent(0, item.RenderContent(_cache));
}
};

Expand Down Expand Up @@ -876,7 +906,15 @@ public async Task DragItemCallback(int originIndex, int currentIndex)
}
}

private string? GetIdByTabItem(TabItem item) => (ShowFullScreen && item.ShowFullScreen) ? ComponentIdGenerator.Generate(item) : null;
private string? GetIdByTabItem(TabItem item) => ComponentIdGenerator.Generate(item);

private Task OnRefreshAsync()
{
// refresh the active tab item
var item = TabItems.FirstOrDefault(i => i.IsActive);
item.Refresh(_cache);
return Task.CompletedTask;
}

/// <summary>
/// <inheritdoc/>
Expand Down
47 changes: 47 additions & 0 deletions src/BootstrapBlazor/Components/Tab/Tab.razor.scss
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,7 @@
}

.tabs .tabs-body {
background-color: var(--bs-body-bg);
padding: var(--bb-tabs-body-padding);
flex: 1;
}
Expand Down Expand Up @@ -232,6 +233,8 @@
.tabs .tabs-item-fix {
height: 100%;
flex: 1;
width: 1%;
min-width: 0;
border: 1px solid var(--bs-border-color);
border-width: 0 0 1px 0;
}
Expand Down Expand Up @@ -643,3 +646,47 @@
}
}
}

.tabs {
&:not(.tabs-vertical) > .tabs-header .tabs-nav-toolbar {
display: flex;
}

&.tabs-bottom > .tabs-header {
.tabs-nav-toolbar {
border-top: 1px solid var(--bs-border-color);
}
}

&:not(.tabs-bottom) > .tabs-header {
.tabs-nav-toolbar {
border-bottom: 1px solid var(--bs-border-color);
}
}

> .tabs-header {
.tabs-nav-toolbar {
display: none;
align-items: center;
height: 100%;
padding: 3px 0.5rem;

.tabs-nav-toolbar-button {
cursor: pointer;
padding: 0 .75rem;
height: 100%;
display: flex;
align-items: center;
border-radius: var(--bs-border-radius);

&:not(.disabled):not(:disabled):hover {
background-color: var(--bb-tabs-item-hover-bg-color);
}

.btn {
padding: 0;
}
}
}
}
}
Loading