diff --git a/source/iNKORE.UI.WPF.Modern.Gallery/Assets/Design/Cards.dark.png b/source/iNKORE.UI.WPF.Modern.Gallery/Assets/Design/Cards.dark.png
new file mode 100644
index 00000000..4fbec4ac
Binary files /dev/null and b/source/iNKORE.UI.WPF.Modern.Gallery/Assets/Design/Cards.dark.png differ
diff --git a/source/iNKORE.UI.WPF.Modern.Gallery/Assets/Design/Cards.light.png b/source/iNKORE.UI.WPF.Modern.Gallery/Assets/Design/Cards.light.png
new file mode 100644
index 00000000..62b880de
Binary files /dev/null and b/source/iNKORE.UI.WPF.Modern.Gallery/Assets/Design/Cards.light.png differ
diff --git a/source/iNKORE.UI.WPF.Modern.Gallery/Assets/Design/Dialog.dark.png b/source/iNKORE.UI.WPF.Modern.Gallery/Assets/Design/Dialog.dark.png
new file mode 100644
index 00000000..7afd73dd
Binary files /dev/null and b/source/iNKORE.UI.WPF.Modern.Gallery/Assets/Design/Dialog.dark.png differ
diff --git a/source/iNKORE.UI.WPF.Modern.Gallery/Assets/Design/Dialog.light.png b/source/iNKORE.UI.WPF.Modern.Gallery/Assets/Design/Dialog.light.png
new file mode 100644
index 00000000..1d8f13f5
Binary files /dev/null and b/source/iNKORE.UI.WPF.Modern.Gallery/Assets/Design/Dialog.light.png differ
diff --git a/source/iNKORE.UI.WPF.Modern.Gallery/DataModel/Data/Controls.Foundation.json b/source/iNKORE.UI.WPF.Modern.Gallery/DataModel/Data/Controls.Foundation.json
index 45a7ec64..aa9f3b99 100644
--- a/source/iNKORE.UI.WPF.Modern.Gallery/DataModel/Data/Controls.Foundation.json
+++ b/source/iNKORE.UI.WPF.Modern.Gallery/DataModel/Data/Controls.Foundation.json
@@ -24,6 +24,27 @@
"Description": "Design guidance and resources",
"Items":
[
+ {
+ "UniqueId": "Spacing",
+ "Title": "Spacing",
+ "Subtitle": "Spacing values and layout examples",
+ "ImagePath": "ms-appx:///Assets/ControlIcons/DefaultIcon.png",
+ "ImageIconPath": "ms-appx:///Assets/ControlIcons/DefaultIcon.png",
+ "Description": "",
+ "Content": "",
+ "IncludedInBuild": true,
+ "IsNew": false,
+ "IsUpdated": false,
+ "Docs": [
+ {
+ "Title": "Content design basics",
+ "Uri": "https://learn.microsoft.com/windows/apps/design/basics/content-basics"
+ }
+ ],
+ "RelatedControls":
+ [
+ ]
+ },
{
"UniqueId": "Typography",
"Title": "Typography",
@@ -68,4 +89,4 @@
]
}
]
-}
\ No newline at end of file
+}
diff --git a/source/iNKORE.UI.WPF.Modern.Gallery/Navigation/NavigationRootPage.xaml b/source/iNKORE.UI.WPF.Modern.Gallery/Navigation/NavigationRootPage.xaml
index 61e9a267..c501d8d5 100644
--- a/source/iNKORE.UI.WPF.Modern.Gallery/Navigation/NavigationRootPage.xaml
+++ b/source/iNKORE.UI.WPF.Modern.Gallery/Navigation/NavigationRootPage.xaml
@@ -121,6 +121,14 @@
+
+
+
+
+
r.Groups)
+ .SelectMany(g => g.Items)
+ .FirstOrDefault(i => i.UniqueId == "Spacing");
+ if (spacingItem != null)
+ {
+ rootFrame.Navigate(ItemPage.Create(spacingItem));
+ }
+ }
else if (selectedItem?.Tag?.ToString() == "Typography")
{
- // Handle Typography navigation
var typographyId = "Typography";
if (_lastItem?.ToString() == typographyId) return;
_lastItem = typographyId;
-
- // Find Typography item from the data source
var typographyItem = ControlInfoDataSource.Instance.Realms
.SelectMany(r => r.Groups)
.SelectMany(g => g.Items)
.FirstOrDefault(i => i.UniqueId == "Typography");
-
if (typographyItem != null)
{
rootFrame.Navigate(ItemPage.Create(typographyItem));
diff --git a/source/iNKORE.UI.WPF.Modern.Gallery/Pages/Controls/Foundation/Design/SpacingPage.xaml b/source/iNKORE.UI.WPF.Modern.Gallery/Pages/Controls/Foundation/Design/SpacingPage.xaml
new file mode 100644
index 00000000..dc44208f
--- /dev/null
+++ b/source/iNKORE.UI.WPF.Modern.Gallery/Pages/Controls/Foundation/Design/SpacingPage.xaml
@@ -0,0 +1,168 @@
+
+
+
+
+
+
+
+
+ The use of consistently sized spacing and gutters semantically groups an experience into separate components. These values map to our rounded corner logic and together help create a cohesive and usable layout.
+ A best practice in design is to use a 4px grid. This means that any spacing or sizing should be a multiple of 4. This helps to create a consistent and harmonious layout and these values are easy to scale.
+
+
+ Below, you can find a few examples of common layout types with highlighted spacing values (in epx).
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/source/iNKORE.UI.WPF.Modern.Gallery/Pages/Controls/Foundation/Design/SpacingPage.xaml.cs b/source/iNKORE.UI.WPF.Modern.Gallery/Pages/Controls/Foundation/Design/SpacingPage.xaml.cs
new file mode 100644
index 00000000..6c397e71
--- /dev/null
+++ b/source/iNKORE.UI.WPF.Modern.Gallery/Pages/Controls/Foundation/Design/SpacingPage.xaml.cs
@@ -0,0 +1,129 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+using iNKORE.UI.WPF.Modern.Controls;
+using System;
+using System.ComponentModel;
+using System.Diagnostics;
+using System.Windows;
+using System.Windows.Navigation;
+using System.Windows.Media.Imaging;
+using System.Windows.Threading;
+using iNKORE.UI.WPF.Modern.Gallery.Helpers;
+using iNKORE.UI.WPF.Modern;
+
+namespace iNKORE.UI.WPF.Modern.Gallery.Pages.Controls.Foundation
+{
+ ///
+ /// Spacing page showcasing Windows spacing values and layout examples.
+ ///
+ public partial class SpacingPage : Page
+ {
+ private DispatcherTimer _themeMonitorTimer;
+ private ElementTheme _lastKnownTheme = ElementTheme.Default;
+
+ public SpacingPage()
+ {
+ this.InitializeComponent();
+ Loaded += SpacingPage_Loaded;
+
+ ThemeManager.Current.ActualApplicationThemeChanged += OnThemeChanged;
+ ThemeManager.AddActualThemeChangedHandler(this, OnElementThemeChanged);
+
+ _themeMonitorTimer = new DispatcherTimer
+ {
+ Interval = TimeSpan.FromMilliseconds(200)
+ };
+ _themeMonitorTimer.Tick += ThemeMonitorTimer_Tick;
+ _themeMonitorTimer.Start();
+ }
+
+ private void SpacingPage_Loaded(object sender, RoutedEventArgs e)
+ {
+ if (NavigationRootPage.Current?.NavigationView != null)
+ {
+ NavigationRootPage.Current.NavigationView.Header = "Spacing";
+ }
+ UpdateSpacingImages();
+ }
+
+ private void UpdateSpacingImages()
+ {
+ if (CardsImage == null || DialogImage == null) return;
+
+ var pageTheme = ThemeManager.GetActualTheme(this);
+ var parentTheme = ElementTheme.Default;
+
+ var parentElement = this.Parent as FrameworkElement;
+ while (parentElement != null)
+ {
+ var currentParentTheme = ThemeManager.GetActualTheme(parentElement);
+ if (currentParentTheme != ElementTheme.Default)
+ {
+ parentTheme = currentParentTheme;
+ break;
+ }
+ parentElement = parentElement.Parent as FrameworkElement;
+ }
+
+ var effectiveTheme = pageTheme != ElementTheme.Default ? pageTheme : parentTheme;
+ var isDarkTheme = effectiveTheme == ElementTheme.Dark ||
+ (effectiveTheme == ElementTheme.Default && ThemeHelper.IsDarkTheme());
+
+ var cardsImageName = isDarkTheme ? "Cards.dark.png" : "Cards.light.png";
+ var dialogImageName = isDarkTheme ? "Dialog.dark.png" : "Dialog.light.png";
+
+ var cardsUri = new Uri($"pack://application:,,,/iNKORE.UI.WPF.Modern.Gallery;component/Assets/Design/{cardsImageName}");
+ var dialogUri = new Uri($"pack://application:,,,/iNKORE.UI.WPF.Modern.Gallery;component/Assets/Design/{dialogImageName}");
+
+ try
+ {
+ var cardsBitmap = new BitmapImage();
+ cardsBitmap.BeginInit();
+ cardsBitmap.UriSource = cardsUri;
+ cardsBitmap.CacheOption = BitmapCacheOption.OnLoad;
+ cardsBitmap.CreateOptions = BitmapCreateOptions.IgnoreImageCache;
+ cardsBitmap.EndInit();
+ cardsBitmap.Freeze();
+ CardsImage.Source = cardsBitmap;
+
+ var dialogBitmap = new BitmapImage();
+ dialogBitmap.BeginInit();
+ dialogBitmap.UriSource = dialogUri;
+ dialogBitmap.CacheOption = BitmapCacheOption.OnLoad;
+ dialogBitmap.CreateOptions = BitmapCreateOptions.IgnoreImageCache;
+ dialogBitmap.EndInit();
+ dialogBitmap.Freeze();
+ DialogImage.Source = dialogBitmap;
+ }
+ catch (Exception ex)
+ {
+ Debug.WriteLine($"Failed to load spacing images: {ex.Message}");
+ // Fallback to dark images if there's an issue
+ CardsImage.Source = new BitmapImage(new Uri("pack://application:,,,/iNKORE.UI.WPF.Modern.Gallery;component/Assets/Design/Cards.dark.png"));
+ DialogImage.Source = new BitmapImage(new Uri("pack://application:,,,/iNKORE.UI.WPF.Modern.Gallery;component/Assets/Design/Dialog.dark.png"));
+ }
+ }
+
+ private void OnThemeChanged(ThemeManager sender, object args)
+ {
+ UpdateSpacingImages();
+ }
+
+ private void OnElementThemeChanged(object sender, RoutedEventArgs e)
+ {
+ UpdateSpacingImages();
+ }
+
+ private void ThemeMonitorTimer_Tick(object sender, EventArgs e)
+ {
+ var currentTheme = ThemeManager.GetActualTheme(this);
+ if (currentTheme != _lastKnownTheme)
+ {
+ _lastKnownTheme = currentTheme;
+ UpdateSpacingImages();
+ Debug.WriteLine($"Theme change detected: {currentTheme}");
+ }
+ }
+ }
+}