mirror of
https://github.com/aliasvault/aliasvault.git
synced 2026-03-21 16:13:27 -04:00
Improve flow with separate creating step, minor tweaks (#306)
This commit is contained in:
@@ -1,4 +1,3 @@
|
||||
@inherits LayoutComponentBase
|
||||
|
||||
<GlobalNotificationDisplay />
|
||||
@Body
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
@inherits AliasVault.Client.Auth.Pages.Base.LoginBase
|
||||
@layout Auth.Layout.EmptyLayout
|
||||
@attribute [AllowAnonymous]
|
||||
@inject IConfiguration Configuration
|
||||
@using System.Text.Json
|
||||
@using AliasVault.Client.Utilities
|
||||
@using AliasVault.Cryptography.Client
|
||||
@using AliasVault.Shared.Models.WebApi.Auth
|
||||
@using SecureRemotePassword
|
||||
|
||||
<div class="w-full mx-auto">
|
||||
<div class="relative inset-0 mt-10 z-10">
|
||||
<GlobalNotificationDisplay />
|
||||
@if (IsLoading)
|
||||
{
|
||||
<div class="flex justify-center items-center">
|
||||
<div class="animate-spin rounded-full h-16 w-16 border-t-2 border-b-2 border-primary-500"></div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@code {
|
||||
private bool IsLoading { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// The username to use for the new account.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public string Username { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// The password to use for the new account.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public string Password { get; set; } = string.Empty;
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||
{
|
||||
await base.OnAfterRenderAsync(firstRender);
|
||||
if (firstRender)
|
||||
{
|
||||
await CompleteSetup();
|
||||
}
|
||||
}
|
||||
|
||||
private async Task CompleteSetup()
|
||||
{
|
||||
StateHasChanged();
|
||||
|
||||
try
|
||||
{
|
||||
var client = new SrpClient();
|
||||
var salt = client.GenerateSalt();
|
||||
|
||||
string encryptionType = Defaults.EncryptionType;
|
||||
string encryptionSettings = Defaults.EncryptionSettings;
|
||||
if (Configuration["CryptographyOverrideType"] is not null && Configuration["CryptographyOverrideSettings"] is not null)
|
||||
{
|
||||
encryptionType = Configuration["CryptographyOverrideType"]!;
|
||||
encryptionSettings = Configuration["CryptographyOverrideSettings"]!;
|
||||
}
|
||||
|
||||
var passwordHash = await Encryption.DeriveKeyFromPasswordAsync(Password, salt, encryptionType, encryptionSettings);
|
||||
var passwordHashString = BitConverter.ToString(passwordHash).Replace("-", string.Empty);
|
||||
var srpSignup = Srp.PasswordChangeAsync(client, salt, Username, passwordHashString);
|
||||
|
||||
var registerRequest = new RegisterRequest(srpSignup.Username, srpSignup.Salt, srpSignup.Verifier, encryptionType, encryptionSettings);
|
||||
var result = await Http.PostAsJsonAsync("api/v1/Auth/register", registerRequest);
|
||||
var responseContent = await result.Content.ReadAsStringAsync();
|
||||
|
||||
if (!result.IsSuccessStatusCode)
|
||||
{
|
||||
foreach (var error in ApiResponseUtility.ParseErrorResponse(responseContent))
|
||||
{
|
||||
GlobalNotificationService.AddErrorMessage(error, true);
|
||||
}
|
||||
IsLoading = false;
|
||||
StateHasChanged();
|
||||
return;
|
||||
}
|
||||
|
||||
var tokenObject = JsonSerializer.Deserialize<TokenModel>(responseContent);
|
||||
|
||||
if (tokenObject != null)
|
||||
{
|
||||
await AuthService.StoreEncryptionKeyAsync(passwordHash);
|
||||
await AuthService.StoreAccessTokenAsync(tokenObject.Token);
|
||||
await AuthService.StoreRefreshTokenAsync(tokenObject.RefreshToken);
|
||||
await AuthStateProvider.GetAuthenticationStateAsync();
|
||||
|
||||
NavigationManager.NavigateTo("/");
|
||||
}
|
||||
else
|
||||
{
|
||||
IsLoading = false;
|
||||
GlobalNotificationService.AddErrorMessage("An error occurred during registration.", true);
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
GlobalNotificationService.AddErrorMessage($"An error occurred: {ex.Message}", true);
|
||||
}
|
||||
finally
|
||||
{
|
||||
IsLoading = false;
|
||||
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,7 +11,7 @@
|
||||
</div>
|
||||
}
|
||||
<div class="@(isLoading ? "invisible opacity-0" : "opacity-100") transition-opacity duration-300 w-full">
|
||||
<div class="bg-white dark:bg-gray-800 rounded-lg shadow-lg lg:shadow-none p-6 mb-6">
|
||||
<div class="bg-white dark:bg-gray-800 rounded-lg shadow-lg lg:shadow-none p-6">
|
||||
<div class="flex items-start mb-4">
|
||||
<div class="flex-shrink-0">
|
||||
<img class="h-10 w-10 rounded-full" src="/img/avatar.webp" alt="AliasVault Assistant">
|
||||
@@ -20,21 +20,21 @@
|
||||
<p class="text-sm text-gray-900 dark:text-white">
|
||||
Great! Now, let's set up your master password for AliasVault.
|
||||
</p>
|
||||
<p class="text-sm text-gray-900 dark:text-white mt-3">
|
||||
Please enter a strong master password for your account. Your username is: <strong>@Username</strong>
|
||||
</p>
|
||||
<p class="text-sm text-gray-900 dark:text-white mt-3 font-semibold">
|
||||
Important: This master password will be used to encrypt your vault. It should be a long, complex string that you can remember. If you forget this password, your data will be permanently inaccessible.
|
||||
</p>
|
||||
<ul class="text-sm text-gray-900 dark:text-white mt-3 list-disc list-inside">
|
||||
<li>Your master password never leaves your device</li>
|
||||
<li>The server has no access to your unencrypted data</li>
|
||||
<li>Even the server admin cannot restore your access if you forget this password</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="p-4 mb-6 bg-gray-100 dark:bg-gray-900 rounded-lg text-gray-900 dark:text-gray-100">
|
||||
<p class="text-sm font-semibold">
|
||||
Important: This master password will be used to encrypt your vault. It should be a long, complex string that you can remember. If you forget this password, your data will be permanently inaccessible.
|
||||
</p>
|
||||
<ul class="text-sm mt-3 list-disc list-inside">
|
||||
<li>Your master password never leaves your device</li>
|
||||
<li>The server has no access to your unencrypted data</li>
|
||||
<li>Even the server admin cannot restore your access if you forget this password</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="space-y-4">
|
||||
<div>
|
||||
<div class="">
|
||||
@@ -127,6 +127,7 @@
|
||||
|
||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||
{
|
||||
await base.OnAfterRenderAsync(firstRender);
|
||||
if (firstRender)
|
||||
{
|
||||
await Task.Delay(100); // Give time for the DOM to update
|
||||
|
||||
@@ -1,60 +0,0 @@
|
||||
@using AliasVault.Client.Auth.Pages.Setup.Components
|
||||
|
||||
<div class="w-full max-w-md mx-auto">
|
||||
<div class="bg-white dark:bg-gray-800 rounded-lg shadow-lg lg:shadow-none p-6 mb-6">
|
||||
<div class="flex items-start mb-4">
|
||||
<div class="flex-shrink-0">
|
||||
<img class="h-10 w-10 rounded-full" src="/img/avatar.webp" alt="AliasVault Assistant">
|
||||
</div>
|
||||
<div class="ml-3 bg-blue-100 dark:bg-blue-900 rounded-lg p-3">
|
||||
<p class="text-sm text-gray-900 dark:text-white">
|
||||
Great choice! Here are some tips for using AliasVault for @Purpose:
|
||||
</p>
|
||||
<ul class="list-disc list-inside text-sm text-gray-900 dark:text-white mt-3">
|
||||
@foreach (var instruction in GetInstructions())
|
||||
{
|
||||
<li>@instruction</li>
|
||||
}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@code {
|
||||
[Parameter]
|
||||
public string Purpose { get; set; } = string.Empty;
|
||||
|
||||
[Parameter]
|
||||
public EventCallback OnNext { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public EventCallback OnBack { get; set; }
|
||||
|
||||
private List<string> GetInstructions()
|
||||
{
|
||||
return Purpose switch
|
||||
{
|
||||
"Personal Security" => new List<string>
|
||||
{
|
||||
"Create unique aliases for each of your online accounts",
|
||||
"Use the password generator to create strong, unique passwords",
|
||||
"Enable two-factor authentication for added security",
|
||||
"Regularly review your aliases and remove unused ones"
|
||||
},
|
||||
"Privacy Protection" => new List<string>
|
||||
{
|
||||
"Use different aliases for different types of online activities",
|
||||
"Take advantage of the disposable email feature for temporary signups",
|
||||
"Use the notes feature to keep track of which alias is used where",
|
||||
"Regularly check the email forwarding settings for each alias"
|
||||
},
|
||||
_ => new List<string>
|
||||
{
|
||||
"Explore the different features of AliasVault",
|
||||
"Use the help section for detailed guides on each feature",
|
||||
"Contact support if you need any assistance"
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,6 @@
|
||||
}
|
||||
<div class="@(isLoading ? "invisible opacity-0" : "opacity-100") transition-opacity duration-300 w-full">
|
||||
<div class="bg-white dark:bg-gray-800 rounded-lg shadow-lg lg:shadow-none p-6">
|
||||
<h2 class="text-xl font-semibold text-gray-900 dark:text-white mb-4">Using AliasVault</h2>
|
||||
<p class="text-sm text-gray-600 dark:text-gray-400 mb-4">
|
||||
Please read and agree to the following terms and conditions before proceeding.
|
||||
</p>
|
||||
@@ -30,7 +29,7 @@
|
||||
</p>
|
||||
</div>
|
||||
<div class="flex items-center">
|
||||
<input type="checkbox" id="agreeTerms" @bind="agreedToTerms" @bind:after="OnAgreedToTerms" class="mr-2">
|
||||
<input type="checkbox" id="agreeTerms" @bind="AgreedToTerms" @bind:after="OnAgreedToTerms" class="mr-2">
|
||||
<label for="agreeTerms" class="text-sm font-bold text-gray-600 dark:text-gray-400">
|
||||
I have read and agree to the Terms and Conditions
|
||||
</label>
|
||||
@@ -40,12 +39,17 @@
|
||||
</div>
|
||||
|
||||
@code {
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether the user has agreed to the terms and conditions.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public bool AgreedToTerms { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public EventCallback<bool> OnAgreedToTermsChanged { get; set; }
|
||||
|
||||
private bool isLoading = true;
|
||||
private Timer? loadingTimer;
|
||||
private bool agreedToTerms = false;
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
@@ -68,6 +72,6 @@
|
||||
|
||||
private async Task OnAgreedToTerms()
|
||||
{
|
||||
await OnAgreedToTermsChanged.InvokeAsync(agreedToTerms);
|
||||
await OnAgreedToTermsChanged.InvokeAsync(AgreedToTerms);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -111,6 +111,7 @@
|
||||
|
||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||
{
|
||||
await base.OnAfterRenderAsync(firstRender);
|
||||
if (firstRender)
|
||||
{
|
||||
await Task.Delay(100); // Give time for the DOM to update
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
<div class="w-full max-w-md mx-auto">
|
||||
<h2 class="mt-16 text-2xl font-bold text-gray-900 dark:text-white mb-4 text-center">Welcome to AliasVault</h2>
|
||||
<p class="text-gray-600 dark:text-gray-400 mb-8 text-center">
|
||||
<p class="mt-16 text-gray-600 dark:text-gray-400 mb-8 text-center">
|
||||
AliasVault is a secure app which help you manage your online identities and passwords.
|
||||
Let's get you set up with your new vault.
|
||||
</p>
|
||||
|
||||
@@ -3,12 +3,6 @@
|
||||
@inherits AliasVault.Client.Auth.Pages.Base.LoginBase
|
||||
@layout Auth.Layout.EmptyLayout
|
||||
@attribute [AllowAnonymous]
|
||||
@inject IConfiguration Configuration
|
||||
@using System.Text.Json
|
||||
@using AliasVault.Shared.Models.WebApi.Auth
|
||||
@using AliasVault.Client.Utilities
|
||||
@using AliasVault.Cryptography.Client
|
||||
@using SecureRemotePassword
|
||||
|
||||
<div class="min-h-screen bg-gray-100 dark:bg-gray-900 flex items-center justify-center">
|
||||
<div class="w-full mx-auto lg:max-w-xl lg:bg-white lg:dark:bg-gray-800 lg:shadow-xl lg:rounded-lg lg:overflow-hidden">
|
||||
@@ -22,25 +16,33 @@
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
<div class="flex-grow text-center">
|
||||
<h2 class="text-xl font-semibold text-gray-900 dark:text-white">@GetStepTitle(currentStep)</h2>
|
||||
</div>
|
||||
<button @onclick="CancelSetup" class="text-gray-500 -mt-1 hover:text-gray-800 dark:text-gray-400 dark:hover:text-gray-200">
|
||||
<svg class="w-8 h-8" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
@if (GetProgressPercentage() > 0)
|
||||
{
|
||||
<div class="w-full bg-gray-200 rounded-full h-2.5 mb-4 dark:bg-gray-700 mt-4">
|
||||
<div class="bg-primary-600 h-2.5 rounded-full" style="width: @(GetProgressPercentage())%"></div>
|
||||
</div>
|
||||
}
|
||||
|
||||
@switch (currentStep)
|
||||
{
|
||||
case SetupStep.Welcome:
|
||||
<WelcomeStep />
|
||||
break;
|
||||
case SetupStep.Purpose:
|
||||
<TermsAndConditionsStep OnAgreedToTermsChanged="@HandleAgreedToTermsChanged" />
|
||||
case SetupStep.TermsAndConditions:
|
||||
<TermsAndConditionsStep
|
||||
AgreedToTerms="@setupData.AgreedToTerms"
|
||||
OnAgreedToTermsChanged="@HandleAgreedToTermsChanged" />
|
||||
break;
|
||||
case SetupStep.PurposeInstructions:
|
||||
<PurposeInstructionsStep />
|
||||
break;
|
||||
case SetupStep.UserInfo:
|
||||
case SetupStep.Username:
|
||||
<UsernameStep
|
||||
DefaultUsername="@setupData.Username"
|
||||
OnUsernameChange="@((string username) => { setupData.Username = username; StateHasChanged(); })" />
|
||||
@@ -50,17 +52,20 @@
|
||||
Username="@setupData.Username"
|
||||
OnPasswordChange="@((string pwd) => { setupData.Password = pwd; StateHasChanged(); })" />
|
||||
break;
|
||||
case SetupStep.Creating:
|
||||
<CreatingStep Username="@setupData.Username" Password="@setupData.Password" />
|
||||
break;
|
||||
}
|
||||
</div>
|
||||
<div class="p-8 bg-gray-100 dark:bg-gray-900 border-t border-gray-200 dark:border-gray-700 lg:bg-transparent lg:dark:bg-transparent lg:border-0">
|
||||
@if (currentStep == SetupStep.Password && !string.IsNullOrWhiteSpace(setupData.Password))
|
||||
{
|
||||
<button @onclick="CompleteSetup"
|
||||
<button @onclick="GoNext"
|
||||
class="w-full py-3 px-4 bg-green-600 hover:bg-green-700 text-white font-semibold rounded-lg transition duration-300 ease-in-out">
|
||||
Create Account
|
||||
</button>
|
||||
}
|
||||
else
|
||||
else if (currentStep != SetupStep.Creating)
|
||||
{
|
||||
<button @onclick="GoNext"
|
||||
class="w-full py-3 px-4 bg-primary-600 hover:bg-primary-700 text-white font-semibold rounded-lg transition duration-300 ease-in-out @(isNextEnabled ? "" : "opacity-50 cursor-not-allowed")"
|
||||
@@ -73,18 +78,14 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<FullScreenLoadingIndicator @ref="LoadingIndicator"/>
|
||||
|
||||
@code {
|
||||
private FullScreenLoadingIndicator LoadingIndicator = new();
|
||||
private SetupStep currentStep = SetupStep.Welcome;
|
||||
private SetupData setupData = new();
|
||||
private bool isNextEnabled => currentStep switch
|
||||
{
|
||||
SetupStep.Welcome => true,
|
||||
SetupStep.Purpose => setupData.AgreedToTerms,
|
||||
SetupStep.PurposeInstructions => true,
|
||||
SetupStep.UserInfo => !string.IsNullOrWhiteSpace(setupData.Username),
|
||||
SetupStep.TermsAndConditions => setupData.AgreedToTerms,
|
||||
SetupStep.Username => !string.IsNullOrWhiteSpace(setupData.Username),
|
||||
SetupStep.Password => !string.IsNullOrWhiteSpace(setupData.Password),
|
||||
_ => false
|
||||
};
|
||||
@@ -93,17 +94,17 @@
|
||||
{
|
||||
switch (currentStep)
|
||||
{
|
||||
case SetupStep.Purpose:
|
||||
case SetupStep.TermsAndConditions:
|
||||
currentStep = SetupStep.Welcome;
|
||||
break;
|
||||
case SetupStep.PurposeInstructions:
|
||||
currentStep = SetupStep.Purpose;
|
||||
break;
|
||||
case SetupStep.UserInfo:
|
||||
currentStep = SetupStep.PurposeInstructions;
|
||||
case SetupStep.Username:
|
||||
currentStep = SetupStep.TermsAndConditions;
|
||||
break;
|
||||
case SetupStep.Password:
|
||||
currentStep = SetupStep.UserInfo;
|
||||
currentStep = SetupStep.Username;
|
||||
break;
|
||||
case SetupStep.Creating:
|
||||
currentStep = SetupStep.Password;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -112,79 +113,14 @@
|
||||
{
|
||||
currentStep = currentStep switch
|
||||
{
|
||||
SetupStep.Welcome => SetupStep.Purpose,
|
||||
SetupStep.Purpose => SetupStep.PurposeInstructions,
|
||||
SetupStep.PurposeInstructions => SetupStep.UserInfo,
|
||||
SetupStep.UserInfo => SetupStep.Password,
|
||||
SetupStep.Welcome => SetupStep.TermsAndConditions,
|
||||
SetupStep.TermsAndConditions => SetupStep.Username,
|
||||
SetupStep.Username => SetupStep.Password,
|
||||
SetupStep.Password => SetupStep.Creating,
|
||||
_ => currentStep
|
||||
};
|
||||
}
|
||||
|
||||
private async Task CompleteSetup()
|
||||
{
|
||||
LoadingIndicator.Show();
|
||||
StateHasChanged();
|
||||
|
||||
try
|
||||
{
|
||||
var client = new SrpClient();
|
||||
var salt = client.GenerateSalt();
|
||||
|
||||
string encryptionType = Defaults.EncryptionType;
|
||||
string encryptionSettings = Defaults.EncryptionSettings;
|
||||
if (Configuration["CryptographyOverrideType"] is not null && Configuration["CryptographyOverrideSettings"] is not null)
|
||||
{
|
||||
encryptionType = Configuration["CryptographyOverrideType"]!;
|
||||
encryptionSettings = Configuration["CryptographyOverrideSettings"]!;
|
||||
}
|
||||
|
||||
var passwordHash = await Encryption.DeriveKeyFromPasswordAsync(setupData.Password, salt, encryptionType, encryptionSettings);
|
||||
var passwordHashString = BitConverter.ToString(passwordHash).Replace("-", string.Empty);
|
||||
var srpSignup = Srp.PasswordChangeAsync(client, salt, setupData.Username, passwordHashString);
|
||||
|
||||
var registerRequest = new RegisterRequest(srpSignup.Username, srpSignup.Salt, srpSignup.Verifier, encryptionType, encryptionSettings);
|
||||
var result = await Http.PostAsJsonAsync("api/v1/Auth/register", registerRequest);
|
||||
var responseContent = await result.Content.ReadAsStringAsync();
|
||||
|
||||
if (!result.IsSuccessStatusCode)
|
||||
{
|
||||
foreach (var error in ApiResponseUtility.ParseErrorResponse(responseContent))
|
||||
{
|
||||
GlobalNotificationService.AddErrorMessage(error);
|
||||
}
|
||||
StateHasChanged();
|
||||
return;
|
||||
}
|
||||
|
||||
var tokenObject = JsonSerializer.Deserialize<TokenModel>(responseContent);
|
||||
|
||||
if (tokenObject != null)
|
||||
{
|
||||
await AuthService.StoreEncryptionKeyAsync(passwordHash);
|
||||
await AuthService.StoreAccessTokenAsync(tokenObject.Token);
|
||||
await AuthService.StoreRefreshTokenAsync(tokenObject.RefreshToken);
|
||||
await AuthStateProvider.GetAuthenticationStateAsync();
|
||||
|
||||
GlobalNotificationService.AddSuccessMessage("Account created successfully!");
|
||||
NavigationManager.NavigateTo("/");
|
||||
}
|
||||
else
|
||||
{
|
||||
GlobalNotificationService.AddErrorMessage("An error occurred during registration.");
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
GlobalNotificationService.AddErrorMessage($"An error occurred: {ex.Message}");
|
||||
}
|
||||
finally
|
||||
{
|
||||
LoadingIndicator.Hide();
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
||||
|
||||
private void CancelSetup()
|
||||
{
|
||||
NavigationManager.NavigateTo("/");
|
||||
@@ -199,10 +135,10 @@
|
||||
private enum SetupStep
|
||||
{
|
||||
Welcome,
|
||||
Purpose,
|
||||
PurposeInstructions,
|
||||
UserInfo,
|
||||
Password
|
||||
TermsAndConditions,
|
||||
Username,
|
||||
Password,
|
||||
Creating
|
||||
}
|
||||
|
||||
private class SetupData
|
||||
@@ -216,11 +152,11 @@
|
||||
{
|
||||
return step switch
|
||||
{
|
||||
SetupStep.Welcome => "Welcome",
|
||||
SetupStep.Purpose => "Terms and Conditions",
|
||||
SetupStep.PurposeInstructions => "Purpose Instructions",
|
||||
SetupStep.UserInfo => "Choose Username",
|
||||
SetupStep.Welcome => "Welcome to AliasVault",
|
||||
SetupStep.TermsAndConditions => "Using AliasVault",
|
||||
SetupStep.Username => "Choose Username",
|
||||
SetupStep.Password => "Set Password",
|
||||
SetupStep.Creating => "Creating Vault",
|
||||
_ => "Setup"
|
||||
};
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
return;
|
||||
}
|
||||
|
||||
<div class="messages-container grid px-4 pt-6 lg:gap-4 dark:bg-gray-900">
|
||||
<div class="messages-container grid px-4 pt-6 lg:gap-4">
|
||||
@foreach (var message in Messages)
|
||||
{
|
||||
if (message.Key == "success")
|
||||
|
||||
@@ -849,6 +849,14 @@ video {
|
||||
margin-top: 4rem;
|
||||
}
|
||||
|
||||
.mb-10 {
|
||||
margin-bottom: 2.5rem;
|
||||
}
|
||||
|
||||
.mt-10 {
|
||||
margin-top: 2.5rem;
|
||||
}
|
||||
|
||||
.line-clamp-2 {
|
||||
overflow: hidden;
|
||||
display: -webkit-box;
|
||||
@@ -1361,6 +1369,11 @@ video {
|
||||
border-color: rgb(214 131 56 / var(--tw-border-opacity));
|
||||
}
|
||||
|
||||
.border-yellow-500 {
|
||||
--tw-border-opacity: 1;
|
||||
border-color: rgb(234 179 8 / var(--tw-border-opacity));
|
||||
}
|
||||
|
||||
.bg-blue-100 {
|
||||
--tw-bg-opacity: 1;
|
||||
background-color: rgb(219 234 254 / var(--tw-bg-opacity));
|
||||
@@ -1506,6 +1519,11 @@ video {
|
||||
background-color: rgb(254 252 232 / var(--tw-bg-opacity));
|
||||
}
|
||||
|
||||
.bg-yellow-100 {
|
||||
--tw-bg-opacity: 1;
|
||||
background-color: rgb(254 249 195 / var(--tw-bg-opacity));
|
||||
}
|
||||
|
||||
.bg-opacity-50 {
|
||||
--tw-bg-opacity: 0.5;
|
||||
}
|
||||
@@ -1913,6 +1931,11 @@ video {
|
||||
color: rgb(133 77 14 / var(--tw-text-opacity));
|
||||
}
|
||||
|
||||
.text-yellow-700 {
|
||||
--tw-text-opacity: 1;
|
||||
color: rgb(161 98 7 / var(--tw-text-opacity));
|
||||
}
|
||||
|
||||
.opacity-0 {
|
||||
opacity: 0;
|
||||
}
|
||||
@@ -2383,6 +2406,11 @@ video {
|
||||
background-color: rgb(133 77 14 / var(--tw-bg-opacity));
|
||||
}
|
||||
|
||||
.dark\:bg-yellow-900:is(.dark *) {
|
||||
--tw-bg-opacity: 1;
|
||||
background-color: rgb(113 63 18 / var(--tw-bg-opacity));
|
||||
}
|
||||
|
||||
.dark\:bg-opacity-80:is(.dark *) {
|
||||
--tw-bg-opacity: 0.8;
|
||||
}
|
||||
@@ -2462,6 +2490,11 @@ video {
|
||||
color: rgb(250 204 21 / var(--tw-text-opacity));
|
||||
}
|
||||
|
||||
.dark\:text-yellow-200:is(.dark *) {
|
||||
--tw-text-opacity: 1;
|
||||
color: rgb(254 240 138 / 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));
|
||||
|
||||
Reference in New Issue
Block a user