Redesign Wino Account login and registration dialogs (#835)

Add hero illustrations using XAML-native vector graphics (shield+lock
for login, person+plus badge for registration). Improve visual design
with gradient backgrounds, icon badges on benefit cards, and refined
spacing/corner radii. Add Enter key handling so pressing Enter in an
input field moves focus to the next field, and pressing Enter on the
last field triggers the primary action (login/register).

https://claude.ai/code/session_011B1M6UVeo4yUX3zNHBxQ2P

Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
Burak Kaan Köse
2026-03-17 16:08:04 +01:00
committed by GitHub
parent ea204fef21
commit 4a94dfb10c
4 changed files with 466 additions and 61 deletions
@@ -19,65 +19,218 @@
</ContentDialog.Resources>
<ScrollViewer VerticalScrollBarVisibility="Auto">
<StackPanel Spacing="16">
<StackPanel Spacing="20">
<!-- Hero illustration area -->
<Border
Padding="14"
Background="{ThemeResource CardBackgroundFillColorSecondaryBrush}"
CornerRadius="16">
<Grid ColumnSpacing="12">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<FontIcon
FontSize="18"
Foreground="{ThemeResource AccentTextFillColorPrimaryBrush}"
Glyph="&#xE8D7;" />
<StackPanel Grid.Column="1" Spacing="4">
<TextBlock Style="{StaticResource BodyStrongTextBlockStyle}" Text="{x:Bind domain:Translator.WinoAccount_LoginDialog_BenefitsTitle}" />
<TextBlock
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
Text="{x:Bind domain:Translator.WinoAccount_LoginDialog_BenefitsDescription}"
TextWrapping="WrapWholeWords" />
</StackPanel>
</Grid>
Height="140"
CornerRadius="12">
<Border.Background>
<LinearGradientBrush StartPoint="0,0" EndPoint="1,1">
<GradientStop Offset="0" Color="#1A6EE7B7" />
<GradientStop Offset="0.5" Color="#2038BDF8" />
<GradientStop Offset="1" Color="#1A818CF8" />
</LinearGradientBrush>
</Border.Background>
<Canvas>
<!-- Background decorative circles -->
<Ellipse
Canvas.Left="340"
Canvas.Top="-20"
Width="100"
Height="100"
Opacity="0.15">
<Ellipse.Fill>
<RadialGradientBrush>
<GradientStop Offset="0" Color="#38BDF8" />
<GradientStop Offset="1" Color="Transparent" />
</RadialGradientBrush>
</Ellipse.Fill>
</Ellipse>
<Ellipse
Canvas.Left="20"
Canvas.Top="80"
Width="80"
Height="80"
Opacity="0.1">
<Ellipse.Fill>
<RadialGradientBrush>
<GradientStop Offset="0" Color="#6EE7B7" />
<GradientStop Offset="1" Color="Transparent" />
</RadialGradientBrush>
</Ellipse.Fill>
</Ellipse>
<!-- Shield with lock illustration -->
<Canvas Canvas.Left="190" Canvas.Top="16">
<!-- Shield shape -->
<Path
Data="M46 4 L82 18 L82 48 C82 66 65 80 46 84 C27 80 10 66 10 48 L10 18 Z"
Opacity="0.9">
<Path.Fill>
<LinearGradientBrush StartPoint="0,0" EndPoint="1,1">
<GradientStop Offset="0" Color="#6EE7B7" />
<GradientStop Offset="1" Color="#059669" />
</LinearGradientBrush>
</Path.Fill>
</Path>
<!-- Inner shield -->
<Path
Data="M46 12 L76 24 L76 48 C76 64 62 76 46 80 C30 76 16 64 16 48 L16 24 Z"
Opacity="0.5">
<Path.Fill>
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
<GradientStop Offset="0" Color="#A7F3D0" />
<GradientStop Offset="1" Color="#34D399" />
</LinearGradientBrush>
</Path.Fill>
</Path>
<!-- Lock body -->
<Rectangle
Canvas.Left="32"
Canvas.Top="44"
Width="28"
Height="20"
Fill="White"
RadiusX="5"
RadiusY="5" />
<!-- Lock shackle -->
<Path
Data="M38 44 L38 38 A8 8 0 0 1 54 38 L54 44"
Stroke="White"
StrokeEndLineCap="Round"
StrokeStartLineCap="Round"
StrokeThickness="4"
Fill="Transparent" />
<!-- Keyhole -->
<Ellipse
Canvas.Left="42"
Canvas.Top="49"
Width="8"
Height="8"
Fill="#059669" />
<Rectangle
Canvas.Left="44"
Canvas.Top="55"
Width="4"
Height="6"
Fill="#059669"
RadiusX="2"
RadiusY="2" />
</Canvas>
<!-- Decorative sparkles -->
<Ellipse
Canvas.Left="150"
Canvas.Top="30"
Width="6"
Height="6"
Fill="{ThemeResource AccentTextFillColorPrimaryBrush}"
Opacity="0.5" />
<Ellipse
Canvas.Left="320"
Canvas.Top="50"
Width="5"
Height="5"
Fill="#6EE7B7"
Opacity="0.6" />
<Ellipse
Canvas.Left="130"
Canvas.Top="100"
Width="4"
Height="4"
Fill="#38BDF8"
Opacity="0.4" />
<Ellipse
Canvas.Left="360"
Canvas.Top="100"
Width="4"
Height="4"
Fill="#A78BFA"
Opacity="0.5" />
</Canvas>
</Border>
<Border
Padding="14"
Background="{ThemeResource CardBackgroundFillColorSecondaryBrush}"
BorderBrush="{ThemeResource TextFillColorDisabledBrush}"
BorderThickness="1"
CornerRadius="16">
<Grid ColumnSpacing="12">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<FontIcon
FontSize="18"
Foreground="{ThemeResource AccentTextFillColorPrimaryBrush}"
Glyph="&#xE946;" />
<StackPanel Grid.Column="1" Spacing="4">
<TextBlock Style="{StaticResource BodyStrongTextBlockStyle}" Text="{x:Bind domain:Translator.WinoAccount_LoginDialog_DifferenceTitle}" />
<TextBlock
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
Text="{x:Bind domain:Translator.WinoAccount_LoginDialog_DifferenceDescription}"
TextWrapping="WrapWholeWords" />
</StackPanel>
</Grid>
</Border>
<!-- Benefits cards -->
<StackPanel Spacing="8">
<Border
Padding="14"
Background="{ThemeResource CardBackgroundFillColorSecondaryBrush}"
CornerRadius="12">
<Grid ColumnSpacing="12">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Border
Width="36"
Height="36"
Background="{ThemeResource AccentFillColorDefaultBrush}"
CornerRadius="8"
Opacity="0.15" />
<FontIcon
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontSize="16"
Foreground="{ThemeResource AccentTextFillColorPrimaryBrush}"
Glyph="&#xE8D7;" />
<StackPanel Grid.Column="1" Spacing="2">
<TextBlock Style="{StaticResource BodyStrongTextBlockStyle}" Text="{x:Bind domain:Translator.WinoAccount_LoginDialog_BenefitsTitle}" />
<TextBlock
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
Style="{StaticResource CaptionTextBlockStyle}"
Text="{x:Bind domain:Translator.WinoAccount_LoginDialog_BenefitsDescription}"
TextWrapping="WrapWholeWords" />
</StackPanel>
</Grid>
</Border>
<Border
Padding="14"
Background="{ThemeResource CardBackgroundFillColorSecondaryBrush}"
CornerRadius="12">
<Grid ColumnSpacing="12">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Border
Width="36"
Height="36"
Background="{ThemeResource AccentFillColorDefaultBrush}"
CornerRadius="8"
Opacity="0.15" />
<FontIcon
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontSize="16"
Foreground="{ThemeResource AccentTextFillColorPrimaryBrush}"
Glyph="&#xE946;" />
<StackPanel Grid.Column="1" Spacing="2">
<TextBlock Style="{StaticResource BodyStrongTextBlockStyle}" Text="{x:Bind domain:Translator.WinoAccount_LoginDialog_DifferenceTitle}" />
<TextBlock
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
Style="{StaticResource CaptionTextBlockStyle}"
Text="{x:Bind domain:Translator.WinoAccount_LoginDialog_DifferenceDescription}"
TextWrapping="WrapWholeWords" />
</StackPanel>
</Grid>
</Border>
</StackPanel>
<!-- Input fields -->
<StackPanel Spacing="12">
<TextBox
x:Name="EmailTextBox"
Header="{x:Bind domain:Translator.WinoAccount_EmailLabel}"
KeyDown="EmailTextBox_KeyDown"
PlaceholderText="{x:Bind domain:Translator.WinoAccount_EmailPlaceholder}"
TextChanging="InputChanged" />
<PasswordBox
x:Name="PasswordBox"
Header="{x:Bind domain:Translator.WinoAccount_PasswordLabel}"
KeyDown="PasswordBox_KeyDown"
PasswordChanged="InputChanged" />
</StackPanel>
@@ -1,5 +1,7 @@
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Input;
using Windows.System;
using Wino.Core.Domain;
using Wino.Core.Domain.Entities.Shared;
using Wino.Core.Domain.Interfaces;
@@ -32,6 +34,25 @@ public sealed partial class WinoAccountLoginDialog : ContentDialog
var deferral = args.GetDeferral();
try
{
await PerformLoginAsync();
}
finally
{
deferral.Complete();
}
}
private async System.Threading.Tasks.Task PerformLoginAsync()
{
var validationError = ValidateInput();
if (!string.IsNullOrWhiteSpace(validationError))
{
ShowError(validationError);
return;
}
try
{
SetBusyState(true);
@@ -46,13 +67,11 @@ public sealed partial class WinoAccountLoginDialog : ContentDialog
}
Result = result.Account;
args.Cancel = false;
Hide();
}
finally
{
SetBusyState(false);
deferral.Complete();
}
}
@@ -71,6 +90,24 @@ public sealed partial class WinoAccountLoginDialog : ContentDialog
return string.Empty;
}
private void EmailTextBox_KeyDown(object sender, KeyRoutedEventArgs e)
{
if (e.Key == VirtualKey.Enter)
{
PasswordBox.Focus(FocusState.Programmatic);
e.Handled = true;
}
}
private async void PasswordBox_KeyDown(object sender, KeyRoutedEventArgs e)
{
if (e.Key == VirtualKey.Enter)
{
e.Handled = true;
await PerformLoginAsync();
}
}
private void InputChanged(TextBox sender, TextBoxTextChangingEventArgs args) => HideError();
private void InputChanged(object sender, RoutedEventArgs e) => HideError();
@@ -19,31 +19,187 @@
</ContentDialog.Resources>
<ScrollViewer VerticalScrollBarVisibility="Auto">
<StackPanel Spacing="4">
<Image
Width="64"
Height="64"
Source="/Assets/AppEntries/MailAssets/LargeTile.png" />
<StackPanel Spacing="10">
<TextBlock Style="{StaticResource BodyStrongTextBlockStyle}" Text="{x:Bind domain:Translator.WinoAccount_RegisterDialog_BenefitsTitle}" />
<StackPanel Spacing="20">
<!-- Hero illustration area -->
<Border
Height="140"
CornerRadius="12">
<Border.Background>
<LinearGradientBrush StartPoint="0,0" EndPoint="1,1">
<GradientStop Offset="0" Color="#1A818CF8" />
<GradientStop Offset="0.5" Color="#20A78BFA" />
<GradientStop Offset="1" Color="#1AE879F9" />
</LinearGradientBrush>
</Border.Background>
<Canvas>
<!-- Background decorative circles -->
<Ellipse
Canvas.Left="370"
Canvas.Top="-10"
Width="90"
Height="90"
Opacity="0.12">
<Ellipse.Fill>
<RadialGradientBrush>
<GradientStop Offset="0" Color="#A78BFA" />
<GradientStop Offset="1" Color="Transparent" />
</RadialGradientBrush>
</Ellipse.Fill>
</Ellipse>
<Ellipse
Canvas.Left="30"
Canvas.Top="90"
Width="70"
Height="70"
Opacity="0.1">
<Ellipse.Fill>
<RadialGradientBrush>
<GradientStop Offset="0" Color="#38BDF8" />
<GradientStop Offset="1" Color="Transparent" />
</RadialGradientBrush>
</Ellipse.Fill>
</Ellipse>
<!-- Person/account illustration -->
<Canvas Canvas.Left="200" Canvas.Top="12">
<!-- Circular badge background -->
<Ellipse
Canvas.Left="8"
Canvas.Top="8"
Width="80"
Height="80"
Opacity="0.9">
<Ellipse.Fill>
<LinearGradientBrush StartPoint="0,0" EndPoint="1,1">
<GradientStop Offset="0" Color="#818CF8" />
<GradientStop Offset="1" Color="#6366F1" />
</LinearGradientBrush>
</Ellipse.Fill>
</Ellipse>
<!-- Inner circle -->
<Ellipse
Canvas.Left="14"
Canvas.Top="14"
Width="68"
Height="68"
Opacity="0.35">
<Ellipse.Fill>
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
<GradientStop Offset="0" Color="#C7D2FE" />
<GradientStop Offset="1" Color="#A5B4FC" />
</LinearGradientBrush>
</Ellipse.Fill>
</Ellipse>
<!-- Person head -->
<Ellipse
Canvas.Left="34"
Canvas.Top="24"
Width="28"
Height="28"
Fill="White" />
<!-- Person body -->
<Path
Data="M28 68 A20 16 0 0 1 68 68"
Fill="White" />
<!-- Plus badge -->
<Ellipse
Canvas.Left="62"
Canvas.Top="62"
Width="28"
Height="28">
<Ellipse.Fill>
<LinearGradientBrush StartPoint="0,0" EndPoint="1,1">
<GradientStop Offset="0" Color="#4ADE80" />
<GradientStop Offset="1" Color="#16A34A" />
</LinearGradientBrush>
</Ellipse.Fill>
</Ellipse>
<!-- Plus sign -->
<Rectangle
Canvas.Left="73"
Canvas.Top="70"
Width="4"
Height="16"
Fill="White"
RadiusX="2"
RadiusY="2" />
<Rectangle
Canvas.Left="69"
Canvas.Top="74"
Width="12"
Height="4"
Fill="White"
RadiusX="2"
RadiusY="2" />
</Canvas>
<!-- Decorative sparkles -->
<Ellipse
Canvas.Left="140"
Canvas.Top="35"
Width="6"
Height="6"
Fill="#A78BFA"
Opacity="0.5" />
<Ellipse
Canvas.Left="350"
Canvas.Top="55"
Width="5"
Height="5"
Fill="#38BDF8"
Opacity="0.6" />
<Ellipse
Canvas.Left="120"
Canvas.Top="95"
Width="4"
Height="4"
Fill="#6EE7B7"
Opacity="0.4" />
<Ellipse
Canvas.Left="380"
Canvas.Top="105"
Width="4"
Height="4"
Fill="#F472B6"
Opacity="0.5" />
</Canvas>
</Border>
<!-- Benefits section -->
<StackPanel Spacing="8">
<TextBlock
Margin="0,0,0,4"
Style="{StaticResource BodyStrongTextBlockStyle}"
Text="{x:Bind domain:Translator.WinoAccount_RegisterDialog_BenefitsTitle}" />
<Border
Padding="14"
Background="{ThemeResource CardBackgroundFillColorSecondaryBrush}"
CornerRadius="16">
CornerRadius="12">
<Grid ColumnSpacing="12">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Border
Width="36"
Height="36"
Background="{ThemeResource AccentFillColorDefaultBrush}"
CornerRadius="8"
Opacity="0.15" />
<FontIcon
FontSize="18"
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontSize="16"
Foreground="{ThemeResource AccentTextFillColorPrimaryBrush}"
Glyph="&#xE8D7;" />
<StackPanel Grid.Column="1" Spacing="2">
<TextBlock Style="{StaticResource BodyStrongTextBlockStyle}" Text="{x:Bind domain:Translator.WinoAccount_RegisterDialog_BenefitSyncTitle}" />
<TextBlock
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
Style="{StaticResource CaptionTextBlockStyle}"
Text="{x:Bind domain:Translator.WinoAccount_RegisterDialog_BenefitSyncDescription}"
TextWrapping="WrapWholeWords" />
</StackPanel>
@@ -53,20 +209,29 @@
<Border
Padding="14"
Background="{ThemeResource CardBackgroundFillColorSecondaryBrush}"
CornerRadius="16">
CornerRadius="12">
<Grid ColumnSpacing="12">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Border
Width="36"
Height="36"
Background="{ThemeResource AccentFillColorDefaultBrush}"
CornerRadius="8"
Opacity="0.15" />
<FontIcon
FontSize="18"
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontSize="16"
Foreground="{ThemeResource AccentTextFillColorPrimaryBrush}"
Glyph="&#xEA18;" />
<StackPanel Grid.Column="1" Spacing="2">
<TextBlock Style="{StaticResource BodyStrongTextBlockStyle}" Text="{x:Bind domain:Translator.WinoAccount_RegisterDialog_BenefitAiTitle}" />
<TextBlock
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
Style="{StaticResource CaptionTextBlockStyle}"
Text="{x:Bind domain:Translator.WinoAccount_RegisterDialog_BenefitAiDescription}"
TextWrapping="WrapWholeWords" />
</StackPanel>
@@ -74,21 +239,25 @@
</Border>
</StackPanel>
<StackPanel Margin="0,12" Spacing="12">
<!-- Input fields -->
<StackPanel Spacing="12">
<TextBox
x:Name="EmailTextBox"
Header="{x:Bind domain:Translator.WinoAccount_EmailLabel}"
KeyDown="EmailTextBox_KeyDown"
PlaceholderText="{x:Bind domain:Translator.WinoAccount_EmailPlaceholder}"
TextChanging="InputChanged" />
<PasswordBox
x:Name="PasswordBox"
Header="{x:Bind domain:Translator.WinoAccount_PasswordLabel}"
KeyDown="PasswordBox_KeyDown"
PasswordChanged="InputChanged" />
<PasswordBox
x:Name="ConfirmPasswordBox"
Header="{x:Bind domain:Translator.WinoAccount_ConfirmPasswordLabel}"
KeyDown="ConfirmPasswordBox_KeyDown"
PasswordChanged="InputChanged" />
</StackPanel>
@@ -1,6 +1,8 @@
using System;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Input;
using Windows.System;
using Wino.Core.Domain;
using Wino.Core.Domain.Entities.Shared;
using Wino.Core.Domain.Interfaces;
@@ -33,6 +35,25 @@ public sealed partial class WinoAccountRegistrationDialog : ContentDialog
var deferral = args.GetDeferral();
try
{
await PerformRegistrationAsync();
}
finally
{
deferral.Complete();
}
}
private async System.Threading.Tasks.Task PerformRegistrationAsync()
{
var validationError = ValidateInput();
if (!string.IsNullOrWhiteSpace(validationError))
{
ShowError(validationError);
return;
}
try
{
SetBusyState(true);
@@ -47,13 +68,11 @@ public sealed partial class WinoAccountRegistrationDialog : ContentDialog
}
Result = result.Account;
args.Cancel = false;
Hide();
}
finally
{
SetBusyState(false);
deferral.Complete();
}
}
@@ -77,6 +96,33 @@ public sealed partial class WinoAccountRegistrationDialog : ContentDialog
return string.Empty;
}
private void EmailTextBox_KeyDown(object sender, KeyRoutedEventArgs e)
{
if (e.Key == VirtualKey.Enter)
{
PasswordBox.Focus(FocusState.Programmatic);
e.Handled = true;
}
}
private void PasswordBox_KeyDown(object sender, KeyRoutedEventArgs e)
{
if (e.Key == VirtualKey.Enter)
{
ConfirmPasswordBox.Focus(FocusState.Programmatic);
e.Handled = true;
}
}
private async void ConfirmPasswordBox_KeyDown(object sender, KeyRoutedEventArgs e)
{
if (e.Key == VirtualKey.Enter)
{
e.Handled = true;
await PerformRegistrationAsync();
}
}
private void InputChanged(TextBox sender, TextBoxTextChangingEventArgs args) => HideError();
private void InputChanged(object sender, RoutedEventArgs e) => HideError();