Skip to content

Commit

Permalink
New default UI for toasts (#181)
Browse files Browse the repository at this point in the history
  • Loading branch information
chrissainty authored Jan 4, 2023
1 parent 4f98e1e commit 634f559
Show file tree
Hide file tree
Showing 32 changed files with 663 additions and 957 deletions.
3 changes: 1 addition & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@
##
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore

# Custom
src/Blazored.Toast/wwwroot/*.css
.DS_Store

# User-specific files
*.suo
Expand Down
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,10 +68,11 @@ Toasts are configured using parameters on the `<BlazoredToasts />` component. Th
- ShowCloseButton (Default: true)
- CloseButtonContent (provide custom close button)
- MaxToastCount (Default: `int.MaxValue`)
- RemoveToastsOnNavigation (Default: false)

By default, you don't need to provide any settings everything will just work. But if you want to add icons to toasts or override the default styling then you can use the options above to do that.

For example, to add an icon from Font Awesome to all success toasts you can do the following.
For example, to add an icon from Font Awesome to all success toasts you can do the following:

```html
<BlazoredToasts SuccessIcon="fa fa-thumbs-up"/>
Expand Down
8 changes: 4 additions & 4 deletions samples/BlazorServer/Pages/Index.razor
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,19 @@
<h1>Blazored Toasts</h1>

<button class="btn btn-info" @onclick="@(() => toastService.ShowInfo("I'm an INFO message"))">Info Toast</button>
<button class="btn btn-success" @onclick="@(() => toastService.ShowSuccess("I'm a SUCCESS message with a custom heading", "Congratulations!"))">Success Toast</button>
<button class="btn btn-success" @onclick="@(() => toastService.ShowSuccess("I'm a SUCCESS message with a custom heading"))">Success Toast</button>
<button class="btn btn-warning" @onclick="@(() => toastService.ShowWarning("I'm a WARNING message"))">Warning Toast</button>
<button class="btn btn-danger" @onclick="@(() => toastService.ShowError("I'm an ERROR message"))">Error Toast</button>
<button class="btn btn-info" @onclick="@OnShowHtml">Info Toast with HTML</button>
<button class="btn btn-info" @onclick="@(() => toastService.ShowInfo("Click to refresh the page", "Click me!", () => { NavigationManager.NavigateTo("/", true); }))">
<button class="btn btn-info" @onclick="@(() => toastService.ShowInfo("Click to refresh the page", options => options.OnClick = () => NavigationManager.NavigateTo("/", true)))">
Info Toast with custom action on click
</button>
<hr />

<h1>Blazored Toasts - Custom Component</h1>

<button class="btn btn-primary" @onclick="@(() => toastService.ShowToast<MyToastComponent>(new ToastInstanceSettings(5, true)))">Custom Toast</button>
<button class="btn btn-secondary" @onclick="@(() => toastService.ShowToast<MyToastComponent>(_toastParameters, new ToastInstanceSettings(5, true)))">Custom Toast with parameters</button>
<button class="btn btn-primary" @onclick="@(() => toastService.ShowToast<MyToastComponent>(settings => { settings.Timeout = 5; settings.ShowProgressBar = false; }))">Custom Toast</button>
<button class="btn btn-secondary" @onclick="@(() => toastService.ShowToast<MyToastComponent>(_toastParameters, settings => { settings.Timeout = 5; settings.ShowProgressBar = false; }))">Custom Toast with parameters</button>
<hr />

<h1>Blazored Toasts - Remove Toasts</h1>
Expand Down
1 change: 1 addition & 0 deletions samples/BlazorServer/Pages/_Host.cshtml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
crossorigin="anonymous"
integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" />
</environment>
<link href="BlazorServer.styles.css" rel="stylesheet" />
<link href="~/css/site.css" rel="stylesheet" />

<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
Expand Down
11 changes: 6 additions & 5 deletions samples/BlazorWebAssembly/Pages/Index.razor
Original file line number Diff line number Diff line change
@@ -1,25 +1,26 @@
@page "/"
@using Blazored.Toast.Configuration
@inject IToastService ToastService
@inject NavigationManager NavigationManager

<PageTitle>Blazored Toast Samples</PageTitle>

<h1>Blazored Toasts</h1>

<button class="btn btn-info" id="InfoButton" @onclick="@(() => ToastService.ShowInfo("I'm an INFO message"))">Info Toast</button>
<button class="btn btn-success" id="SuccessButton" @onclick="@(() => ToastService.ShowSuccess("I'm a SUCCESS message with a custom heading", "Congratulations!"))">Success Toast</button>
<button class="btn btn-info" id="InfoButton" @onclick="@(() => ToastService.ShowInfo("I'm an INFO message", settings => settings.IconType = IconType.None))">Info Toast</button>
<button class="btn btn-success" id="SuccessButton" @onclick="@(() => ToastService.ShowSuccess("I'm a SUCCESS message with a lot of text to see what a toast looks like when it's really big."))">Success Toast</button>
<button class="btn btn-warning" @onclick="@(() => ToastService.ShowWarning("I'm a WARNING message"))">Warning Toast</button>
<button class="btn btn-danger" @onclick="@(() => ToastService.ShowError("I'm an ERROR message"))">Error Toast</button>
<button class="btn btn-info" @onclick="@OnShowHtml">Info Toast with HTML</button>
<button class="btn btn-info" @onclick="@(() => ToastService.ShowInfo("Click to refresh the page", "Click me!", () => { NavigationManager.NavigateTo("/", true); }))">
<button class="btn btn-info" @onclick="@(() => ToastService.ShowInfo("Click to refresh the page", settings => settings.OnClick = () => NavigationManager.NavigateTo("/", true)))">
Info Toast with custom action on click
</button>
<hr />
<h1>Blazored Toasts - Custom Component</h1>
<button class="btn btn-primary" @onclick="@(() => ToastService.ShowToast<MyToastComponent>(new ToastInstanceSettings(5, true)))">Custom Toast</button>
<button class="btn btn-secondary" id="CustomButton" @onclick="@(() => ToastService.ShowToast<MyToastComponent>(_toastParameters, new ToastInstanceSettings(5, true)))">Custom Toast with parameters</button>
<button class="btn btn-primary" @onclick="@(() => ToastService.ShowToast<MyToastComponent>(settings => { settings.Timeout = 5; settings.ShowProgressBar = false; }))">Custom Toast</button>
<button class="btn btn-secondary" id="CustomButton" @onclick="@(() => ToastService.ShowToast<MyToastComponent>(_toastParameters, settings => { settings.Timeout = 5; settings.ShowProgressBar = true; }))">Custom Toast with parameters</button>
<hr />
<h1>Blazored Toasts - Remove Toasts</h1>
Expand Down
4 changes: 2 additions & 2 deletions samples/BlazorWebAssembly/Shared/MainLayout.razor
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
@using Blazored.Toast.Configuration

<BlazoredToasts Position="ToastPosition.BottomRight"
Timeout="60"
IconType="IconType.FontAwesome"
Timeout="120"
ShowProgressBar="true"
IconType="IconType.FontAwesome"
SuccessClass="success-toast-override"
ErrorIcon="fa fa-bug"
SuccessIcon="fa fa-thumbs-up" />
Expand Down
31 changes: 0 additions & 31 deletions samples/bUnitExample/BlazoredToastTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -64,20 +64,6 @@ public void DisplaysToastWithLevel()
Assert.Equal(ToastLevel.Info, toastService.Toasts.Single().ToastLevel);
}

[Fact]
public void DisplaysToastWithHeading()
{
// Arrange
var toastService = this.AddBlazoredToast();
var cut = RenderComponent<Index>();

// Act
cut.Find("#SuccessButton").Click();

// Assert
Assert.Equal("Congratulations!", toastService.Toasts.Single().Heading);
}

[Fact]
public void DisplaysTwoToastsWithLevel()
{
Expand All @@ -95,23 +81,6 @@ public void DisplaysTwoToastsWithLevel()
_ => Assert.Equal(ToastLevel.Success, _.ToastLevel));
}

[Fact]
public void DisplaysTwoToastsWithHeading()
{
// Arrange
var toastService = this.AddBlazoredToast();
var cut = RenderComponent<Index>();

// Act
cut.Find("#InfoButton").Click();
cut.Find("#SuccessButton").Click();

// Assert
Assert.Collection(toastService.Toasts,
_ => Assert.Equal("Info", _.Heading),
_ => Assert.Equal("Congratulations!", _.Heading));
}

[Fact]
public void DisplaysToasts()
{
Expand Down
Binary file modified screenshot.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 1 addition & 3 deletions src/Blazored.Toast.TestExtensions/InMemoryToast.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,12 @@ public class InMemoryToast
public Type ToastType { get; set; }
public ToastLevel ToastLevel { get; }
public RenderFragment Message { get; }
public string Heading { get; }

public InMemoryToast(Type toastType, ToastLevel toastLevel, RenderFragment message, string heading)
public InMemoryToast(Type toastType, ToastLevel toastLevel, RenderFragment message)
{
ToastType = toastType;
ToastLevel = toastLevel;
Message = message;
Heading = heading;
}

public InMemoryToast(Type toastType)
Expand Down
106 changes: 42 additions & 64 deletions src/Blazored.Toast.TestExtensions/InMemoryToastService.cs
Original file line number Diff line number Diff line change
@@ -1,106 +1,84 @@
using Blazored.Toast.Services;
using Blazored.Toast.Configuration;
using Blazored.Toast.Services;
using Microsoft.AspNetCore.Components;

namespace Blazored.Toast.TestExtensions;

public class InMemoryToastService : IToastService
{
private readonly List<InMemoryToast> toasts = new List<InMemoryToast>();
public IReadOnlyList<InMemoryToast> Toasts => toasts;

public event Action<ToastLevel, RenderFragment, string, Action> OnShow;

public event Action<Type, ToastParameters, ToastInstanceSettings> OnShowComponent;
private readonly List<InMemoryToast> _toasts = new();
public IReadOnlyList<InMemoryToast> Toasts => _toasts;

public event Action<Type, ToastParameters?, Action<ToastSettings>?> OnShowComponent;
public event Action<ToastLevel, RenderFragment, Action<ToastSettings>?>? OnShow;
public event Action OnClearAll;
public event Action<ToastLevel> OnClearToasts;
public event Action OnClearCustomToasts;
public event Action? OnClearQueue;
public event Action<ToastLevel>? OnClearQueueToasts;

public void ShowToast<TComponent>() where TComponent : IComponent
{
toasts.Add(new InMemoryToast(typeof(TComponent)));
}

public void ShowToast<TComponent>(ToastParameters parameters) where TComponent : IComponent
{
toasts.Add(new InMemoryToast(typeof(TComponent)));
}

public void ShowToast<TComponent>(ToastInstanceSettings settings) where TComponent : IComponent
{
toasts.Add(new InMemoryToast(typeof(TComponent)));
}
public void ShowToast<TComponent>() where TComponent : IComponent
=> _toasts.Add(new InMemoryToast(typeof(TComponent)));

public void ShowToast<TComponent>(ToastParameters parameters, ToastInstanceSettings settings) where TComponent : IComponent
{
toasts.Add(new InMemoryToast(typeof(TComponent)));
}
public void ShowToast<TComponent>(ToastParameters parameters) where TComponent : IComponent
=> _toasts.Add(new InMemoryToast(typeof(TComponent)));

public void ShowError(string message, string heading = "", Action onClick = null)
=> ShowToast(ToastLevel.Error, message, heading, onClick);
public void ShowToast<TComponent>(Action<ToastSettings>? settings) where TComponent : IComponent
=> _toasts.Add(new InMemoryToast(typeof(TComponent)));

public void ShowError(RenderFragment message, string heading = "", Action onClick = null)
=> ShowToast(ToastLevel.Error, message, heading, onClick);
public void ShowToast<TComponent>(ToastParameters parameters, Action<ToastSettings>? settings) where TComponent : IComponent
=> _toasts.Add(new InMemoryToast(typeof(TComponent)));

public void ShowInfo(string message, string heading = "", Action onClick = null)
=> ShowToast(ToastLevel.Info, message, heading, onClick);
public void ShowError(string message, Action<ToastSettings>? settings = null)
=> ShowToast(ToastLevel.Error, message, settings);

public void ShowInfo(RenderFragment message, string heading = "", Action onClick = null)
=> ShowToast(ToastLevel.Info, message, heading, onClick);
public void ShowError(RenderFragment message, Action<ToastSettings>? settings = null)
=> ShowToast(ToastLevel.Error, message, settings);

public void ShowSuccess(string message, string heading = "", Action onClick = null)
=> ShowToast(ToastLevel.Success, message, heading, onClick);
public void ShowInfo(string message, Action<ToastSettings>? settings = null)
=> ShowToast(ToastLevel.Info, message, settings);

public void ShowSuccess(RenderFragment message, string heading = "", Action onClick = null)
=> ShowToast(ToastLevel.Success, message, heading, onClick);
public void ShowInfo(RenderFragment message, Action<ToastSettings>? settings = null)
=> ShowToast(ToastLevel.Info, message, settings);

public void ShowToast(ToastLevel level, string message, string heading = "", Action onClick = null)
=> ShowToast(level, builder => builder.AddContent(0, message), heading, onClick);
public void ShowSuccess(string message, Action<ToastSettings>? settings = null)
=> ShowToast(ToastLevel.Success, message, settings);

public void ShowToast(ToastLevel level, RenderFragment message, string heading = "", Action onClick = null)
=> toasts.Add(new InMemoryToast(typeof(Configuration.ToastInstance), level, message, GetHeading(level, heading)));
public void ShowSuccess(RenderFragment message, Action<ToastSettings>? settings = null)
=> ShowToast(ToastLevel.Success, message, settings);

public void ShowWarning(string message, string heading = "", Action onClick = null)
=> ShowToast(ToastLevel.Warning, message, heading, onClick);
public void ShowToast(ToastLevel level, string message, Action<ToastSettings>? settings = null)
=> ShowToast(level, builder => builder.AddContent(0, message), settings);

public void ShowWarning(RenderFragment message, string heading = "", Action onClick = null)
=> ShowToast(ToastLevel.Warning, message, heading, onClick);
public void ShowToast(ToastLevel level, RenderFragment message, Action<ToastSettings>? settings = null)
=> _toasts.Add(new InMemoryToast(typeof(ToastInstance), level, message));

private string GetHeading(ToastLevel level, string heading)
{
if (!string.IsNullOrWhiteSpace(heading)) return heading;
public void ShowWarning(string message, Action<ToastSettings>? settings = null)
=> ShowToast(ToastLevel.Warning, message, settings);

return level switch
{
ToastLevel.Error => "Error",
ToastLevel.Info => "Info",
ToastLevel.Success => "Success",
ToastLevel.Warning => "Warning",
_ => throw new InvalidOperationException(),
};
}
public void ShowWarning(RenderFragment message, Action<ToastSettings>? settings = null)
=> ShowToast(ToastLevel.Warning, message, settings);

public void ClearAll()
=> toasts.Clear();
=> _toasts.Clear();

public void ClearToasts(ToastLevel toastLevel)
=> toasts.RemoveAll(x => x.ToastType == typeof(Configuration.ToastInstance) && x.ToastLevel == toastLevel);
=> _toasts.RemoveAll(x => x.ToastType == typeof(ToastInstance) && x.ToastLevel == toastLevel);

public void ClearWarningToasts()
=> toasts.RemoveAll(x => x.ToastType == typeof(Configuration.ToastInstance) && x.ToastLevel == ToastLevel.Warning);
=> _toasts.RemoveAll(x => x.ToastType == typeof(ToastInstance) && x.ToastLevel == ToastLevel.Warning);

public void ClearInfoToasts()
=> toasts.RemoveAll(x => x.ToastType == typeof(Configuration.ToastInstance) && x.ToastLevel == ToastLevel.Info);
=> _toasts.RemoveAll(x => x.ToastType == typeof(ToastInstance) && x.ToastLevel == ToastLevel.Info);

public void ClearSuccessToasts()
=> toasts.RemoveAll(x => x.ToastType == typeof(Configuration.ToastInstance) && x.ToastLevel == ToastLevel.Success);
=> _toasts.RemoveAll(x => x.ToastType == typeof(ToastInstance) && x.ToastLevel == ToastLevel.Success);

public void ClearErrorToasts()
=> toasts.RemoveAll(x => x.ToastType == typeof(Configuration.ToastInstance) && x.ToastLevel == ToastLevel.Error);
=> _toasts.RemoveAll(x => x.ToastType == typeof(ToastInstance) && x.ToastLevel == ToastLevel.Error);

public void ClearCustomToasts()
=> toasts.RemoveAll(x => x.ToastType != typeof(Configuration.ToastInstance));
=> _toasts.RemoveAll(x => x.ToastType != typeof(ToastInstance));

public void ClearQueue()
=> throw new NotImplementedException();
Expand Down
10 changes: 4 additions & 6 deletions src/Blazored.Toast/Blazored.Toast.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -30,19 +30,13 @@
</PropertyGroup>

<ItemGroup>
<Content Remove="bundleconfig.json" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="BuildBundlerMinifier" Version="3.2.449" PrivateAssets="all" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="6.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Components" Version="6.0.7" />
<PackageReference Include="Microsoft.AspNetCore.Components.Web" Version="6.0.7" />
</ItemGroup>

<ItemGroup>
<None Include="icon.png" Pack="true" PackagePath="\" />
<None Include="bundleconfig.json" />
</ItemGroup>

<ItemGroup>
Expand All @@ -52,5 +46,9 @@
</_Parameter1>
</AssemblyAttribute>
</ItemGroup>

<ItemGroup>
<_ContentIncludedByDefault Remove="wwwroot\blazored-toast.css" />
</ItemGroup>

</Project>
Loading

0 comments on commit 634f559

Please sign in to comment.