ui(brand): superimposed dragon watermark behind participants, theme-flipped (white/dark, black/light)
Some checks failed
CI / build-and-test (push) Failing after 27s

This commit is contained in:
Zac Gaetano 2026-05-16 19:10:36 -04:00
parent 80d9baf2d0
commit dfdfa9e0e1
7 changed files with 99 additions and 2 deletions

View file

@ -0,0 +1,34 @@
from PIL import Image
import os
# We treat the navy-blue dragon-mark.png as a silhouette source: anything with
# nontrivial alpha is "dragon", everything else stays transparent. We emit a
# pure-black and pure-white variant, tightly cropped to the actual content
# bbox so they center cleanly when used as a watermark.
ROOT = os.path.dirname(os.path.abspath(__file__))
src_path = os.path.join(ROOT, "dragon-mark.png")
src = Image.open(src_path).convert("RGBA")
alpha = src.split()[-1]
# Threshold to drop anti-alias fringe that can fool getbbox into reporting
# the whole canvas as "in".
mask = alpha.point(lambda v: 255 if v > 16 else 0)
bbox = mask.getbbox()
print("content bbox =", bbox, "size =", (bbox[2] - bbox[0], bbox[3] - bbox[1]))
cropped = src.crop(bbox)
_, _, _, ca = cropped.split()
for name, rgb in (("black", (0, 0, 0)), ("white", (255, 255, 255))):
flat = Image.merge(
"RGBA",
(
Image.new("L", cropped.size, rgb[0]),
Image.new("L", cropped.size, rgb[1]),
Image.new("L", cropped.size, rgb[2]),
ca,
),
)
out_path = os.path.join(ROOT, f"dragon-mark-{name}.png")
flat.save(out_path, "PNG", optimize=True)
print("wrote", out_path, flat.size)

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

View file

@ -106,7 +106,11 @@
BorderThickness="0" BorderThickness="0"
Cursor="Hand" Cursor="Hand"
ToolTip="About TeamsISO"> ToolTip="About TeamsISO">
<Image Source="/Assets/dragon-mark.png" <!-- Source bound to Wd.BrandMark.Image so the mark flips
white↔black with the active theme (see Theme.Dark /
Theme.Light). The PNG carries its own AA so HighQuality
scaling is preferred over NearestNeighbor at this size. -->
<Image Source="{DynamicResource Wd.BrandMark.Image}"
Width="20" Height="20" Width="20" Height="20"
RenderOptions.BitmapScalingMode="HighQuality"/> RenderOptions.BitmapScalingMode="HighQuality"/>
</Button> </Button>
@ -447,8 +451,30 @@
BorderBrush="{DynamicResource Wd.Border}" BorderBrush="{DynamicResource Wd.Border}"
BorderThickness="1" BorderThickness="1"
CornerRadius="{StaticResource Radius.M}" CornerRadius="{StaticResource Radius.M}"
Background="{DynamicResource Wd.Surface}"> Background="{DynamicResource Wd.Surface}"
ClipToBounds="True">
<Grid> <Grid>
<!--
Brand watermark superimposed BEHIND the participants grid.
Sits at 6% opacity so a populated grid reads cleanly over
the top while the dragon is still visible through the
transparent row backgrounds (RowBackground="Transparent"
on the DataGrid below). When the grid is empty the
watermark becomes the de-facto empty-state surface.
IsHitTestVisible=False so the watermark never absorbs
clicks meant for grid rows or the empty area below them.
Source binds to the theme-flipped Wd.BrandMark.Image
resource — white dragon in dark mode, black in light.
-->
<Image Source="{DynamicResource Wd.BrandMark.Image}"
Opacity="0.06"
Stretch="Uniform"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Margin="40"
IsHitTestVisible="False"
RenderOptions.BitmapScalingMode="HighQuality"/>
<DataGrid x:Name="ParticipantsGrid" <DataGrid x:Name="ParticipantsGrid"
ItemsSource="{Binding ParticipantsView}" ItemsSource="{Binding ParticipantsView}"
AutoGenerateColumns="False" AutoGenerateColumns="False"

View file

@ -60,7 +60,17 @@
<!-- Wild Dragon brand assets — embedded as resources so the published binary is self-contained. --> <!-- Wild Dragon brand assets — embedded as resources so the published binary is self-contained. -->
<ItemGroup> <ItemGroup>
<!-- Source navy-blue dragon-mark, kept for AboutWindow / installer iconography. -->
<Resource Include="Assets\dragon-mark.png" /> <Resource Include="Assets\dragon-mark.png" />
<!--
Theme-aware silhouette variants used by Theme.Dark / Theme.Light to expose
a single Wd.BrandMark.Image resource key. The dark theme picks the white
dragon (visible on #0A0A0A), the light theme picks the black dragon
(visible on #FAFAFB). Generated from dragon-mark.png via
Assets/_recolor_dragon.py — re-run if the source mark ever changes.
-->
<Resource Include="Assets\dragon-mark-white.png" />
<Resource Include="Assets\dragon-mark-black.png" />
<Resource Include="Assets\wild-dragon-wordmark.png" /> <Resource Include="Assets\wild-dragon-wordmark.png" />
<Resource Include="Assets\teamsiso.ico" /> <Resource Include="Assets\teamsiso.ico" />
<!-- <!--

View file

@ -44,4 +44,20 @@
<SolidColorBrush x:Key="Wd.Status.LiveBg" Color="#13261A"/> <SolidColorBrush x:Key="Wd.Status.LiveBg" Color="#13261A"/>
<SolidColorBrush x:Key="Wd.Status.Warn" Color="#FBBF24"/> <SolidColorBrush x:Key="Wd.Status.Warn" Color="#FBBF24"/>
<SolidColorBrush x:Key="Wd.Status.Error" Color="#FB819C"/> <SolidColorBrush x:Key="Wd.Status.Error" Color="#FB819C"/>
<!--
Brand mark image, theme-flipped. Dark mode shows the WHITE dragon so it
reads against the near-black canvas. The light theme exposes the same
key pointing at the BLACK dragon. Consumers bind via
{DynamicResource Wd.BrandMark.Image} so the swap is automatic on
ThemeManager.Toggle().
CacheOption=OnLoad decodes the PNG at load time and releases the
underlying stream, which matters because the source files are 1243×1125
— without OnLoad the BitmapImage holds the stream open for the life
of the resource dictionary.
-->
<BitmapImage x:Key="Wd.BrandMark.Image"
UriSource="pack://application:,,,/TeamsISO;component/Assets/dragon-mark-white.png"
CacheOption="OnLoad"/>
</ResourceDictionary> </ResourceDictionary>

View file

@ -46,4 +46,15 @@
<SolidColorBrush x:Key="Wd.Status.LiveBg" Color="#DCFCE7"/> <SolidColorBrush x:Key="Wd.Status.LiveBg" Color="#DCFCE7"/>
<SolidColorBrush x:Key="Wd.Status.Warn" Color="#B45309"/> <SolidColorBrush x:Key="Wd.Status.Warn" Color="#B45309"/>
<SolidColorBrush x:Key="Wd.Status.Error" Color="#D43E5C"/> <SolidColorBrush x:Key="Wd.Status.Error" Color="#D43E5C"/>
<!--
Brand mark image, theme-flipped. Light mode shows the BLACK dragon so it
reads against the cyan-tinted off-white canvas. Mirror of the Dark
theme's resource — same key, opposite silhouette. Consumers use
{DynamicResource Wd.BrandMark.Image} so the swap is automatic.
See Theme.Dark.xaml's comment for the CacheOption=OnLoad rationale.
-->
<BitmapImage x:Key="Wd.BrandMark.Image"
UriSource="pack://application:,,,/TeamsISO;component/Assets/dragon-mark-black.png"
CacheOption="OnLoad"/>
</ResourceDictionary> </ResourceDictionary>