design: every window inherits Inter (implicit Window style)
Dialogs are separate WPF windows, so the FontFamily set on MainWindow never reached them — GoLive, Socials and the four pickers still rendered Segoe UI while the main window used Inter. The theme now carries an implicit Window style (family + Display text mode + layout rounding). Guard: DialogTypographyTests opens a real Window inside the real app and asserts it resolves the bundled Inter family — which fails if the style or the font resource goes missing — and asserts no dialog sets FontFamily itself, i.e. nobody opts out of the standard.
This commit is contained in:
@@ -2,6 +2,16 @@
|
|||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:Helpers="clr-namespace:ytLive.Helpers">
|
xmlns:Helpers="clr-namespace:ytLive.Helpers">
|
||||||
|
|
||||||
|
<!-- Typography for every window: dialogs are separate WPF windows, so FontFamily set on
|
||||||
|
MainWindow does not reach them. This implicit style is the one place that does — a
|
||||||
|
dialog inherits Inter without setting anything, and the design standard holds for every
|
||||||
|
surface the creator can open. -->
|
||||||
|
<Style TargetType="Window">
|
||||||
|
<Setter Property="FontFamily" Value="{StaticResource FontFamily.Sans}"/>
|
||||||
|
<Setter Property="TextOptions.TextFormattingMode" Value="Display"/>
|
||||||
|
<Setter Property="UseLayoutRounding" Value="True"/>
|
||||||
|
</Style>
|
||||||
|
|
||||||
<!-- Base button style -->
|
<!-- Base button style -->
|
||||||
<Style x:Key="YtButton" TargetType="Button">
|
<Style x:Key="YtButton" TargetType="Button">
|
||||||
<Setter Property="Background" Value="{StaticResource Brush.Tertiary}"/>
|
<Setter Property="Background" Value="{StaticResource Brush.Tertiary}"/>
|
||||||
|
|||||||
@@ -0,0 +1,57 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Windows;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace ytLive.Tests;
|
||||||
|
|
||||||
|
/// <summary>DESIGN.md names Inter for all UI text, but a dialog is a SEPARATE WPF window: the
|
||||||
|
/// FontFamily set on MainWindow never reaches it, so every dialog still rendered Segoe UI while
|
||||||
|
/// the main window had moved on (found 2026-10-30).
|
||||||
|
///
|
||||||
|
/// <para>The theme now carries an implicit <c>Window</c> style. This test proves the mechanism on
|
||||||
|
/// a real window inside the real app — which is what catches a missing resource or a broken
|
||||||
|
/// implicit-style lookup — and asserts no dialog opts out by setting FontFamily itself.</para></summary>
|
||||||
|
[Collection("RealApp")]
|
||||||
|
public class DialogTypographyTests
|
||||||
|
{
|
||||||
|
private readonly RealAppHost _app;
|
||||||
|
|
||||||
|
public DialogTypographyTests(RealAppHost app) => _app = app;
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void A_window_inherits_the_standard_typeface_and_no_dialog_opts_out()
|
||||||
|
{
|
||||||
|
// 1. The mechanism: any Window opened in the app resolves the token family. Dialogs are
|
||||||
|
// Windows; proving it once here covers all of them, and it fails if the implicit style
|
||||||
|
// or the font resource ever goes missing.
|
||||||
|
_app.Run(() =>
|
||||||
|
{
|
||||||
|
var window = new Window();
|
||||||
|
window.Show();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Assert.Contains("Inter", window.FontFamily?.Source ?? string.Empty,
|
||||||
|
StringComparison.OrdinalIgnoreCase);
|
||||||
|
}
|
||||||
|
finally { window.Close(); }
|
||||||
|
});
|
||||||
|
|
||||||
|
// 2. Opt-outs: a dialog that sets FontFamily itself would silently leave the standard.
|
||||||
|
foreach (var file in DialogFiles())
|
||||||
|
Assert.DoesNotContain("FontFamily=", File.ReadAllText(file));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IEnumerable<string> DialogFiles()
|
||||||
|
{
|
||||||
|
var root = Path.GetDirectoryName(SourceAssert.RepoPath("App.xaml"))!;
|
||||||
|
return Directory.EnumerateFiles(root, "*.xaml", SearchOption.AllDirectories)
|
||||||
|
.Where(p => !p.Contains($"{Path.DirectorySeparatorChar}obj{Path.DirectorySeparatorChar}", StringComparison.Ordinal)
|
||||||
|
&& !p.Contains($"{Path.DirectorySeparatorChar}bin{Path.DirectorySeparatorChar}", StringComparison.Ordinal)
|
||||||
|
&& !p.Contains("ytLive.Tests", StringComparison.Ordinal))
|
||||||
|
.Where(p => Path.GetFileName(p).Contains("Dialog", StringComparison.OrdinalIgnoreCase)
|
||||||
|
|| Path.GetFileName(p).StartsWith("GoLiveWindow", StringComparison.OrdinalIgnoreCase));
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user