Skip to content

Commit 714d449

Browse files
dooly123claude
andcommitted
Surface package licenses; glass restyle + grid view for Packages
License (SPDX) now flows end to end: read from each package's package.json, baked into the registry feeds (packages.json/catalog.json) by the generator, carried on the desktop catalog, shown on the registry page (wwwroot) cards + detail + submit, and as a license pill per row in the app's Packages tab. Also restyles the app toward the website look: translucent "glass" cards over an animated, drifting background, plus roomier action buttons and a persisted List/Grid layout toggle on the Available list. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 6b7c0da commit 714d449

15 files changed

Lines changed: 243 additions & 34 deletions

File tree

src/BasisPM.App/Localization/Languages/en.json

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -502,10 +502,18 @@
502502
"key": "packages.button.createBundle",
503503
"value": "Create bundle"
504504
},
505+
{
506+
"key": "packages.button.gridView",
507+
"value": "Grid view"
508+
},
505509
{
506510
"key": "packages.button.install",
507511
"value": "Install"
508512
},
513+
{
514+
"key": "packages.button.listView",
515+
"value": "List view"
516+
},
509517
{
510518
"key": "packages.button.refresh",
511519
"value": "Refresh"
@@ -578,6 +586,10 @@
578586
"key": "packages.hero.title",
579587
"value": "Packages"
580588
},
589+
{
590+
"key": "packages.label.license",
591+
"value": "License"
592+
},
581593
{
582594
"key": "packages.label.project",
583595
"value": "Project"
@@ -710,6 +722,10 @@
710722
"key": "packages.tooltip.filterByOwner",
711723
"value": "Filter installed packages by owner (from the package id)"
712724
},
725+
{
726+
"key": "packages.tooltip.toggleLayout",
727+
"value": "Switch between list and grid layout"
728+
},
713729
{
714730
"key": "unity.button.install",
715731
"value": "Install via Unity Hub"

src/BasisPM.App/Styles/BasisTheme.axaml

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,11 @@
1212
<Color x:Key="BasisBorder">#1AFFFFFF</Color>
1313
<Color x:Key="BasisBorderStrong">#33FFFFFF</Color>
1414

15+
<!-- Translucent "glass" fills: a frosted light film over the animated background,
16+
mirroring the website's bg-white/5 cards. -->
17+
<Color x:Key="BasisGlass">#14FFFFFF</Color>
18+
<Color x:Key="BasisGlassStrong">#1FFFFFFF</Color>
19+
1520
<Color x:Key="BasisTextPrimary">#F4F2FF</Color>
1621
<Color x:Key="BasisTextMuted">#B7B3D6</Color>
1722
<Color x:Key="BasisTextSecondary">#9C97C2</Color>
@@ -36,6 +41,8 @@
3641
<SolidColorBrush x:Key="BasisSurfaceMutedBrush" Color="{StaticResource BasisSurfaceMuted}"/>
3742
<SolidColorBrush x:Key="BasisBorderBrush" Color="{StaticResource BasisBorder}"/>
3843
<SolidColorBrush x:Key="BasisBorderStrongBrush" Color="{StaticResource BasisBorderStrong}"/>
44+
<SolidColorBrush x:Key="BasisGlassBrush" Color="{StaticResource BasisGlass}"/>
45+
<SolidColorBrush x:Key="BasisGlassStrongBrush" Color="{StaticResource BasisGlassStrong}"/>
3946
<SolidColorBrush x:Key="BasisTextPrimaryBrush" Color="{StaticResource BasisTextPrimary}"/>
4047
<SolidColorBrush x:Key="BasisTextMutedBrush" Color="{StaticResource BasisTextMuted}"/>
4148
<SolidColorBrush x:Key="BasisTextSecondaryBrush" Color="{StaticResource BasisTextSecondary}"/>
@@ -121,14 +128,24 @@
121128
<Setter Property="Foreground" Value="{StaticResource BasisBrandBrush}"/>
122129
</Style>
123130

131+
<!-- Frosted "glass" card: a translucent film that lets the animated background wash through,
132+
matching the website's bg-white/5 backdrop-blur cards. -->
124133
<Style Selector="Border.card">
125-
<Setter Property="Background" Value="{StaticResource BasisSurfaceBrush}"/>
134+
<Setter Property="Background" Value="{StaticResource BasisGlassBrush}"/>
126135
<Setter Property="BorderBrush" Value="{StaticResource BasisBorderBrush}"/>
127136
<Setter Property="BorderThickness" Value="1"/>
128-
<Setter Property="CornerRadius" Value="16"/>
137+
<Setter Property="CornerRadius" Value="18"/>
129138
<Setter Property="Padding" Value="22"/>
130139
</Style>
131140

141+
<!-- Opt-in glass surface for panels / rows nested inside a card. -->
142+
<Style Selector="Border.glass">
143+
<Setter Property="Background" Value="{StaticResource BasisGlassStrongBrush}"/>
144+
<Setter Property="BorderBrush" Value="{StaticResource BasisBorderBrush}"/>
145+
<Setter Property="BorderThickness" Value="1"/>
146+
<Setter Property="CornerRadius" Value="12"/>
147+
</Style>
148+
132149
<Style Selector="Border.panel">
133150
<Setter Property="Background" Value="{StaticResource BasisPanelBrush}"/>
134151
<Setter Property="BorderBrush" Value="{StaticResource BasisBorderBrush}"/>

src/BasisPM.App/ViewModels/MainWindowViewModel.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ public MainWindowViewModel()
6464
{
6565
_installService = new BasisInstallService(_projectService, _gitService);
6666
InstallsVM = new InstallsViewModel(_settingsService, _installService, _gitService, this);
67-
PackagesVM = new PackagesViewModel(_catalogService, _projectService, this);
67+
PackagesVM = new PackagesViewModel(_settingsService, _catalogService, _projectService, this);
6868
ChangesVM = new ChangesViewModel(_gitService, this);
6969
UnityVM = new UnityViewModel(_hubService, _releaseService, this);
7070
LogsVM = new LogsViewModel(_log);
@@ -289,6 +289,7 @@ public async Task InitializeAsync()
289289
SettingsVM.Apply(settings);
290290
ShowChangesTab = settings.ShowLocalChanges;
291291
ShowDevelopTab = settings.DeveloperMode;
292+
PackagesVM.SetInitialGridView(settings.PackagesGridView);
292293
await InstallsVM.LoadAsync(settings);
293294
await PackagesVM.LoadCatalogAsync(settings.CatalogUrl);
294295

src/BasisPM.App/ViewModels/PackagesViewModel.cs

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,13 @@ namespace BasisPM.App.ViewModels;
1212

1313
public sealed class PackagesViewModel : ObservableObject
1414
{
15+
private readonly UserSettingsService _settingsService;
1516
private readonly CatalogService _catalogService;
1617
private readonly UnityProjectService _projectService;
1718
private readonly GitHubService _githubService;
1819
private readonly VersionService _versionService = new();
1920
private readonly MainWindowViewModel _shell;
21+
private bool _isGridView;
2022

2123
private Catalog _catalog = new();
2224
private BasisInstall? _install;
@@ -57,15 +59,32 @@ public BasisInstall? SelectedInstall
5759
public bool HasInstall => _install is not null && _install.HasUnityProject;
5860
public bool HasInstalls => InstallOptions.Count > 0;
5961

62+
// Packages "Available" list layout: false = rows (default), true = a grid of cards. Persisted.
63+
public bool IsGridView
64+
{
65+
get => _isGridView;
66+
set
67+
{
68+
if (!SetField(ref _isGridView, value)) return;
69+
OnPropertyChanged(nameof(IsListView));
70+
OnPropertyChanged(nameof(LayoutToggleLabel));
71+
_ = PersistGridViewAsync(value);
72+
}
73+
}
74+
public bool IsListView => !_isGridView;
75+
public string LayoutToggleLabel => _isGridView ? L.Tr("packages.button.listView") : L.Tr("packages.button.gridView");
76+
6077
public RelayCommand<CatalogPackageVersion> InstallCommand { get; }
6178
public RelayCommand<InstalledPackageRow> UninstallCommand { get; }
6279
public RelayCommand RefreshCommand { get; }
6380
public RelayCommand AddFromGitHubCommand { get; }
6481
public RelayCommand CreateBundleCommand { get; }
6582
public RelayCommand<CatalogPackageVersion> ChooseVersionCommand { get; }
83+
public RelayCommand ToggleLayoutCommand { get; }
6684

67-
public PackagesViewModel(CatalogService catalogService, UnityProjectService projectService, MainWindowViewModel shell)
85+
public PackagesViewModel(UserSettingsService settingsService, CatalogService catalogService, UnityProjectService projectService, MainWindowViewModel shell)
6886
{
87+
_settingsService = settingsService;
6988
_catalogService = catalogService;
7089
_projectService = projectService;
7190
_githubService = new GitHubService();
@@ -77,6 +96,28 @@ public PackagesViewModel(CatalogService catalogService, UnityProjectService proj
7796
AddFromGitHubCommand = new RelayCommand(AddFromGitHubAsync);
7897
CreateBundleCommand = new RelayCommand(CreateBundleAsync);
7998
ChooseVersionCommand = new RelayCommand<CatalogPackageVersion>(ChooseVersionAsync);
99+
ToggleLayoutCommand = new RelayCommand(() => IsGridView = !IsGridView);
100+
}
101+
102+
/// <summary>Applies the persisted layout choice at startup without re-saving it.</summary>
103+
public void SetInitialGridView(bool grid)
104+
{
105+
if (_isGridView == grid) return;
106+
_isGridView = grid;
107+
OnPropertyChanged(nameof(IsGridView));
108+
OnPropertyChanged(nameof(IsListView));
109+
OnPropertyChanged(nameof(LayoutToggleLabel));
110+
}
111+
112+
private async Task PersistGridViewAsync(bool grid)
113+
{
114+
try
115+
{
116+
var settings = await _settingsService.LoadAsync();
117+
settings.PackagesGridView = grid;
118+
await _settingsService.SaveAsync(settings);
119+
}
120+
catch { /* a view preference isn't worth surfacing a settings-write error */ }
80121
}
81122

82123
public void SetActiveInstall(BasisInstall install)
@@ -554,6 +595,8 @@ public sealed record PackageRow(CatalogPackageVersion Entry, string? InstalledVe
554595
public bool HasAuthor => !string.IsNullOrWhiteSpace(Entry.Author?.Name);
555596
public string? Unity => Entry.Unity;
556597
public bool HasUnity => !string.IsNullOrWhiteSpace(Entry.Unity);
598+
public string? License => Entry.License;
599+
public bool HasLicense => !string.IsNullOrWhiteSpace(Entry.License);
557600
public string Owner => PackagesViewModel.OwnerOf(Entry.Name);
558601
public string Initial => string.IsNullOrWhiteSpace(DisplayName) ? "?" : DisplayName.TrimStart()[..1].ToUpperInvariant();
559602
public bool HasGit => !string.IsNullOrWhiteSpace(Entry.Url);

src/BasisPM.App/Views/MainWindow.axaml

Lines changed: 50 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,52 @@
1111
Background="{StaticResource BasisBackgroundBrush}">
1212

1313
<Panel ClipToBounds="True">
14-
<Border Opacity="0.14">
14+
<!-- Animated background: a base brand gradient that slowly breathes, plus colored blobs
15+
that drift on independent loops — the desktop equivalent of the website's moving gradient. -->
16+
<Panel.Styles>
17+
<Style Selector="Border.bgGradient">
18+
<Style.Animations>
19+
<Animation Duration="0:0:20" IterationCount="INFINITE" PlaybackDirection="Alternate" Easing="SineEaseInOut">
20+
<KeyFrame Cue="0%"><Setter Property="Opacity" Value="0.10"/></KeyFrame>
21+
<KeyFrame Cue="100%"><Setter Property="Opacity" Value="0.18"/></KeyFrame>
22+
</Animation>
23+
</Style.Animations>
24+
</Style>
25+
<Style Selector="Ellipse.blobA">
26+
<Style.Animations>
27+
<Animation Duration="0:0:23" IterationCount="INFINITE" PlaybackDirection="Alternate" Easing="SineEaseInOut">
28+
<KeyFrame Cue="0%"><Setter Property="RenderTransform" Value="translate(0px,0px)"/></KeyFrame>
29+
<KeyFrame Cue="100%"><Setter Property="RenderTransform" Value="translate(80px,60px)"/></KeyFrame>
30+
</Animation>
31+
</Style.Animations>
32+
</Style>
33+
<Style Selector="Ellipse.blobB">
34+
<Style.Animations>
35+
<Animation Duration="0:0:29" IterationCount="INFINITE" PlaybackDirection="Alternate" Easing="SineEaseInOut">
36+
<KeyFrame Cue="0%"><Setter Property="RenderTransform" Value="translate(0px,0px)"/></KeyFrame>
37+
<KeyFrame Cue="100%"><Setter Property="RenderTransform" Value="translate(-70px,50px)"/></KeyFrame>
38+
</Animation>
39+
</Style.Animations>
40+
</Style>
41+
<Style Selector="Ellipse.blobC">
42+
<Style.Animations>
43+
<Animation Duration="0:0:34" IterationCount="INFINITE" PlaybackDirection="Alternate" Easing="SineEaseInOut">
44+
<KeyFrame Cue="0%"><Setter Property="RenderTransform" Value="translate(0px,0px)"/></KeyFrame>
45+
<KeyFrame Cue="100%"><Setter Property="RenderTransform" Value="translate(-60px,-45px)"/></KeyFrame>
46+
</Animation>
47+
</Style.Animations>
48+
</Style>
49+
<Style Selector="Ellipse.blobD">
50+
<Style.Animations>
51+
<Animation Duration="0:0:26" IterationCount="INFINITE" PlaybackDirection="Alternate" Easing="SineEaseInOut">
52+
<KeyFrame Cue="0%"><Setter Property="RenderTransform" Value="translate(0px,0px)"/></KeyFrame>
53+
<KeyFrame Cue="100%"><Setter Property="RenderTransform" Value="translate(55px,-40px)"/></KeyFrame>
54+
</Animation>
55+
</Style.Animations>
56+
</Style>
57+
</Panel.Styles>
58+
59+
<Border Classes="bgGradient" Opacity="0.14">
1560
<Border.Background>
1661
<LinearGradientBrush StartPoint="100%,0%" EndPoint="0%,100%">
1762
<GradientStop Offset="0" Color="#EF1237"/>
@@ -23,25 +68,25 @@
2368
</Border>
2469

2570
<Canvas IsHitTestVisible="False" ClipToBounds="True">
26-
<Ellipse Width="260" Height="260" Canvas.Left="-60" Canvas.Top="-40"
71+
<Ellipse Classes="blobA" Width="260" Height="260" Canvas.Left="-60" Canvas.Top="-40"
2772
Fill="#26EF1237">
2873
<Ellipse.Effect>
2974
<BlurEffect Radius="120"/>
3075
</Ellipse.Effect>
3176
</Ellipse>
32-
<Ellipse Width="320" Height="320" Canvas.Right="-80" Canvas.Top="60"
77+
<Ellipse Classes="blobB" Width="320" Height="320" Canvas.Right="-80" Canvas.Top="60"
3378
Fill="#269333EA">
3479
<Ellipse.Effect>
3580
<BlurEffect Radius="140"/>
3681
</Ellipse.Effect>
3782
</Ellipse>
38-
<Ellipse Width="220" Height="220" Canvas.Left="280" Canvas.Bottom="-40"
83+
<Ellipse Classes="blobC" Width="220" Height="220" Canvas.Left="280" Canvas.Bottom="-40"
3984
Fill="#1F3B82F6">
4085
<Ellipse.Effect>
4186
<BlurEffect Radius="120"/>
4287
</Ellipse.Effect>
4388
</Ellipse>
44-
<Ellipse Width="200" Height="200" Canvas.Right="120" Canvas.Bottom="-30"
89+
<Ellipse Classes="blobD" Width="200" Height="200" Canvas.Right="120" Canvas.Bottom="-30"
4590
Fill="#26F43F5E">
4691
<Ellipse.Effect>
4792
<BlurEffect Radius="100"/>

0 commit comments

Comments
 (0)