Merge pull request #22 from lanedirt/21-improve-blazor-wasm-ui

Improve blazor wasm UI
This commit is contained in:
Leendert de Borst
2024-06-17 06:51:19 -07:00
committed by GitHub
15 changed files with 258 additions and 196 deletions

View File

@@ -6,7 +6,7 @@
return;
}
<div class="p-4 mb-4 text-sm text-red-800 rounded-lg bg-red-50 dark:bg-gray-800 dark:text-red-400" role="alert">
<div class="p-4 mb-4 text-sm text-red-800 rounded-lg bg-red-50 dark:bg-gray-800 dark:text-red-400 border-2" role="alert">
@Message
</div>

View File

@@ -6,7 +6,7 @@
return;
}
<div class="p-4 mb-4 text-sm text-green-800 rounded-lg bg-green-50 dark:bg-gray-800 dark:text-green-400" role="alert">
<div class="p-4 mb-4 text-sm text-green-800 rounded-lg bg-green-50 dark:bg-gray-800 dark:text-green-400 border-2" role="alert">
@Message
</div>

View File

@@ -0,0 +1,72 @@
@inject GlobalNotificationService GlobalNotificationService
@implements IDisposable
@foreach (var message in Messages)
{
if (message.Key == "success")
{
<AlertMessageSuccess Message="@message.Value" />
}
}
@foreach (var message in Messages)
{
if (message.Key == "error")
{
<AlertMessageError Message="@message.Value" />
}
}
@code {
private List<KeyValuePair<string, string>> Messages { get; set; } = new();
private bool _onChangeSubscribed = false;
/// <inheritdoc />
protected override async Task OnAfterRenderAsync(bool firstRender)
{
await base.OnAfterRenderAsync(firstRender);
if (firstRender)
{
// We subscribe to the OnChange event of the PortalMessageService to update the UI when a new message is added
RefreshAddMessages();
GlobalNotificationService.OnChange += RefreshAddMessages;
_onChangeSubscribed = true;
}
}
/// <inheritdoc />
public void Dispose()
{
// We unsubscribe from the OnChange event of the PortalMessageService when the component is disposed
if (_onChangeSubscribed)
{
GlobalNotificationService.OnChange -= RefreshAddMessages;
_onChangeSubscribed = false;
}
}
/// <summary>
/// Refreshes the messages by adding any new messages from the PortalMessageService.
/// </summary>
public void RefreshAddMessages()
{
// We retrieve any additional messages from the GlobalNotificationService that we do not yet have.
var newMessages = GlobalNotificationService.GetMessagesForDisplay();
foreach (var message in newMessages)
{
if (!Messages.Any(m => m.Key == message.Key && m.Value == message.Value))
{
Messages.Add(message);
}
}
// Remove messages that are no longer in the GlobalNotificationService and have already been displayed.
var messagesToRemove = Messages.Where(m => !newMessages.Any(nm => nm.Key == m.Key && nm.Value == m.Value)).ToList();
foreach (var message in messagesToRemove)
{
Messages.Remove(message);
}
StateHasChanged();
}
}

View File

@@ -1,6 +1,5 @@
@using AliasVault.WebApp.Components.Models
@inherits ComponentBase
@using Microsoft.IdentityModel.Tokens
@inherits ComponentBase
<nav class="flex mb-5" aria-label="RecentEmails">
<ol class="inline-flex items-center space-x-1 text-sm font-medium md:space-x-2">
@@ -33,11 +32,16 @@
}
</ol>
</nav>
<GlobalNotificationDisplay />
@code {
/// <summary>
/// Gets or sets the list of breadcrumb items.
/// </summary>
[Parameter]
public List<BreadcrumbItem> BreadcrumbItems { get; set; } = new List<BreadcrumbItem>();
public List<BreadcrumbItem> BreadcrumbItems { get; set; } = new();
/// <inheritdoc />
protected override void OnInitialized()
{
base.OnInitialized();

View File

@@ -1,13 +1,11 @@
@page "/add-alias"
@page "/alias/{id:guid}/edit"
@inherits PageBase
@inject NavigationManager Navigation
@inject AliasService AliasService
@inherits PageBase
@using AliasGenerators.Implementations
@using AliasGenerators.Password.Implementations
@using AliasVault.Shared.Models.WebApi
@using AliasVault.WebApp.Services
@if (EditMode)
{
@@ -197,7 +195,9 @@ else
{
if (Id is null)
{
Navigation.NavigateTo("/404");
// Error loading alias.
GlobalNotificationService.AddErrorMessage("This alias does not exist (anymore). Please try again.");
NavigationManager.NavigateTo("/", false, true);
return;
}
@@ -205,7 +205,9 @@ else
var alias = await AliasService.LoadAliasAsync(Id.Value);
if (alias is null)
{
Navigation.NavigateTo("/404");
// Error loading alias.
GlobalNotificationService.AddErrorMessage("This alias does not exist (anymore). Please try again.");
NavigationManager.NavigateTo("/", false, true);
return;
}
@@ -295,7 +297,7 @@ else
{
if (Id is not null)
{
await AliasService.UpdateAliasAsync(Obj, Id.Value);
Id = await AliasService.UpdateAliasAsync(Obj, Id.Value);
}
}
else
@@ -306,12 +308,23 @@ else
IsSaving = false;
StateHasChanged();
if (Id == Guid.Empty)
if (Id is null || Id == Guid.Empty)
{
// Error saving, do not navigate.
// Error saving.
GlobalNotificationService.AddErrorMessage("Error saving alias. Please try again.", true);
return;
}
// No error, add success message.
if (EditMode)
{
GlobalNotificationService.AddSuccessMessage("Alias updated successfully.");
}
else
{
GlobalNotificationService.AddSuccessMessage("Alias created successfully.");
}
Navigation.NavigateTo("/alias/" + Id);
}
}

View File

@@ -1,8 +1,6 @@
@page "/alias/{id:guid}/delete"
@using AliasVault.Shared.Models.WebApi
@using AliasVault.WebApp.Services
@inherits PageBase
@using AliasVault.Shared.Models.WebApi
@inject AliasService AliasService
<LayoutPageTitle>Delete alias</LayoutPageTitle>
@@ -82,10 +80,12 @@ else
{
if (Obj is null)
{
GlobalNotificationService.AddErrorMessage("Error deleting. Alias not found.", true);
return;
}
await AliasService.DeleteAliasAsync(Id);
GlobalNotificationService.AddSuccessMessage("Alias successfully deleted.");
NavigationManager.NavigateTo("/");
}

View File

@@ -1,9 +1,8 @@
@page "/alias/{id:guid}"
@inherits PageBase
@using AliasVault.Shared.Models.WebApi
@using AliasVault.WebApp.Services
@using AliasVault.WebApp.Components.Email
@inject AliasService AliasService
@inherits PageBase
<LayoutPageTitle>View alias</LayoutPageTitle>
@@ -13,9 +12,11 @@
}
else
{
<div class="grid grid-cols-2 px-4 pt-6 md:grid-cols-3 lg:gap-4 dark:bg-gray-900">
<div class="mb-4 col-span-full xl:mb-2">
<Breadcrumb BreadcrumbItems="BreadcrumbItems"/>
<div class="flex items-center justify-between">
<h1 class="text-xl font-semibold text-gray-900 sm:text-2xl dark:text-white">View alias</h1>
<div class="flex">
@@ -28,6 +29,7 @@ else
</div>
</div>
</div>
<!-- Right Content -->
<div class="col-span-full lg:col-auto">
<div class="p-4 mb-4 bg-white border border-gray-200 rounded-lg shadow-sm 2xl:col-span-2 dark:border-gray-700 sm:p-6 dark:bg-gray-800">
@@ -144,6 +146,15 @@ else
// Load the aliases from the webapi via AliasService.
Alias = await AliasService.LoadAliasAsync(Id);
if (Alias is null)
{
// Error loading alias.
GlobalNotificationService.AddErrorMessage("This alias does not exist (anymore). Please try again.");
NavigationManager.NavigateTo("/", false, true);
return;
}
AliasEmail = Alias?.Identity.EmailPrefix + "@landmail.nl";
IsLoading = false;

View File

@@ -8,6 +8,7 @@
namespace AliasVault.WebApp.Pages.Base;
using AliasVault.WebApp.Components.Models;
using AliasVault.WebApp.Services;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.JSInterop;
@@ -33,6 +34,12 @@ public class PageBase : OwningComponentBase
[Inject]
public AuthenticationStateProvider AuthStateProvider { get; set; } = null!;
/// <summary>
/// Gets or sets the GlobalNotificationService.
/// </summary>
[Inject]
public GlobalNotificationService GlobalNotificationService { get; set; } = null!;
/// <summary>
/// Gets or sets the IJSRuntime.
/// </summary>
@@ -55,10 +62,6 @@ public class PageBase : OwningComponentBase
// Add base breadcrumbs
BreadcrumbItems.Add(new BreadcrumbItem { DisplayName = "Home", Url = NavigationManager.BaseUri });
// Detect success messages in query string and add them to the SuccessMessages list
// TODO: Implement this with example for default add/edit update action...
var uri = new Uri(NavigationManager.Uri);
}
/// <summary>

View File

@@ -1,9 +1,8 @@
@page "/"
@page "/aliases"
@using AliasVault.WebApp.Components.Alias
@using AliasVault.WebApp.Services
@inject AliasService AliasService
@inherits PageBase
@using AliasVault.WebApp.Components.Alias
@inject AliasService AliasService
<LayoutPageTitle>Home</LayoutPageTitle>
@@ -22,13 +21,13 @@
@if (IsLoading)
{
<LoadingIndicator />
<LoadingIndicator />
}
<div class="grid gap-4 px-4 mb-4 md:grid-cols-4 xl:grid-cols-6">
@foreach (var alias in Aliases)
{
<Alias Obj="@alias"/>
<Alias Obj="@alias"/>
}
</div>
@@ -55,8 +54,7 @@
if (aliasListEntries is null)
{
// Error loading aliases.
IsLoading = false;
StateHasChanged();
GlobalNotificationService.AddErrorMessage("Failed to load aliases.", true);
return;
}

View File

@@ -36,6 +36,7 @@ builder.Services.AddTransient<AliasVaultApiHandlerService>();
builder.Services.AddScoped<AuthService>();
builder.Services.AddScoped<AuthenticationStateProvider, AuthStateProvider>();
builder.Services.AddScoped<AliasService>();
builder.Services.AddScoped<GlobalNotificationService>();
builder.Services.AddSingleton<ClipboardCopyService>();
builder.Services.AddAuthorizationCore();
builder.Services.AddBlazoredLocalStorage();

View File

@@ -97,7 +97,7 @@ public class AliasService(HttpClient httpClient)
}
catch
{
return new List<AliasListEntry>();
return null;
}
}

View File

@@ -0,0 +1,94 @@
//-----------------------------------------------------------------------
// <copyright file="GlobalNotificationService.cs" company="lanedirt">
// Copyright (c) lanedirt. All rights reserved.
// Licensed under the MIT license. See LICENSE.md file in the project root for full license information.
// </copyright>
//-----------------------------------------------------------------------
namespace AliasVault.WebApp.Services;
/// <summary>
/// Handles global notifications that should be displayed to the user, such as success or error messages. These messages
/// are stored in this object which is scoped to the current session. This allows the messages to be cached until
/// they actually have been displayed. So they can survive redirects and page reloads.
/// </summary>
public class GlobalNotificationService
{
/// <summary>
/// Allow other components to subscribe to changes in the event object.
/// </summary>
public event Action? OnChange;
/// <summary>
/// Gets or sets success messages that should be displayed to the user.
/// </summary>
protected List<string> SuccessMessages { get; set; } = new();
/// <summary>
/// Gets or sets error messages that should be displayed to the user.
/// </summary>
protected List<string> ErrorMessages { get; set; } = new();
/// <summary>
/// Adds a success message to the list of messages that should be displayed to the user.
/// </summary>
/// <param name="message">The message to add.</param>
/// <param name="notifyStateChanged">Whether to notify state change to subscribers. Defaults to false.
/// Set this to true if you want to show the added message instantly instead of waiting for the notification
/// display to rerender (e.g. after navigation).</param>
public void AddSuccessMessage(string message, bool notifyStateChanged = false)
{
SuccessMessages.Add(message);
// Notify subscribers that a message has been added.
if (notifyStateChanged)
{
NotifyStateChanged();
}
}
/// <summary>
/// Adds an error message to the list of messages that should be displayed to the user.
/// </summary>
/// <param name="message">The message to add.</param>
/// <param name="notifyStateChanged">Whether to notify state change to subscribers. Defaults to false.
/// Set this to true if you want to show the added message instantly instead of waiting for the notification
/// display to rerender (e.g. after navigation).</param>
public void AddErrorMessage(string message, bool notifyStateChanged = false)
{
ErrorMessages.Add(message);
// Notify subscribers that a message has been added.
if (notifyStateChanged)
{
NotifyStateChanged();
}
}
/// <summary>
/// Returns a dictionary with messages that should be displayed to the user. After this method is called,
/// the messages are automatically cleared.
/// </summary>
/// <returns>Dictionary with messages that are ready to be displayed on the next page load.</returns>
public List<KeyValuePair<string, string>> GetMessagesForDisplay()
{
var messages = new List<KeyValuePair<string, string>>();
foreach (var message in SuccessMessages)
{
messages.Add(new KeyValuePair<string, string>("success", message));
}
foreach (var message in ErrorMessages)
{
messages.Add(new KeyValuePair<string, string>("error", message));
}
// Clear messages
SuccessMessages.Clear();
ErrorMessages.Clear();
return messages;
}
private void NotifyStateChanged() => OnChange?.Invoke();
}

View File

@@ -16,6 +16,7 @@
@using AliasVault.WebApp.Components.Alerts
@using AliasVault.WebApp.Components.Loading
@using AliasVault.WebApp.Pages.Base
@using AliasVault.WebApp.Services
@using Microsoft.AspNetCore.Components.Authorization
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication
@using Blazored.LocalStorage

View File

@@ -714,10 +714,6 @@ video {
margin-top: 2rem;
}
.me-2 {
margin-inline-end: 0.5rem;
}
.block {
display: block;
}
@@ -770,10 +766,6 @@ video {
height: 1.5rem;
}
.h-7 {
height: 1.75rem;
}
.h-8 {
height: 2rem;
}
@@ -786,10 +778,6 @@ video {
height: 100%;
}
.h-3 {
height: 0.75rem;
}
.w-1\/2 {
width: 50%;
}
@@ -822,10 +810,6 @@ video {
width: 16rem;
}
.w-7 {
width: 1.75rem;
}
.w-8 {
width: 2rem;
}
@@ -834,10 +818,6 @@ video {
width: 100%;
}
.w-3 {
width: 0.75rem;
}
.min-w-full {
min-width: 100%;
}
@@ -938,12 +918,6 @@ video {
margin-left: calc(0.25rem * calc(1 - var(--tw-space-x-reverse)));
}
.space-x-2 > :not([hidden]) ~ :not([hidden]) {
--tw-space-x-reverse: 0;
margin-right: calc(0.5rem * var(--tw-space-x-reverse));
margin-left: calc(0.5rem * calc(1 - var(--tw-space-x-reverse)));
}
.space-x-6 > :not([hidden]) ~ :not([hidden]) {
--tw-space-x-reverse: 0;
margin-right: calc(1.5rem * var(--tw-space-x-reverse));
@@ -1016,10 +990,6 @@ video {
border-radius: 0.5rem;
}
.rounded-md {
border-radius: 0.375rem;
}
.rounded-l-lg {
border-top-left-radius: 0.5rem;
border-bottom-left-radius: 0.5rem;
@@ -1046,6 +1016,11 @@ video {
border-top-width: 1px;
}
.border-blue-700 {
--tw-border-opacity: 1;
border-color: rgb(29 78 216 / var(--tw-border-opacity));
}
.border-gray-200 {
--tw-border-opacity: 1;
border-color: rgb(229 231 235 / var(--tw-border-opacity));
@@ -1056,31 +1031,11 @@ video {
border-color: rgb(209 213 219 / var(--tw-border-opacity));
}
.border-green-100 {
--tw-border-opacity: 1;
border-color: rgb(220 252 231 / var(--tw-border-opacity));
}
.border-green-500 {
--tw-border-opacity: 1;
border-color: rgb(34 197 94 / var(--tw-border-opacity));
}
.border-orange-100 {
--tw-border-opacity: 1;
border-color: rgb(255 237 213 / var(--tw-border-opacity));
}
.border-purple-100 {
--tw-border-opacity: 1;
border-color: rgb(243 232 255 / var(--tw-border-opacity));
}
.border-blue-700 {
--tw-border-opacity: 1;
border-color: rgb(29 78 216 / var(--tw-border-opacity));
}
.bg-blue-600 {
--tw-bg-opacity: 1;
background-color: rgb(37 99 235 / var(--tw-bg-opacity));
@@ -1111,11 +1066,6 @@ video {
background-color: rgb(17 24 39 / var(--tw-bg-opacity));
}
.bg-green-100 {
--tw-bg-opacity: 1;
background-color: rgb(220 252 231 / var(--tw-bg-opacity));
}
.bg-green-50 {
--tw-bg-opacity: 1;
background-color: rgb(240 253 244 / var(--tw-bg-opacity));
@@ -1126,11 +1076,6 @@ video {
background-color: rgb(22 163 74 / var(--tw-bg-opacity));
}
.bg-orange-100 {
--tw-bg-opacity: 1;
background-color: rgb(255 237 213 / var(--tw-bg-opacity));
}
.bg-primary-600 {
--tw-bg-opacity: 1;
background-color: rgb(214 131 56 / var(--tw-bg-opacity));
@@ -1141,11 +1086,6 @@ video {
background-color: rgb(184 112 47 / var(--tw-bg-opacity));
}
.bg-purple-100 {
--tw-bg-opacity: 1;
background-color: rgb(243 232 255 / var(--tw-bg-opacity));
}
.bg-red-50 {
--tw-bg-opacity: 1;
background-color: rgb(254 242 242 / var(--tw-bg-opacity));
@@ -1161,11 +1101,6 @@ video {
background-color: rgb(255 255 255 / var(--tw-bg-opacity));
}
.bg-blue-700 {
--tw-bg-opacity: 1;
background-color: rgb(29 78 216 / var(--tw-bg-opacity));
}
.bg-opacity-50 {
--tw-bg-opacity: 0.5;
}
@@ -1190,16 +1125,6 @@ video {
padding: 1.5rem;
}
.px-2 {
padding-left: 0.5rem;
padding-right: 0.5rem;
}
.px-2\.5 {
padding-left: 0.625rem;
padding-right: 0.625rem;
}
.px-3 {
padding-left: 0.75rem;
padding-right: 0.75rem;
@@ -1220,16 +1145,6 @@ video {
padding-right: 1.5rem;
}
.py-0 {
padding-top: 0px;
padding-bottom: 0px;
}
.py-0\.5 {
padding-top: 0.125rem;
padding-bottom: 0.125rem;
}
.py-1 {
padding-top: 0.25rem;
padding-bottom: 0.25rem;
@@ -1352,6 +1267,11 @@ video {
letter-spacing: 0.05em;
}
.text-blue-700 {
--tw-text-opacity: 1;
color: rgb(29 78 216 / var(--tw-text-opacity));
}
.text-gray-200 {
--tw-text-opacity: 1;
color: rgb(229 231 235 / var(--tw-text-opacity));
@@ -1387,21 +1307,11 @@ video {
color: rgb(22 101 52 / var(--tw-text-opacity));
}
.text-orange-800 {
--tw-text-opacity: 1;
color: rgb(154 52 18 / var(--tw-text-opacity));
}
.text-primary-700 {
--tw-text-opacity: 1;
color: rgb(184 112 47 / var(--tw-text-opacity));
}
.text-purple-800 {
--tw-text-opacity: 1;
color: rgb(107 33 168 / var(--tw-text-opacity));
}
.text-red-800 {
--tw-text-opacity: 1;
color: rgb(153 27 27 / var(--tw-text-opacity));
@@ -1412,11 +1322,6 @@ video {
color: rgb(255 255 255 / var(--tw-text-opacity));
}
.text-blue-700 {
--tw-text-opacity: 1;
color: rgb(29 78 216 / var(--tw-text-opacity));
}
.opacity-0 {
opacity: 0;
}
@@ -1478,6 +1383,11 @@ video {
background-color: rgb(229 231 235 / var(--tw-bg-opacity));
}
.hover\:bg-gray-50:hover {
--tw-bg-opacity: 1;
background-color: rgb(249 250 251 / var(--tw-bg-opacity));
}
.hover\:bg-gray-800:hover {
--tw-bg-opacity: 1;
background-color: rgb(31 41 55 / var(--tw-bg-opacity));
@@ -1508,16 +1418,6 @@ video {
background-color: rgb(153 27 27 / var(--tw-bg-opacity));
}
.hover\:bg-blue-800:hover {
--tw-bg-opacity: 1;
background-color: rgb(30 64 175 / var(--tw-bg-opacity));
}
.hover\:bg-gray-50:hover {
--tw-bg-opacity: 1;
background-color: rgb(249 250 251 / var(--tw-bg-opacity));
}
.hover\:text-gray-900:hover {
--tw-text-opacity: 1;
color: rgb(17 24 39 / var(--tw-text-opacity));
@@ -1598,6 +1498,11 @@ video {
border-color: rgb(75 85 99 / var(--tw-divide-opacity));
}
.dark\:border-blue-500:is(.dark *) {
--tw-border-opacity: 1;
border-color: rgb(59 130 246 / var(--tw-border-opacity));
}
.dark\:border-gray-600:is(.dark *) {
--tw-border-opacity: 1;
border-color: rgb(75 85 99 / var(--tw-border-opacity));
@@ -1608,26 +1513,6 @@ video {
border-color: rgb(55 65 81 / var(--tw-border-opacity));
}
.dark\:border-green-500:is(.dark *) {
--tw-border-opacity: 1;
border-color: rgb(34 197 94 / var(--tw-border-opacity));
}
.dark\:border-orange-300:is(.dark *) {
--tw-border-opacity: 1;
border-color: rgb(253 186 116 / var(--tw-border-opacity));
}
.dark\:border-purple-500:is(.dark *) {
--tw-border-opacity: 1;
border-color: rgb(168 85 247 / var(--tw-border-opacity));
}
.dark\:border-blue-500:is(.dark *) {
--tw-border-opacity: 1;
border-color: rgb(59 130 246 / var(--tw-border-opacity));
}
.dark\:bg-blue-500:is(.dark *) {
--tw-bg-opacity: 1;
background-color: rgb(59 130 246 / var(--tw-bg-opacity));
@@ -1673,15 +1558,15 @@ video {
background-color: rgb(239 68 68 / var(--tw-bg-opacity));
}
.dark\:bg-blue-600:is(.dark *) {
--tw-bg-opacity: 1;
background-color: rgb(37 99 235 / var(--tw-bg-opacity));
}
.dark\:bg-opacity-80:is(.dark *) {
--tw-bg-opacity: 0.8;
}
.dark\:text-blue-500:is(.dark *) {
--tw-text-opacity: 1;
color: rgb(59 130 246 / var(--tw-text-opacity));
}
.dark\:text-gray-300:is(.dark *) {
--tw-text-opacity: 1;
color: rgb(209 213 219 / var(--tw-text-opacity));
@@ -1702,11 +1587,6 @@ video {
color: rgb(74 222 128 / var(--tw-text-opacity));
}
.dark\:text-orange-300:is(.dark *) {
--tw-text-opacity: 1;
color: rgb(253 186 116 / var(--tw-text-opacity));
}
.dark\:text-primary-200:is(.dark *) {
--tw-text-opacity: 1;
color: rgb(251 203 116 / var(--tw-text-opacity));
@@ -1717,11 +1597,6 @@ video {
color: rgb(244 149 65 / var(--tw-text-opacity));
}
.dark\:text-purple-400:is(.dark *) {
--tw-text-opacity: 1;
color: rgb(192 132 252 / var(--tw-text-opacity));
}
.dark\:text-red-400:is(.dark *) {
--tw-text-opacity: 1;
color: rgb(248 113 113 / var(--tw-text-opacity));
@@ -1732,11 +1607,6 @@ video {
color: rgb(255 255 255 / var(--tw-text-opacity));
}
.dark\:text-blue-500:is(.dark *) {
--tw-text-opacity: 1;
color: rgb(59 130 246 / var(--tw-text-opacity));
}
.dark\:placeholder-gray-400:is(.dark *)::-moz-placeholder {
--tw-placeholder-opacity: 1;
color: rgb(156 163 175 / var(--tw-placeholder-opacity));
@@ -1751,6 +1621,11 @@ video {
--tw-ring-offset-color: #1f2937;
}
.dark\:hover\:bg-blue-500:hover:is(.dark *) {
--tw-bg-opacity: 1;
background-color: rgb(59 130 246 / var(--tw-bg-opacity));
}
.dark\:hover\:bg-blue-600:hover:is(.dark *) {
--tw-bg-opacity: 1;
background-color: rgb(37 99 235 / var(--tw-bg-opacity));
@@ -1786,16 +1661,6 @@ video {
background-color: rgb(220 38 38 / var(--tw-bg-opacity));
}
.dark\:hover\:bg-blue-700:hover:is(.dark *) {
--tw-bg-opacity: 1;
background-color: rgb(29 78 216 / var(--tw-bg-opacity));
}
.dark\:hover\:bg-blue-500:hover:is(.dark *) {
--tw-bg-opacity: 1;
background-color: rgb(59 130 246 / var(--tw-bg-opacity));
}
.dark\:hover\:text-primary-500:hover:is(.dark *) {
--tw-text-opacity: 1;
color: rgb(244 149 65 / var(--tw-text-opacity));

View File

@@ -86,8 +86,8 @@ public class AliasTests : PlaywrightTest
await submitButton.ClickAsync();
await WaitForURLAsync("**/alias/**", "View alias");
// Check if the alias was correctly updated.
pageContent = await Page.TextContentAsync("body");
Assert.That(pageContent, Does.Contain("Alias updated"), "Alias update confirmation message not shown.");
Assert.That(pageContent, Does.Contain(serviceNameAfter), "Alias not updated correctly.");
}