Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
16f73d2
UI polish: tag icons in the left nav + a Tags management view
StuartMeeks May 30, 2026
e4c49fd
UI polish: move CLI switcher + snip search to the title bar; restruct…
StuartMeeks May 30, 2026
2ce4d19
UI polish: centre title-bar search + switcher, fix default tag glyph
StuartMeeks May 30, 2026
ebf34ea
UI polish: interpret typed code points in the tag-icon field
StuartMeeks May 30, 2026
e7bd679
UI polish: card actions, danger styling, dialog corners/spacing, wide…
StuartMeeks May 30, 2026
3bd2e89
UI polish: apply dialog styles to derived ContentDialogs; fix scrollb…
StuartMeeks May 31, 2026
98abec3
Address codex review: title-bar passthrough, search-by-id, hide All-s…
StuartMeeks May 31, 2026
ff6f976
UI polish: Home also resets the CLI switcher to the All scope
StuartMeeks May 31, 2026
0ea4313
UI polish: redesign Home page (hero banner, CLI tiles, snip categorie…
StuartMeeks May 31, 2026
d7fd929
Address codex review: ApplySearch always re-applies the snip list
StuartMeeks May 31, 2026
4e442eb
UI polish: title-bar hamburger, footer nav selection, Home banner/car…
StuartMeeks May 31, 2026
6d0301c
UI polish: shared-parameters screens, Settings sections, Home/nav ref…
StuartMeeks May 31, 2026
09bab26
Address codex review: New CLI in empty state; re-invoke current tag n…
StuartMeeks May 31, 2026
41888ea
Address codex review: style the parameters edit modal; dedupe tag row…
StuartMeeks May 31, 2026
1b36ae6
Address codex review: case-insensitive tag-icon map
StuartMeeks May 31, 2026
a439411
Fix CI: move tag-icon comment out of the fluent chain (IDE0055)
StuartMeeks May 31, 2026
2738987
UI polish: per-parameter edit modal; centre shared-params/tags/trash …
StuartMeeks May 31, 2026
bb8fd81
Fix App build: update stale dialog type reference in App.xaml
StuartMeeks May 31, 2026
6b0d295
Address codex review: preserve the selected Home category across refresh
StuartMeeks May 31, 2026
8358f19
Address codex review: return Home after deleting the selected CLI
StuartMeeks May 31, 2026
1947bb4
UI polish: restructure Home header to the WinUI Gallery layout
StuartMeeks May 31, 2026
eaae2fc
UI polish: theme-specific Home hero image (light/dark)
StuartMeeks May 31, 2026
3113868
Add Home hero images (light + dark theme)
StuartMeeks May 31, 2026
2c509c1
UI polish: CLI tile hover, fixed-height hero, theme fade brush, left-…
StuartMeeks May 31, 2026
a38d686
UI polish: blend hero into the page by unifying the Home pane background
StuartMeeks May 31, 2026
8aaa75a
UI polish: fade hero with a Composition opacity mask (blend into Mica)
StuartMeeks May 31, 2026
bad68c7
UI polish: CLI cards straddle the hero bottom; opaque card backgrounds
StuartMeeks May 31, 2026
87f88ad
UI polish: reduce the title-to-cards gap by a third (hero 360 -> 316)
StuartMeeks May 31, 2026
b4d38e9
UI polish: make CLI/New CLI card background translucent but mostly op…
StuartMeeks May 31, 2026
d484867
UI polish: use AcrylicBackgroundFillColorDefault for CLI / New CLI cards
StuartMeeks May 31, 2026
0194f18
Fix: modals follow the in-app theme, not the OS theme
StuartMeeks May 31, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,33 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]

### Changed
- **Home, navigation and shared-parameters polish.** The Home page leads with a
full-bleed hero banner (drop `Assets/HomeHero.png` to supply the image), the
CLI launcher is a horizontal carousel that overlaps the banner, and a centred
pill selector switches between Most used / Recent / Favourites. The navigation
pane toggle (hamburger) moved to the title bar (Home is the first nav item),
and the footer destinations (Shared parameters / Tags / Trash / Settings) now
show the selected indicator like the other nav items. Clicking Home also
clears the search. Shared parameters — global and per-CLI (reached from the CLI
view header) — now have a read-only card view with an edit modal, instead of
inline editing; the Tags and Shared-parameters panes are left-aligned. Settings
is grouped into "Appearance & behaviour" and "About"; the About expander
shows the version and copyright, with links to clone the repo and file issues.
- **Shell layout: CLI switcher and search moved to the title bar.** The CLI
switcher and a snip search box now live in the custom title bar. Search is
snip-only with name autocomplete, scoped to the selected CLI; each suggestion
shows its CLI in a badge so identically-named snips are distinguishable, and
choosing one filters the list to it. The left navigation now leads with
**Home** and **Documentation** entries, followed by a **Tags** heading with an
**All** entry and the scoped tags; the footer actions (Shared parameters,
Tags, Trash, Settings) are left-aligned.
- **Polished cards, dialogs and destructive actions.** Snip cards now size the
Copy button to its content and group Edit/Delete immediately beside it.
Destructive actions (Delete CLI, and the delete confirmations) use a subtle
red treatment. Dialogs have rounded corners, all dialog buttons share rounded
corners with more breathing room between them, and the snip editor is wider so
its content fills the available space. The snip editor's "Command template"
heading no longer inherits the monospace font.
- **JSON stores moved to System.Text.Json source generation.** `JsonSnipStore`
and `JsonSettingsStore` now serialise via a generated `JsonSerializerContext`
instead of the reflection-based serializer, removing the IL2026 trim warnings.
Expand All @@ -17,6 +44,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
IL2104 on the WinAppSDK/WinRT/Jdenticon assemblies, which aren't trim-safe.

### Added
- **Redesigned Home page.** A gradient hero banner heads the page, the CLI
launcher uses landscape tiles (232×172) showing each CLI's description, and a
segmented selector below switches between **Most used**, **Recent** and
**Favourites** snips (drawn from every CLI) shown as a card grid.
- **CLI descriptions.** A CLI can carry a short description, edited in the CLI
editor and shown on its Home card. (Store schema is now v4; an older build
refuses a v4 store rather than dropping descriptions.)
- **Tag icons in the navigation.** Tags can carry a Segoe Fluent Icons glyph,
shown beside the tag in the left navigation (new tags default to a tag glyph). A new
"Tags" entry in the left-pane footer lets you set each tag's icon. Icons are
nav-only — snip tag chips are unchanged. (Store schema is now v3; an older
build refuses a v3 store rather than dropping tag icons.)
- **Shared parameter definitions.** Define a parameter once and reuse it
across snips, at two scopes: **CLI-scoped** (in the CLI editor — inherited by
every snip under that CLI) and **global** (a new "Shared parameters" entry in
Expand Down
49 changes: 47 additions & 2 deletions src/Snipdeck.App/App.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,59 @@
x:Class="Snipdeck.App.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:Snipdeck.App">
xmlns:local="using:Snipdeck.App"
xmlns:views="using:Snipdeck.App.Views">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<XamlControlsResources xmlns="using:Microsoft.UI.Xaml.Controls" />
<!-- Other merged dictionaries here -->
</ResourceDictionary.MergedDictionaries>
<!-- Other app resources here -->

<!-- Subtle danger: red text/icon on a normal button, for destructive actions. -->
<Style x:Key="DangerButtonStyle" TargetType="Button" BasedOn="{StaticResource DefaultButtonStyle}">
<Setter Property="Foreground" Value="{ThemeResource SystemFillColorCriticalBrush}" />
<Setter Property="CornerRadius" Value="{ThemeResource ControlCornerRadius}" />
</Style>

<!-- Dialog primary (Save / Copy): accent, rounded, gap from the close button. -->
<Style x:Key="DialogPrimaryButtonStyle" TargetType="Button" BasedOn="{StaticResource AccentButtonStyle}">
<Setter Property="CornerRadius" Value="{ThemeResource ControlCornerRadius}" />
<Setter Property="Margin" Value="0,0,4,0" />
</Style>

<!-- Dialog close (Cancel): rounded, gap from the primary. -->
<Style x:Key="DialogCloseButtonStyle" TargetType="Button" BasedOn="{StaticResource DefaultButtonStyle}">
<Setter Property="CornerRadius" Value="{ThemeResource ControlCornerRadius}" />
<Setter Property="Margin" Value="4,0,0,0" />
</Style>

<!-- Destructive dialog primary (Delete): subtle red, rounded, gap. -->
<Style x:Key="DangerDialogPrimaryButtonStyle" TargetType="Button" BasedOn="{StaticResource DefaultButtonStyle}">
<Setter Property="Foreground" Value="{ThemeResource SystemFillColorCriticalBrush}" />
<Setter Property="CornerRadius" Value="{ThemeResource ControlCornerRadius}" />
<Setter Property="Margin" Value="0,0,4,0" />
</Style>

<!-- Round every dialog and standardise its buttons (corners + spacing).
Based on DefaultContentDialogStyle so the rounded 8px overlay
corners are preserved. NOTE: an implicit style only matches the
exact type, so derived dialogs need their own styles (below) — a
plain "ContentDialog" implicit style would skip them. -->
<Style x:Key="SnipdeckContentDialogStyle" TargetType="ContentDialog" BasedOn="{StaticResource DefaultContentDialogStyle}">
<Setter Property="PrimaryButtonStyle" Value="{StaticResource DialogPrimaryButtonStyle}" />
<Setter Property="CloseButtonStyle" Value="{StaticResource DialogCloseButtonStyle}" />
</Style>

<!-- Code-created dialogs (confirm / notify) are exactly ContentDialog. -->
<Style TargetType="ContentDialog" BasedOn="{StaticResource SnipdeckContentDialogStyle}" />

<!-- Derived dialogs need an explicit style each, or they fall back to the
unstyled template (square corners, mismatched buttons). -->
<Style TargetType="views:SnipEditorDialog" BasedOn="{StaticResource SnipdeckContentDialogStyle}" />
<Style TargetType="views:CliEditorDialog" BasedOn="{StaticResource SnipdeckContentDialogStyle}" />
<Style TargetType="views:ParameterFillDialog" BasedOn="{StaticResource SnipdeckContentDialogStyle}" />
<Style TargetType="views:ParameterEditorDialog" BasedOn="{StaticResource SnipdeckContentDialogStyle}" />
</ResourceDictionary>
</Application.Resources>
</Application>
Binary file added src/Snipdeck.App/Assets/HomeHeroDark.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/Snipdeck.App/Assets/HomeHeroLight.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
16 changes: 16 additions & 0 deletions src/Snipdeck.App/Assets/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Assets

## Home hero images (theme-specific)

The Home page hero banner uses a theme-specific image:

- `HomeHeroLight.png` — shown in the Light theme
- `HomeHeroDark.png` — shown in the Dark (and High Contrast) theme

Drop both here (≈2400×1000, wide) and the header swaps them with the selected
theme. Keep the **upper-left area light/clear** in the light image (and suitably
contrasted in the dark image) — the title text uses the theme foreground colour
and sits top-left. The image's lower edge fades into the header background.

Until the files are present, the header shows its background colour. See the
Firefly prompt in the project history for generating them.
1 change: 1 addition & 0 deletions src/Snipdeck.App/Bootstrap.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ public static IServiceProvider Build()
.AddSingleton<IFilePickerService, WindowsFilePickerService>()
.AddSingleton<IFolderPickerService, WindowsFolderPickerService>()
.AddSingleton<IAppRestartService, WindowsAppRestartService>()
.AddSingleton<IExternalLinkService, WindowsExternalLinkService>()
.AddSingleton<IStorageRelocationService>(new StorageRelocationService(_snipStoreFileName))
.AddSingleton<IHotkeyService, WindowsHotkeyService>()
.AddSingleton<ITrayService, HNotifyIconTrayService>()
Expand Down
92 changes: 56 additions & 36 deletions src/Snipdeck.App/Controls/CliCard.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,48 +4,68 @@
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="using:Snipdeck.App.Controls"
xmlns:converters="using:Snipdeck.App.Converters"
xmlns:vm="using:Snipdeck.Core.ViewModels"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">

<Grid Background="{ThemeResource CardBackgroundFillColorDefaultBrush}"
BorderBrush="{ThemeResource CardStrokeColorDefaultBrush}"
BorderThickness="1"
CornerRadius="8"
Padding="16"
Width="200"
Height="200"
Tapped="OnTapped">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<UserControl.Resources>
<converters:BoolToVisibilityConverter x:Key="BoolToVisibility" />
</UserControl.Resources>

<controls:Identicon
Grid.Row="0"
Seed="{x:Bind ViewModel.Id, Mode=OneWay}"
IconRef="{x:Bind ViewModel.IconRef, Mode=OneWay}"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Width="96"
Height="96" />
<!-- A Button so the card gets the same hover/press animation as the New CLI tile. -->
<Button Width="232"
Height="172"
Padding="16"
CornerRadius="8"
HorizontalContentAlignment="Stretch"
VerticalContentAlignment="Stretch"
Background="{ThemeResource AcrylicBackgroundFillColorDefaultBrush}"
BorderBrush="{ThemeResource CardStrokeColorDefaultBrush}"
BorderThickness="1"
Command="{x:Bind NavigateCommand, Mode=OneWay}"
CommandParameter="{x:Bind ViewModel, Mode=OneWay}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>

<TextBlock
Grid.Row="1"
Text="{x:Bind ViewModel.Name, Mode=OneWay}"
Style="{ThemeResource BodyStrongTextBlockStyle}"
HorizontalAlignment="Center"
TextTrimming="CharacterEllipsis"
Margin="0,12,0,0" />
<controls:Identicon
Grid.Row="0"
Seed="{x:Bind ViewModel.Id, Mode=OneWay}"
IconRef="{x:Bind ViewModel.IconRef, Mode=OneWay}"
HorizontalAlignment="Left"
Width="40"
Height="40" />

<TextBlock
Grid.Row="2"
Text="{x:Bind ViewModel.SnipCountDisplay, Mode=OneWay}"
Style="{ThemeResource CaptionTextBlockStyle}"
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
HorizontalAlignment="Center"
Margin="0,2,0,0" />
</Grid>
<TextBlock
Grid.Row="1"
Text="{x:Bind ViewModel.Name, Mode=OneWay}"
Style="{ThemeResource BodyStrongTextBlockStyle}"
TextTrimming="CharacterEllipsis"
Margin="0,12,0,0" />

<TextBlock
Grid.Row="2"
Text="{x:Bind ViewModel.Description, Mode=OneWay}"
Style="{ThemeResource CaptionTextBlockStyle}"
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
TextWrapping="Wrap"
TextTrimming="CharacterEllipsis"
MaxLines="3"
Visibility="{x:Bind ViewModel.HasDescription, Mode=OneWay, Converter={StaticResource BoolToVisibility}}"
Margin="0,4,0,0" />

<TextBlock
Grid.Row="3"
Text="{x:Bind ViewModel.SnipCountDisplay, Mode=OneWay}"
Style="{ThemeResource CaptionTextBlockStyle}"
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
Margin="0,8,0,0" />
</Grid>
</Button>
</UserControl>
9 changes: 0 additions & 9 deletions src/Snipdeck.App/Controls/CliCard.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Input;

using Snipdeck.Core.ViewModels;

Expand Down Expand Up @@ -34,13 +33,5 @@ public ICommand? NavigateCommand
get => (ICommand?)GetValue(NavigateCommandProperty);
set => SetValue(NavigateCommandProperty, value);
}

private void OnTapped(object sender, TappedRoutedEventArgs e)
{
if (NavigateCommand?.CanExecute(ViewModel) == true)
{
NavigateCommand.Execute(ViewModel);
}
}
}
}
10 changes: 6 additions & 4 deletions src/Snipdeck.App/Controls/SnipCard.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,9 @@
Text="{x:Bind ViewModel.CommandTemplate, Mode=OneWay}"
FontFamily="Cascadia Mono, Consolas, Courier New"
FontSize="12"
TextWrapping="Wrap" />
TextWrapping="Wrap"
MaxLines="3"
TextTrimming="CharacterEllipsis" />
</Border>

<ItemsControl
Expand All @@ -87,18 +89,18 @@

<Grid Grid.Row="3" Margin="0,12,0,0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>

<Button
Grid.Column="0"
Content="Copy"
Style="{ThemeResource AccentButtonStyle}"
Command="{x:Bind CopyCommand, Mode=OneWay}"
CommandParameter="{x:Bind ViewModel, Mode=OneWay}"
HorizontalAlignment="Stretch" />
CommandParameter="{x:Bind ViewModel, Mode=OneWay}" />

<Button
Grid.Column="1"
Expand Down
79 changes: 72 additions & 7 deletions src/Snipdeck.App/MainWindow.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:Snipdeck.App"
xmlns:vm="using:Snipdeck.Core.ViewModels"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Expand All @@ -19,18 +20,82 @@
<RowDefinition Height="*" />
</Grid.RowDefinitions>

<Border x:Name="AppTitleBar"
Grid.Row="0"
Height="40"
Padding="12,0,0,0">
<Grid x:Name="AppTitleBar"
Grid.Row="0"
Height="48">

<StackPanel Orientation="Horizontal"
VerticalAlignment="Center">
HorizontalAlignment="Left"
VerticalAlignment="Center"
Spacing="4">
<!-- Pane toggle (hamburger): owned by the title bar so Home is the
first item in the nav pane. Registered as passthrough in code-behind. -->
<Button x:Name="PaneToggleButton"
Click="OnPaneToggleClicked"
Background="Transparent"
BorderThickness="0"
Width="40"
Height="40"
ToolTipService.ToolTip="Toggle navigation">
<FontIcon Glyph="&#xE700;" FontSize="16" />
</Button>
<TextBlock x:Name="AppTitleTextBlock"
Text="Snipdeck"
Style="{StaticResource CaptionTextBlockStyle}"
VerticalAlignment="Center" />
VerticalAlignment="Center"
Margin="4,0,0,0" />
</StackPanel>

<!-- Search and switcher, centred as a group in the bar. The bar is the
drag region; this group is registered as a passthrough region (in
code-behind) so its controls receive input. -->
<StackPanel x:Name="TitleBarControls"
Orientation="Horizontal"
Spacing="12"
HorizontalAlignment="Center"
VerticalAlignment="Center"
SizeChanged="OnTitleBarControlsChanged">
<AutoSuggestBox x:Name="SearchBox"
VerticalAlignment="Center"
Width="280"
PlaceholderText="Search snips"
QueryIcon="Find"
TextMemberPath="Title"
TextChanged="OnSearchTextChanged"
SuggestionChosen="OnSearchSuggestionChosen"
QuerySubmitted="OnSearchQuerySubmitted">
<AutoSuggestBox.ItemTemplate>
<DataTemplate x:DataType="vm:SnipSearchResult">
<Grid ColumnSpacing="8">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Border Grid.Column="0"
Background="{ThemeResource SubtleFillColorSecondaryBrush}"
CornerRadius="4"
Padding="6,2"
VerticalAlignment="Center">
<TextBlock Text="{x:Bind CliName}"
Style="{ThemeResource CaptionTextBlockStyle}" />
</Border>
<TextBlock Grid.Column="1"
Text="{x:Bind Title}"
VerticalAlignment="Center"
TextTrimming="CharacterEllipsis" />
</Grid>
</DataTemplate>
</AutoSuggestBox.ItemTemplate>
</AutoSuggestBox>

<ComboBox VerticalAlignment="Center"
MinWidth="160"
ToolTipService.ToolTip="Switch CLI"
ItemsSource="{x:Bind Shell.CliChoices, Mode=OneWay}"
SelectedItem="{x:Bind Shell.SelectedCliChoice, Mode=TwoWay}"
DisplayMemberPath="Display" />
</StackPanel>
</Border>
</Grid>

<ContentControl x:Name="ShellHost"
Grid.Row="1"
Expand Down
Loading
Loading