diff --git a/CubeKit.slnx b/CubeKit.slnx
index c7eb810..b989b43 100644
--- a/CubeKit.slnx
+++ b/CubeKit.slnx
@@ -36,6 +36,7 @@
+
@@ -63,6 +64,7 @@
+
@@ -77,6 +79,9 @@
+
+
+
@@ -98,6 +103,7 @@
+
diff --git a/eng/MultiTarget/GlobalUsings.cs b/eng/MultiTarget/GlobalUsings.cs
index 36d63fa..9234bca 100644
--- a/eng/MultiTarget/GlobalUsings.cs
+++ b/eng/MultiTarget/GlobalUsings.cs
@@ -32,6 +32,7 @@
global using global::Microsoft.UI.Xaml.Media.Animation;
global using global::Microsoft.UI.Xaml.Shapes;
global using global::Microsoft.UI.Xaml.Controls.Primitives;
+global using global::Microsoft.UI.Xaml.Automation;
#elif Uwp
global using global::Windows;
global using global::Windows.UI.Xaml;
@@ -47,6 +48,7 @@
global using global::Windows.UI.Xaml.Media.Animation;
global using global::Windows.UI.Xaml.Shapes;
global using global::Windows.UI.Xaml.Controls.Primitives;
+global using global::Windows.UI.Xaml.Automation;
#elif Wpf
global using global::System.Windows;
global using global::System.Windows.Controls;
diff --git a/src/core/Riverside.Toolkit.Controls.Settings/Riverside.Toolkit.Controls.Settings.projitems b/src/core/Riverside.Toolkit.Controls.Settings/Riverside.Toolkit.Controls.Settings.projitems
new file mode 100644
index 0000000..a91304e
--- /dev/null
+++ b/src/core/Riverside.Toolkit.Controls.Settings/Riverside.Toolkit.Controls.Settings.projitems
@@ -0,0 +1,19 @@
+
+
+
+ $(MSBuildAllProjects);$(MSBuildThisFileFullPath)
+ true
+ d131c7fe-6aed-4515-8c28-17da95b09fea
+
+
+ Riverside.Toolkit.Controls.Settings
+
+
+
+
+ $(DefaultXamlRuntime)
+ MSBuild:Compile
+ Designer
+
+
+
diff --git a/src/core/Riverside.Toolkit.Controls.Settings/Riverside.Toolkit.Controls.Settings.shproj b/src/core/Riverside.Toolkit.Controls.Settings/Riverside.Toolkit.Controls.Settings.shproj
new file mode 100644
index 0000000..d68c3ef
--- /dev/null
+++ b/src/core/Riverside.Toolkit.Controls.Settings/Riverside.Toolkit.Controls.Settings.shproj
@@ -0,0 +1,13 @@
+
+
+
+ d131c7fe-6aed-4515-8c28-17da95b09fea
+ 14.0
+
+
+
+
+
+
+
+
diff --git a/src/core/Riverside.Toolkit.Controls.Settings/SettingsBlockControl.xaml b/src/core/Riverside.Toolkit.Controls.Settings/SettingsBlockControl.xaml
new file mode 100644
index 0000000..0aa1317
--- /dev/null
+++ b/src/core/Riverside.Toolkit.Controls.Settings/SettingsBlockControl.xaml
@@ -0,0 +1,117 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/core/Riverside.Toolkit.Controls.Settings/SettingsBlockControl.xaml.cs b/src/core/Riverside.Toolkit.Controls.Settings/SettingsBlockControl.xaml.cs
new file mode 100644
index 0000000..28f5d3f
--- /dev/null
+++ b/src/core/Riverside.Toolkit.Controls.Settings/SettingsBlockControl.xaml.cs
@@ -0,0 +1,139 @@
+using System;
+using System.Windows.Input;
+
+namespace Riverside.Toolkit.Controls
+{
+ [ContentProperty(Name = nameof(SettingsActionableElement))]
+ public sealed partial class SettingsBlockControl : UserControl
+ {
+ public FrameworkElement SettingsActionableElement { get; set; }
+
+ public ICommand ButtonCommand
+ {
+ get { return (ICommand)GetValue(ButtonCommandProperty); }
+ set { SetValue(ButtonCommandProperty, value); }
+ }
+ public static readonly DependencyProperty ButtonCommandProperty =
+ DependencyProperty.Register("ButtonCommand", typeof(ICommand), typeof(SettingsBlockControl), new PropertyMetadata(null));
+
+ public static readonly DependencyProperty ExpandableContentProperty = DependencyProperty.Register(
+ "ExpandableContent",
+ typeof(FrameworkElement),
+ typeof(SettingsBlockControl),
+ new PropertyMetadata(null)
+ );
+
+ public FrameworkElement ExpandableContent
+ {
+ get => (FrameworkElement)GetValue(ExpandableContentProperty);
+ set => SetValue(ExpandableContentProperty, value);
+ }
+
+ public static readonly DependencyProperty AdditionalDescriptionContentProperty = DependencyProperty.Register(
+ "AdditionalDescriptionContent",
+ typeof(FrameworkElement),
+ typeof(SettingsBlockControl),
+ new PropertyMetadata(null)
+ );
+
+ public FrameworkElement AdditionalDescriptionContent
+ {
+ get => (FrameworkElement)GetValue(AdditionalDescriptionContentProperty);
+ set => SetValue(AdditionalDescriptionContentProperty, value);
+ }
+
+ public static readonly DependencyProperty TitleProperty = DependencyProperty.Register(
+ "Title",
+ typeof(string),
+ typeof(SettingsBlockControl),
+ new PropertyMetadata(null)
+ );
+
+ public string Title
+ {
+ get => (string)GetValue(TitleProperty);
+ set => SetValue(TitleProperty, value);
+ }
+
+ public static readonly DependencyProperty DescriptionProperty = DependencyProperty.Register(
+ "Description",
+ typeof(string),
+ typeof(SettingsBlockControl),
+ new PropertyMetadata(null)
+ );
+
+ public string Description
+ {
+ get => (string)GetValue(DescriptionProperty);
+ set => SetValue(DescriptionProperty, value);
+ }
+
+ public static readonly DependencyProperty IconProperty = DependencyProperty.Register(
+ "Icon",
+ typeof(IconElement),
+ typeof(SettingsBlockControl),
+ new PropertyMetadata(null)
+ );
+
+ public IconElement Icon
+ {
+ get => (IconElement)GetValue(IconProperty);
+ set => SetValue(IconProperty, value);
+ }
+
+ public static readonly DependencyProperty IsClickableProperty = DependencyProperty.Register(
+ "IsClickable",
+ typeof(bool),
+ typeof(SettingsBlockControl),
+ new PropertyMetadata(false)
+ );
+
+ public bool IsClickable
+ {
+ get => (bool)GetValue(IsClickableProperty);
+ set => SetValue(IsClickableProperty, value);
+ }
+
+ public static readonly DependencyProperty IsExpandedProperty = DependencyProperty.Register(
+ "IsExpanded",
+ typeof(bool),
+ typeof(SettingsBlockControl),
+ new PropertyMetadata(false)
+ );
+
+ public bool IsExpanded
+ {
+ get => (bool)GetValue(IsExpandedProperty);
+ set => SetValue(IsExpandedProperty, value);
+ }
+
+ //
+ // Summary:
+ // Occurs when a button control is clicked.
+ public event EventHandler Click;
+
+ public SettingsBlockControl()
+ {
+ InitializeComponent();
+ Loaded += SettingsBlockControl_Loaded;
+ }
+
+ private void SettingsBlockControl_Loaded(object sender, RoutedEventArgs e)
+ {
+ if (ActionableButton is not null)
+ {
+ AutomationProperties.SetName(ActionableButton, Title);
+ }
+ }
+
+ private void Expander_Expanding(Microsoft.UI.Xaml.Controls.Expander sender, Microsoft.UI.Xaml.Controls.ExpanderExpandingEventArgs args)
+ {
+ Click?.Invoke(this, true);
+ }
+
+ private void Expander_Collapsed(Microsoft.UI.Xaml.Controls.Expander sender, Microsoft.UI.Xaml.Controls.ExpanderCollapsedEventArgs args)
+ {
+ Click?.Invoke(this, false);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/core/Riverside.Toolkit.Controls.Settings/SettingsDisplayControl.xaml b/src/core/Riverside.Toolkit.Controls.Settings/SettingsDisplayControl.xaml
new file mode 100644
index 0000000..56d94f3
--- /dev/null
+++ b/src/core/Riverside.Toolkit.Controls.Settings/SettingsDisplayControl.xaml
@@ -0,0 +1,110 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/core/Riverside.Toolkit.Controls.Settings/SettingsDisplayControl.xaml.cs b/src/core/Riverside.Toolkit.Controls.Settings/SettingsDisplayControl.xaml.cs
new file mode 100644
index 0000000..e3c2261
--- /dev/null
+++ b/src/core/Riverside.Toolkit.Controls.Settings/SettingsDisplayControl.xaml.cs
@@ -0,0 +1,75 @@
+namespace Riverside.Toolkit.Controls
+{
+ [ContentProperty(Name = nameof(SettingsActionableElement))]
+ public sealed partial class SettingsDisplayControl : UserControl
+ {
+ public FrameworkElement SettingsActionableElement { get; set; }
+
+ public static readonly DependencyProperty AdditionalDescriptionContentProperty = DependencyProperty.Register(
+ "AdditionalDescriptionContent",
+ typeof(FrameworkElement),
+ typeof(SettingsDisplayControl),
+ new PropertyMetadata(null)
+ );
+
+ public FrameworkElement AdditionalDescriptionContent
+ {
+ get => (FrameworkElement)GetValue(AdditionalDescriptionContentProperty);
+ set => SetValue(AdditionalDescriptionContentProperty, value);
+ }
+
+ public static readonly DependencyProperty TitleProperty = DependencyProperty.Register(
+ "Title",
+ typeof(string),
+ typeof(SettingsDisplayControl),
+ new PropertyMetadata(null)
+ );
+
+ public string Title
+ {
+ get => (string)GetValue(TitleProperty);
+ set => SetValue(TitleProperty, value);
+ }
+
+ public static readonly DependencyProperty DescriptionProperty = DependencyProperty.Register(
+ "Description",
+ typeof(string),
+ typeof(SettingsDisplayControl),
+ new PropertyMetadata(null)
+ );
+
+ public string Description
+ {
+ get => (string)GetValue(DescriptionProperty);
+ set => SetValue(DescriptionProperty, value);
+ }
+
+ public static readonly DependencyProperty IconProperty = DependencyProperty.Register(
+ "Icon",
+ typeof(IconElement),
+ typeof(SettingsDisplayControl),
+ new PropertyMetadata(null)
+ );
+
+ public IconElement Icon
+ {
+ get => (IconElement)GetValue(IconProperty);
+ set => SetValue(IconProperty, value);
+ }
+
+ public SettingsDisplayControl()
+ {
+ InitializeComponent();
+ VisualStateManager.GoToState(this, "NormalState", false);
+ }
+
+ private void MainPanel_SizeChanged(object sender, SizeChangedEventArgs e)
+ {
+ if (e.NewSize.Width == e.PreviousSize.Width || ActionableElement is null)
+ return;
+
+ var stateToGoName = (ActionableElement.ActualWidth > e.NewSize.Width / 3) ? "CompactState" : "NormalState";
+ VisualStateManager.GoToState(this, stateToGoName, false);
+ }
+ }
+}
diff --git a/src/platforms/Riverside.Toolkit.Uno.Controls.Settings/Riverside.Toolkit.Uno.Controls.Settings.csproj b/src/platforms/Riverside.Toolkit.Uno.Controls.Settings/Riverside.Toolkit.Uno.Controls.Settings.csproj
new file mode 100644
index 0000000..835eb50
--- /dev/null
+++ b/src/platforms/Riverside.Toolkit.Uno.Controls.Settings/Riverside.Toolkit.Uno.Controls.Settings.csproj
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/src/platforms/Riverside.Toolkit.Uwp.Controls.Settings/Riverside.Toolkit.Uwp.Controls.Settings.csproj b/src/platforms/Riverside.Toolkit.Uwp.Controls.Settings/Riverside.Toolkit.Uwp.Controls.Settings.csproj
new file mode 100644
index 0000000..b003cd5
--- /dev/null
+++ b/src/platforms/Riverside.Toolkit.Uwp.Controls.Settings/Riverside.Toolkit.Uwp.Controls.Settings.csproj
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/src/platforms/Riverside.Toolkit.WinUI.Controls.Settings/Riverside.Toolkit.WinUI.Controls.Settings.csproj b/src/platforms/Riverside.Toolkit.WinUI.Controls.Settings/Riverside.Toolkit.WinUI.Controls.Settings.csproj
new file mode 100644
index 0000000..62dc687
--- /dev/null
+++ b/src/platforms/Riverside.Toolkit.WinUI.Controls.Settings/Riverside.Toolkit.WinUI.Controls.Settings.csproj
@@ -0,0 +1,5 @@
+
+
+
+
+