diff --git a/demo/Ursa.Demo/App.axaml b/demo/Ursa.Demo/App.axaml
index 218b0f4..e9083c2 100644
--- a/demo/Ursa.Demo/App.axaml
+++ b/demo/Ursa.Demo/App.axaml
@@ -4,7 +4,7 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:Ursa.Demo">
-
+
diff --git a/demo/Ursa.Demo/Pages/BadgeDemo.axaml b/demo/Ursa.Demo/Pages/BadgeDemo.axaml
new file mode 100644
index 0000000..4a3bfd0
--- /dev/null
+++ b/demo/Ursa.Demo/Pages/BadgeDemo.axaml
@@ -0,0 +1,190 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/demo/Ursa.Demo/Pages/BadgeDemo.axaml.cs b/demo/Ursa.Demo/Pages/BadgeDemo.axaml.cs
new file mode 100644
index 0000000..eec79bf
--- /dev/null
+++ b/demo/Ursa.Demo/Pages/BadgeDemo.axaml.cs
@@ -0,0 +1,18 @@
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Markup.Xaml;
+
+namespace Ursa.Demo.Pages;
+
+public partial class BadgeDemo : UserControl
+{
+ public BadgeDemo()
+ {
+ InitializeComponent();
+ }
+
+ private void InitializeComponent()
+ {
+ AvaloniaXamlLoader.Load(this);
+ }
+}
\ No newline at end of file
diff --git a/demo/Ursa.Demo/Pages/BannerDemo.axaml.cs b/demo/Ursa.Demo/Pages/BannerDemo.axaml.cs
index 8ea8b76..b4d2c86 100644
--- a/demo/Ursa.Demo/Pages/BannerDemo.axaml.cs
+++ b/demo/Ursa.Demo/Pages/BannerDemo.axaml.cs
@@ -14,6 +14,11 @@ public partial class BannerDemo : UserControl
InitializeComponent();
this.DataContext = new BannerDemoViewModel();
}
+
+ private void InitializeComponent()
+ {
+ AvaloniaXamlLoader.Load(this);
+ }
}
public class BannerDemoViewModel: ViewModelBase
diff --git a/demo/Ursa.Demo/Views/MainWindow.axaml b/demo/Ursa.Demo/Views/MainWindow.axaml
index 860266a..a5c4284 100644
--- a/demo/Ursa.Demo/Views/MainWindow.axaml
+++ b/demo/Ursa.Demo/Views/MainWindow.axaml
@@ -16,10 +16,20 @@
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
diff --git a/demo/Ursa.Demo/Views/MainWindow.axaml.cs b/demo/Ursa.Demo/Views/MainWindow.axaml.cs
index 45aa4b8..ff545b9 100644
--- a/demo/Ursa.Demo/Views/MainWindow.axaml.cs
+++ b/demo/Ursa.Demo/Views/MainWindow.axaml.cs
@@ -1,4 +1,7 @@
+using Avalonia;
using Avalonia.Controls;
+using Avalonia.Interactivity;
+using Avalonia.Styling;
namespace Ursa.Demo.Views;
@@ -8,4 +11,14 @@ public partial class MainWindow : Window
{
InitializeComponent();
}
+
+ private void ToggleButton_OnIsCheckedChanged(object? sender, RoutedEventArgs e)
+ {
+ var app = Application.Current;
+ if (app is not null)
+ {
+ var theme = app.ActualThemeVariant;
+ app.RequestedThemeVariant = theme == ThemeVariant.Dark ? ThemeVariant.Light : ThemeVariant.Dark;
+ }
+ }
}
\ No newline at end of file
diff --git a/src/Ursa.Themes.Semi/Controls/Badge.axaml b/src/Ursa.Themes.Semi/Controls/Badge.axaml
new file mode 100644
index 0000000..cf6896f
--- /dev/null
+++ b/src/Ursa.Themes.Semi/Controls/Badge.axaml
@@ -0,0 +1,134 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Ursa.Themes.Semi/Controls/_index.axaml b/src/Ursa.Themes.Semi/Controls/_index.axaml
index 8827a5d..8b9ac73 100644
--- a/src/Ursa.Themes.Semi/Controls/_index.axaml
+++ b/src/Ursa.Themes.Semi/Controls/_index.axaml
@@ -1,6 +1,7 @@
+
diff --git a/src/Ursa.Themes.Semi/Index.axaml b/src/Ursa.Themes.Semi/Index.axaml
index 5c182e5..e1d3523 100644
--- a/src/Ursa.Themes.Semi/Index.axaml
+++ b/src/Ursa.Themes.Semi/Index.axaml
@@ -8,10 +8,10 @@
-
+
-
+
diff --git a/src/Ursa.Themes.Semi/Themes/Dark/Badge.axaml b/src/Ursa.Themes.Semi/Themes/Dark/Badge.axaml
new file mode 100644
index 0000000..f621202
--- /dev/null
+++ b/src/Ursa.Themes.Semi/Themes/Dark/Badge.axaml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Ursa.Themes.Semi/Themes/Dark/Banner.axaml b/src/Ursa.Themes.Semi/Themes/Dark/Banner.axaml
index 9017e8d..74df0ab 100644
--- a/src/Ursa.Themes.Semi/Themes/Dark/Banner.axaml
+++ b/src/Ursa.Themes.Semi/Themes/Dark/Banner.axaml
@@ -1,3 +1,13 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Ursa.Themes.Semi/Themes/Dark/_index.axaml b/src/Ursa.Themes.Semi/Themes/Dark/_index.axaml
index 8827a5d..8b9ac73 100644
--- a/src/Ursa.Themes.Semi/Themes/Dark/_index.axaml
+++ b/src/Ursa.Themes.Semi/Themes/Dark/_index.axaml
@@ -1,6 +1,7 @@
+
diff --git a/src/Ursa.Themes.Semi/Themes/Light/Badge.axaml b/src/Ursa.Themes.Semi/Themes/Light/Badge.axaml
new file mode 100644
index 0000000..f621202
--- /dev/null
+++ b/src/Ursa.Themes.Semi/Themes/Light/Badge.axaml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Ursa.Themes.Semi/Themes/Light/_index.axaml b/src/Ursa.Themes.Semi/Themes/Light/_index.axaml
index 8827a5d..8b9ac73 100644
--- a/src/Ursa.Themes.Semi/Themes/Light/_index.axaml
+++ b/src/Ursa.Themes.Semi/Themes/Light/_index.axaml
@@ -1,6 +1,7 @@
+
diff --git a/src/Ursa.Themes.Semi/Themes/Shared/Badge.axaml b/src/Ursa.Themes.Semi/Themes/Shared/Badge.axaml
new file mode 100644
index 0000000..688be66
--- /dev/null
+++ b/src/Ursa.Themes.Semi/Themes/Shared/Badge.axaml
@@ -0,0 +1,8 @@
+
+
+ 18
+ 8
+ 6,0
+ 1
+ 8
+
diff --git a/src/Ursa.Themes.Semi/Themes/Shared/_index.axaml b/src/Ursa.Themes.Semi/Themes/Shared/_index.axaml
index 8827a5d..8b9ac73 100644
--- a/src/Ursa.Themes.Semi/Themes/Shared/_index.axaml
+++ b/src/Ursa.Themes.Semi/Themes/Shared/_index.axaml
@@ -1,6 +1,7 @@
+
diff --git a/src/Ursa/Common/CornerPosition.cs b/src/Ursa/Common/CornerPosition.cs
new file mode 100644
index 0000000..ba85776
--- /dev/null
+++ b/src/Ursa/Common/CornerPosition.cs
@@ -0,0 +1,9 @@
+namespace Ursa.Common;
+
+public enum CornerPosition
+{
+ TopLeft,
+ TopRight,
+ BottomLeft,
+ BottomRight,
+}
\ No newline at end of file
diff --git a/src/Ursa/Controls/Badge.cs b/src/Ursa/Controls/Badge.cs
new file mode 100644
index 0000000..72b2c0f
--- /dev/null
+++ b/src/Ursa/Controls/Badge.cs
@@ -0,0 +1,105 @@
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Controls.Metadata;
+using Avalonia.Controls.Presenters;
+using Avalonia.Controls.Primitives;
+using Avalonia.Media;
+using Avalonia.Styling;
+using Ursa.Common;
+
+namespace Ursa.Controls;
+
+[TemplatePart(PART_ContentPresenter, typeof(ContentPresenter))]
+[TemplatePart(PART_BadgeContainer, typeof(Border))]
+[TemplatePart(PART_BadgeContentPresenter, typeof(ContentPresenter))]
+public class Badge: ContentControl
+{
+ public const string PART_ContentPresenter = "PART_ContentPresenter";
+ public const string PART_BadgeContainer = "PART_BadgeContainer";
+ public const string PART_BadgeContentPresenter = "PART_BadgeContentPresenter";
+
+ private ContentPresenter? _content;
+ private Border? _badgeContainer;
+ private ContentPresenter? _badgeContent;
+
+ public static readonly StyledProperty BadgeThemeProperty = AvaloniaProperty.Register(
+ nameof(BadgeTheme));
+ public ControlTheme BadgeTheme
+ {
+ get => GetValue(BadgeThemeProperty);
+ set => SetValue(BadgeThemeProperty, value);
+ }
+
+ public static readonly StyledProperty DotProperty = AvaloniaProperty.Register(
+ nameof(Dot));
+ public bool Dot
+ {
+ get => GetValue(DotProperty);
+ set => SetValue(DotProperty, value);
+ }
+
+ public static readonly StyledProperty