Compare commits
11
Commits
v1.1.2
..
fa37f57e38
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fa37f57e38 | ||
|
|
34e75645f5 | ||
|
|
2a1640624e | ||
|
|
a200ce37b5 | ||
|
|
9058c68a47 | ||
|
|
f20c22417e | ||
|
|
0a9f5447aa | ||
|
|
c2341b0203 | ||
|
|
f5b31fbc5e | ||
|
|
eab48e30e4 | ||
|
|
79ae6bd7f2 |
No files matched your search
@@ -1,4 +1,4 @@
|
|||||||
<Application x:Class="ShortcutsPanel.App" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
<Application x:Class="Orbit.App" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||||
|
|
||||||
<Application.Resources>
|
<Application.Resources>
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
using System.Windows;
|
using System.Windows;
|
||||||
namespace ShortcutsPanel;
|
namespace Orbit;
|
||||||
public partial class App : Application
|
public partial class App : Application
|
||||||
{
|
{
|
||||||
protected override void OnStartup(StartupEventArgs e)
|
protected override void OnStartup(StartupEventArgs e)
|
||||||
|
|||||||
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Windows.Media.Imaging;
|
using System.Windows.Media.Imaging;
|
||||||
|
|
||||||
namespace ShortcutsPanel;
|
namespace Orbit;
|
||||||
|
|
||||||
public static class CustomIcons
|
public static class CustomIcons
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ using System.IO;
|
|||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
namespace ShortcutsPanel;
|
namespace Orbit;
|
||||||
|
|
||||||
public sealed record LibraryExport(int Version, List<Shortcut> Links, List<string> Collections);
|
public sealed record LibraryExport(int Version, List<Shortcut> Links, List<string> Collections);
|
||||||
|
|
||||||
|
|||||||
+11
-6
@@ -1,4 +1,4 @@
|
|||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
@@ -7,7 +7,7 @@ using System.Windows.Controls;
|
|||||||
using System.Windows.Input;
|
using System.Windows.Input;
|
||||||
using System.Windows.Media;
|
using System.Windows.Media;
|
||||||
|
|
||||||
namespace ShortcutsPanel;
|
namespace Orbit;
|
||||||
|
|
||||||
public partial class MainWindow
|
public partial class MainWindow
|
||||||
{
|
{
|
||||||
@@ -72,7 +72,7 @@ public partial class MainWindow
|
|||||||
if (choice == MessageBoxResult.Cancel) return;
|
if (choice == MessageBoxResult.Cancel) return;
|
||||||
var next = choice == MessageBoxResult.Yes ? LibraryOperations.Merge(entries, incoming.Links) : incoming.Links;
|
var next = choice == MessageBoxResult.Yes ? LibraryOperations.Merge(entries, incoming.Links) : incoming.Links;
|
||||||
var order = choice == MessageBoxResult.Yes ? collectionOrder.Concat(incoming.Collections).Distinct().ToList() : incoming.Collections;
|
var order = choice == MessageBoxResult.Yes ? collectionOrder.Concat(incoming.Collections).Distinct().ToList() : incoming.Collections;
|
||||||
if (Save(next, order)) { deleted.Clear(); if (undoButton != null) undoButton.IsEnabled = false; dialog.Close(); }
|
if (Save(next, order)) { deleted.Clear(); UpdateUndoNotice(); dialog.Close(); }
|
||||||
}
|
}
|
||||||
catch (Exception ex) { MessageBox.Show(dialog, ex.Message, "Import failed — library unchanged"); }
|
catch (Exception ex) { MessageBox.Show(dialog, ex.Message, "Import failed — library unchanged"); }
|
||||||
}); import.Margin = new Thickness(0,12,0,18); panel.Children.Add(import);
|
}); import.Margin = new Thickness(0,12,0,18); panel.Children.Add(import);
|
||||||
@@ -83,14 +83,19 @@ public partial class MainWindow
|
|||||||
var index = entries.FindIndex(x => x.Id == item.Id); if (index < 0) return false;
|
var index = entries.FindIndex(x => x.Id == item.Id); if (index < 0) return false;
|
||||||
var next = entries.ToList(); next.RemoveAt(index);
|
var next = entries.ToList(); next.RemoveAt(index);
|
||||||
if (!Save(next)) return false;
|
if (!Save(next)) return false;
|
||||||
deleted.Push((item, index)); if (undoButton != null) undoButton.IsEnabled = true;
|
deleted.Push((item, index)); UpdateUndoNotice(); return true;
|
||||||
status.Text = $"Deleted {item.Name} · Undo is available"; return true;
|
}
|
||||||
|
void UpdateUndoNotice()
|
||||||
|
{
|
||||||
|
undoNotice.Visibility = deleted.Count > 0 ? Visibility.Visible : Visibility.Collapsed;
|
||||||
|
status.Text = deleted.TryPeek(out var latest) ? $"Removed {latest.Item.Name}" : "";
|
||||||
|
if (undoButton != null) undoButton.IsEnabled = deleted.Count > 0;
|
||||||
}
|
}
|
||||||
void UndoDelete()
|
void UndoDelete()
|
||||||
{
|
{
|
||||||
if (!deleted.TryPeek(out var restore)) return;
|
if (!deleted.TryPeek(out var restore)) return;
|
||||||
var next = entries.ToList(); next.Insert(Math.Min(restore.Index, next.Count), restore.Item);
|
var next = entries.ToList(); next.Insert(Math.Min(restore.Index, next.Count), restore.Item);
|
||||||
if (Save(next)) { deleted.Pop(); if (undoButton != null) undoButton.IsEnabled = deleted.Count > 0; }
|
if (Save(next)) { deleted.Pop(); UpdateUndoNotice(); }
|
||||||
}
|
}
|
||||||
void ManageCollections()
|
void ManageCollections()
|
||||||
{
|
{
|
||||||
|
|||||||
+22
-14
@@ -1,4 +1,4 @@
|
|||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
@@ -7,7 +7,7 @@ using System.Windows.Input;
|
|||||||
using System.Windows.Media;
|
using System.Windows.Media;
|
||||||
using System.Windows.Media.Imaging;
|
using System.Windows.Media.Imaging;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
namespace ShortcutsPanel;
|
namespace Orbit;
|
||||||
public record Shortcut(string Name, string Url, string Group, string Color, string? Icon = null, string Id = "");
|
public record Shortcut(string Name, string Url, string Group, string Color, string? Icon = null, string Id = "");
|
||||||
public partial class MainWindow : Window
|
public partial class MainWindow : Window
|
||||||
{
|
{
|
||||||
@@ -17,7 +17,9 @@ public partial class MainWindow : Window
|
|||||||
readonly TextBlock heading = new() { FontSize = 30, FontWeight = FontWeights.SemiBold };
|
readonly TextBlock heading = new() { FontSize = 30, FontWeight = FontWeights.SemiBold };
|
||||||
static readonly Dictionary<string, Task<BitmapSource?>> logos = new();
|
static readonly Dictionary<string, Task<BitmapSource?>> logos = new();
|
||||||
readonly TextBox search = new() { Width = 280, ToolTip = "Search by name, website, or collection" };
|
readonly TextBox search = new() { Width = 280, ToolTip = "Search by name, website, or collection" };
|
||||||
readonly TextBlock status = new() { Foreground = Brush("#939DB8"), FontSize = 12 };
|
readonly TextBlock websiteCount = new() { FontSize = 12, Foreground = Brush("#7B8377"), VerticalAlignment = VerticalAlignment.Center };
|
||||||
|
readonly TextBlock status = new() { FontSize = 12, VerticalAlignment = VerticalAlignment.Center, TextTrimming = TextTrimming.CharacterEllipsis };
|
||||||
|
Border undoNotice = null!;
|
||||||
List<Shortcut> entries = [];
|
List<Shortcut> entries = [];
|
||||||
string selectedGroup = "All";
|
string selectedGroup = "All";
|
||||||
List<string> collectionOrder = [];
|
List<string> collectionOrder = [];
|
||||||
@@ -31,7 +33,7 @@ public partial class MainWindow : Window
|
|||||||
try { Theme.Apply(settings.LoadDarkTheme()); }
|
try { Theme.Apply(settings.LoadDarkTheme()); }
|
||||||
catch { Theme.Apply(false); }
|
catch { Theme.Apply(false); }
|
||||||
Background = Brush("#FAF9F6"); Foreground = Brush("#252924"); FontFamily = new FontFamily("Segoe UI");
|
Background = Brush("#FAF9F6"); Foreground = Brush("#252924"); FontFamily = new FontFamily("Segoe UI");
|
||||||
Title = "Orbit • Shortcuts Panel"; Width = 1100; Height = 720; MinWidth = 800; MinHeight = 520;
|
Title = "Orbit"; Width = 1100; Height = 720; MinWidth = 800; MinHeight = 520;
|
||||||
WindowStartupLocation = WindowStartupLocation.CenterScreen; WindowState = WindowState.Maximized;
|
WindowStartupLocation = WindowStartupLocation.CenterScreen; WindowState = WindowState.Maximized;
|
||||||
var root = new Grid(); Content = root;
|
var root = new Grid(); Content = root;
|
||||||
root.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(210) });
|
root.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(210) });
|
||||||
@@ -39,7 +41,7 @@ public partial class MainWindow : Window
|
|||||||
var sidebar = new DockPanel { Margin = new Thickness(20, 32, 20, 24) };
|
var sidebar = new DockPanel { Margin = new Thickness(20, 32, 20, 24) };
|
||||||
var sideSurface = new Border { Background = Brush("#F1F2ED"), BorderBrush = Brush("#E2E5DD"), BorderThickness = new Thickness(0,0,1,0), Child = sidebar }; root.Children.Add(sideSurface);
|
var sideSurface = new Border { Background = Brush("#F1F2ED"), BorderBrush = Brush("#E2E5DD"), BorderThickness = new Thickness(0,0,1,0), Child = sidebar }; root.Children.Add(sideSurface);
|
||||||
var brand = new StackPanel { Margin = new Thickness(12, 0, 0, 36) };
|
var brand = new StackPanel { Margin = new Thickness(12, 0, 0, 36) };
|
||||||
brand.Children.Add(new TextBlock { Text = "◉ orbit", FontSize = 27, FontWeight = FontWeights.SemiBold, Foreground = Brush("#294B3C") });
|
brand.Children.Add(new TextBlock { Text = "◉ Orbit", FontSize = 27, FontWeight = FontWeights.SemiBold, Foreground = Brush("#294B3C") });
|
||||||
brand.Children.Add(new TextBlock { Text = "A little more organized.", FontSize = 11, Foreground = Brush("#80877D"), Margin = new Thickness(1, 6, 0, 0) });
|
brand.Children.Add(new TextBlock { Text = "A little more organized.", FontSize = 11, Foreground = Brush("#80877D"), Margin = new Thickness(1, 6, 0, 0) });
|
||||||
DockPanel.SetDock(brand, Dock.Top); sidebar.Children.Add(brand);
|
DockPanel.SetDock(brand, Dock.Top); sidebar.Children.Add(brand);
|
||||||
var bottom = new StackPanel();
|
var bottom = new StackPanel();
|
||||||
@@ -68,17 +70,23 @@ public partial class MainWindow : Window
|
|||||||
var top = new StackPanel(); DockPanel.SetDock(top, Dock.Top); main.Children.Add(top);
|
var top = new StackPanel(); DockPanel.SetDock(top, Dock.Top); main.Children.Add(top);
|
||||||
var header = new DockPanel(); top.Children.Add(header);
|
var header = new DockPanel(); top.Children.Add(header);
|
||||||
var add = Button("+ Add website", () => Edit(null), "#294B3D"); add.Foreground = Brushes.White; add.VerticalAlignment = VerticalAlignment.Center; DockPanel.SetDock(add, Dock.Right); header.Children.Add(add);
|
var add = Button("+ Add website", () => Edit(null), "#294B3D"); add.Foreground = Brushes.White; add.VerticalAlignment = VerticalAlignment.Center; DockPanel.SetDock(add, Dock.Right); header.Children.Add(add);
|
||||||
header.Children.Add(heading);
|
var titleRow = new DockPanel();
|
||||||
|
var countBadge = new Border { Background = Brush("#DFE6DA"), CornerRadius = new CornerRadius(10), Padding = new Thickness(10,5,10,5), Margin = new Thickness(14,0,18,0), VerticalAlignment = VerticalAlignment.Center, Child = websiteCount };
|
||||||
|
DockPanel.SetDock(heading, Dock.Left); titleRow.Children.Add(heading); titleRow.Children.Add(countBadge);
|
||||||
|
countBadge.HorizontalAlignment = HorizontalAlignment.Left;
|
||||||
|
header.Children.Add(titleRow);
|
||||||
top.Children.Add(new TextBlock { Text = "Your favorite places, thoughtfully collected.", FontSize = 13, Foreground = Brush("#7B8377"), Margin = new Thickness(0, 9, 0, 26) });
|
top.Children.Add(new TextBlock { Text = "Your favorite places, thoughtfully collected.", FontSize = 13, Foreground = Brush("#7B8377"), Margin = new Thickness(0, 9, 0, 26) });
|
||||||
search.Width = double.NaN; search.HorizontalAlignment = HorizontalAlignment.Stretch;
|
search.Width = double.NaN; search.HorizontalAlignment = HorizontalAlignment.Stretch;
|
||||||
search.ToolTip = "Search websites and collections";
|
search.ToolTip = "Search websites and collections";
|
||||||
System.Windows.Automation.AutomationProperties.SetName(search, "Search websites");
|
System.Windows.Automation.AutomationProperties.SetName(search, "Search websites");
|
||||||
var searchRow = new DockPanel { Margin = new Thickness(0, 0, 8, 28) };
|
var searchRow = new DockPanel { Margin = new Thickness(0, 0, 8, 28) };
|
||||||
var searchLabel = new TextBlock { Text = "Search", VerticalAlignment = VerticalAlignment.Center, Margin = new Thickness(0,0,12,0), Foreground = Brush("#7B8377"), FontSize = 12 }; searchRow.Children.Add(searchLabel); searchRow.Children.Add(search); top.Children.Add(searchRow);
|
var searchLabel = new TextBlock { Text = "Search", VerticalAlignment = VerticalAlignment.Center, Margin = new Thickness(0,0,12,0), Foreground = Brush("#7B8377"), FontSize = 12 }; searchRow.Children.Add(searchLabel); searchRow.Children.Add(search); top.Children.Add(searchRow);
|
||||||
var footer = new DockPanel { Margin = new Thickness(0, 16, 8, 0) }; DockPanel.SetDock(footer, Dock.Bottom); main.Children.Add(footer);
|
var noticeRow = new DockPanel();
|
||||||
undoButton = Button("Undo deletion", UndoDelete); undoButton.IsEnabled = false;
|
undoButton = Button("Undo", UndoDelete); undoButton.Margin = new Thickness(16,0,0,0);
|
||||||
DockPanel.SetDock(undoButton, Dock.Right); footer.Children.Add(undoButton);
|
DockPanel.SetDock(undoButton, Dock.Right); noticeRow.Children.Add(undoButton);
|
||||||
status.Foreground = Brush("#868D80"); footer.Children.Add(status);
|
status.Foreground = Brush("#374632"); noticeRow.Children.Add(status);
|
||||||
|
undoNotice = new Border { Background = Brush("#DFE6DA"), BorderBrush = Brush("#E2E5DD"), BorderThickness = new Thickness(1), CornerRadius = new CornerRadius(10), Padding = new Thickness(14,8,8,8), Margin = new Thickness(0,12,8,0), MaxWidth = 460, HorizontalAlignment = HorizontalAlignment.Left, Visibility = Visibility.Collapsed, Child = noticeRow };
|
||||||
|
DockPanel.SetDock(undoNotice, Dock.Bottom); main.Children.Add(undoNotice);
|
||||||
main.Children.Add(new ScrollViewer { Content = cards, VerticalScrollBarVisibility = ScrollBarVisibility.Auto, HorizontalScrollBarVisibility = ScrollBarVisibility.Disabled });
|
main.Children.Add(new ScrollViewer { Content = cards, VerticalScrollBarVisibility = ScrollBarVisibility.Auto, HorizontalScrollBarVisibility = ScrollBarVisibility.Disabled });
|
||||||
search.TextChanged += (_, _) => RenderCards();
|
search.TextChanged += (_, _) => RenderCards();
|
||||||
Load(); Render();
|
Load(); Render();
|
||||||
@@ -126,9 +134,9 @@ public partial class MainWindow : Window
|
|||||||
b.HorizontalContentAlignment = HorizontalAlignment.Stretch;
|
b.HorizontalContentAlignment = HorizontalAlignment.Stretch;
|
||||||
var row = new DockPanel { Width = 138 };
|
var row = new DockPanel { Width = 138 };
|
||||||
var number = new TextBlock { Text = count.ToString(), Foreground = Brush("#7B8377"), FontSize = 11, VerticalAlignment = VerticalAlignment.Center }; DockPanel.SetDock(number, Dock.Right); row.Children.Add(number);
|
var number = new TextBlock { Text = count.ToString(), Foreground = Brush("#7B8377"), FontSize = 11, VerticalAlignment = VerticalAlignment.Center }; DockPanel.SetDock(number, Dock.Right); row.Children.Add(number);
|
||||||
row.Children.Add(new TextBlock { Text = name == "All" ? "▦ All websites" : "• " + name, FontSize = 12, TextTrimming = TextTrimming.CharacterEllipsis, Foreground = Brush("#374632") });
|
row.Children.Add(new TextBlock { Text = name == "All" ? "▦ All Websites" : "• " + name, FontSize = 12, TextTrimming = TextTrimming.CharacterEllipsis, Foreground = Brush("#374632") });
|
||||||
b.Content = row; b.Margin = new Thickness(0,0,0,6); groups.Children.Add(b);
|
b.Content = row; b.Margin = new Thickness(0,0,0,6); groups.Children.Add(b);
|
||||||
System.Windows.Automation.AutomationProperties.SetName(b, name == "All" ? "All websites" : name);
|
System.Windows.Automation.AutomationProperties.SetName(b, name == "All" ? "All Websites" : name);
|
||||||
if (name != "All") ConfigureCollection(b, name);
|
if (name != "All") ConfigureCollection(b, name);
|
||||||
}
|
}
|
||||||
RenderCards();
|
RenderCards();
|
||||||
@@ -160,8 +168,8 @@ public partial class MainWindow : Window
|
|||||||
cards.Children.Add(card); ConfigureCard(card, item);
|
cards.Children.Add(card); ConfigureCard(card, item);
|
||||||
}
|
}
|
||||||
if (filtered.Count == 0) cards.Children.Add(new TextBlock { Text = entries.Count == 0 ? "A fresh start. Add your first website above." : "No websites match. Try another search or collection.", FontSize = 18, Margin = new Thickness(0, 35, 0, 35) });
|
if (filtered.Count == 0) cards.Children.Add(new TextBlock { Text = entries.Count == 0 ? "A fresh start. Add your first website above." : "No websites match. Try another search or collection.", FontSize = 18, Margin = new Thickness(0, 35, 0, 35) });
|
||||||
heading.Text = selectedGroup == "All" ? "All websites" : selectedGroup;
|
heading.Text = selectedGroup == "All" ? "All Websites" : selectedGroup;
|
||||||
status.Text = $"{filtered.Count} websites · Opens in your default browser";
|
websiteCount.Text = $"{filtered.Count} {(filtered.Count == 1 ? "Website" : "Websites")}";
|
||||||
}
|
}
|
||||||
static async Task ApplyLogo(Border badge, string url)
|
static async Task ApplyLogo(Border badge, string url)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -6,8 +6,11 @@
|
|||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<ApplicationIcon>app.ico</ApplicationIcon>
|
<ApplicationIcon>app.ico</ApplicationIcon>
|
||||||
<AssemblyName>ShortcutsPanel</AssemblyName>
|
<AssemblyName>Orbit</AssemblyName>
|
||||||
<Version>1.1.2</Version>
|
<Version>1.1.3</Version>
|
||||||
|
<Product>Orbit</Product>
|
||||||
|
<Title>Orbit</Title>
|
||||||
|
<Description>Orbit website launcher</Description>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup><Compile Remove="tests/**/*.cs" /></ItemGroup>
|
<ItemGroup><Compile Remove="tests/**/*.cs" /></ItemGroup>
|
||||||
<ItemGroup><EmbeddedResource Include="app.ico" LogicalName="OrbitIcon" /></ItemGroup>
|
<ItemGroup><EmbeddedResource Include="app.ico" LogicalName="OrbitIcon" /></ItemGroup>
|
||||||
@@ -1,6 +1,18 @@
|
|||||||
# Orbit
|
# Orbit
|
||||||
|
|
||||||
A portable C# / WPF website launcher for Windows, created by **Dario P.**
|
A portable C# / WPF website launcher for Windows.
|
||||||
|
|
||||||
|
[**Download for Windows**](https://github.com/donishki/orbit/releases/latest) | [Features](#features) | [Build from source](#build)
|
||||||
|
|
||||||
|
## Screenshots
|
||||||
|
|
||||||
|
### Charcoal
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
### Light
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
@@ -13,9 +25,13 @@ A portable C# / WPF website launcher for Windows, created by **Dario P.**
|
|||||||
|
|
||||||
## Run
|
## Run
|
||||||
|
|
||||||
Download the portable Windows x64 package from this repository's Releases page,
|
Choose a Windows x64 (64-bit) or x86 (32-bit) download from [Releases](https://github.com/donishki/orbit/releases/latest):
|
||||||
extract it, and run `ShortcutsPanel.exe`. No installer or separate .NET runtime
|
|
||||||
is required. Windows 10 or Windows 11, 64-bit.
|
- **Orbit-Setup-win-x64.exe**: installs Orbit for your Windows account, adds a Start menu shortcut, and offers an optional desktop shortcut. Remove it through Windows Settings > Apps.
|
||||||
|
- **Orbit-Portable-win-x64.zip**: extract and run `Orbit.exe`, without installing.
|
||||||
|
- **Orbit-Setup-win-x86.exe** / **Orbit-Portable-win-x86.zip**: the equivalent 32-bit versions.
|
||||||
|
|
||||||
|
All packages include .NET. Use x64 for 64-bit Windows 10/11, or x86 for 32-bit Windows 10 (also runnable on 64-bit Windows). The installer defaults to `%LOCALAPPDATA%\Programs\Orbit`, requires no administrator password, and preserves links and settings during upgrades and uninstall. The x86 installer uses `%LOCALAPPDATA%\Programs\Orbit-x86` and labels shortcuts "Orbit (32-bit)" so both architectures can coexist. Installed and portable copies share the same settings for your account.
|
||||||
|
|
||||||
## Settings
|
## Settings
|
||||||
|
|
||||||
@@ -32,9 +48,24 @@ the theme remains local. Undo history lasts for the current session.
|
|||||||
Requires Windows and the .NET 8 SDK.
|
Requires Windows and the .NET 8 SDK.
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
dotnet publish ShortcutsPanel.csproj -c Release -r win-x64 --self-contained true -p:PublishSingleFile=true -p:IncludeNativeLibrariesForSelfExtract=true -p:DebugType=None -p:DebugSymbols=false -o release
|
dotnet publish Orbit.csproj -c Release -r win-x64 --self-contained true -p:PublishSingleFile=true -p:IncludeNativeLibrariesForSelfExtract=true -p:DebugType=None -p:DebugSymbols=false -o release
|
||||||
```
|
```
|
||||||
|
|
||||||
|
For the 32-bit portable build, replace `win-x64` with `win-x86` and use a separate output directory.
|
||||||
|
|
||||||
|
### Build the installer
|
||||||
|
|
||||||
|
Install Inno Setup 7, then run:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
./installer/Build-Installer.ps1
|
||||||
|
./installer/Build-Installer.ps1 -Architecture x86
|
||||||
|
```
|
||||||
|
|
||||||
|
Use `-IsccPath` for a compiler installed elsewhere. The output is
|
||||||
|
`release/Orbit-Setup-win-x64.exe` or `release/Orbit-Setup-win-x86.exe`. The installer bundles the runtime as normal
|
||||||
|
files so the installed app does not need to extract it on launch.
|
||||||
|
|
||||||
## Checks
|
## Checks
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
|
|||||||
+11
-5
@@ -1,8 +1,12 @@
|
|||||||
ORBIT 1.1.2 - WEBSITE SHORTCUTS
|
ORBIT 1.1.3 - WEBSITE SHORTCUTS
|
||||||
Created by Dario P.
|
Created by Dario P.
|
||||||
|
|
||||||
Run ShortcutsPanel.exe on 64-bit Windows 10 or Windows 11.
|
Run Orbit.exe. Choose x64 for 64-bit Windows 10/11, or x86 for 32-bit
|
||||||
No installer or separate .NET installation is required.
|
Windows 10. The x86 version also runs on 64-bit Windows.
|
||||||
|
The portable version needs no installer or separate .NET installation.
|
||||||
|
Alternatively, run Orbit-Setup-win-x64.exe or Orbit-Setup-win-x86.exe to install Orbit for your Windows
|
||||||
|
account with a Start menu shortcut and optional desktop shortcut. Uninstall
|
||||||
|
through Windows Settings > Apps. Saved links and settings are preserved.
|
||||||
|
|
||||||
NEW IN 1.1
|
NEW IN 1.1
|
||||||
- Import / Export: share a JSON library including custom icons and collection
|
- Import / Export: share a JSON library including custom icons and collection
|
||||||
@@ -20,7 +24,7 @@ NEW IN 1.1
|
|||||||
Importing a library clears undo history. Undo history is not saved on exit.
|
Importing a library clears undo history. Undo history is not saved on exit.
|
||||||
- Open collection is available in Manage collections and the right-click menu.
|
- Open collection is available in Manage collections and the right-click menu.
|
||||||
Opening multiple sites asks for confirmation and opens each distinct URL once.
|
Opening multiple sites asks for confirmation and opens each distinct URL once.
|
||||||
- About Orbit displays version 1.1.2 and author Dario P.
|
- About Orbit displays version 1.1.3 and author Dario P.
|
||||||
|
|
||||||
Add, edit, delete, search, and group website cards. Dark mode is optional.
|
Add, edit, delete, search, and group website cards. Dark mode is optional.
|
||||||
Website icons are discovered from page metadata, then /favicon.ico.
|
Website icons are discovered from page metadata, then /favicon.ico.
|
||||||
@@ -44,7 +48,7 @@ The bundled .NET runtime extracts supporting files to temporary storage.
|
|||||||
This executable is not digitally signed.
|
This executable is not digitally signed.
|
||||||
|
|
||||||
Build:
|
Build:
|
||||||
dotnet publish ShortcutsPanel.csproj -c Release -r win-x64 --self-contained true -p:PublishSingleFile=true -p:IncludeNativeLibrariesForSelfExtract=true -p:DebugType=None -p:DebugSymbols=false -o release
|
dotnet publish Orbit.csproj -c Release -r win-x64 --self-contained true -p:PublishSingleFile=true -p:IncludeNativeLibrariesForSelfExtract=true -p:DebugType=None -p:DebugSymbols=false -o release
|
||||||
|
|
||||||
Checks:
|
Checks:
|
||||||
dotnet run --project tests/StorageChecks.csproj
|
dotnet run --project tests/StorageChecks.csproj
|
||||||
@@ -54,3 +58,5 @@ dotnet run --project tests/ThemeChecks.csproj
|
|||||||
1.1.1: aligned sidebar rows, whole-card dragging, and the Orbit icon in About.
|
1.1.1: aligned sidebar rows, whole-card dragging, and the Orbit icon in About.
|
||||||
|
|
||||||
1.1.2: starts maximized; green outer borders for drag/focus; Dark mode is at the sidebar bottom; About credits Dario P. and 2026.
|
1.1.2: starts maximized; green outer borders for drag/focus; Dark mode is at the sidebar bottom; About credits Dario P. and 2026.
|
||||||
|
|
||||||
|
1.1.3: Orbit naming throughout; website count beside the heading; contextual Undo notice; cleaner library layout.
|
||||||
+1
-1
@@ -2,7 +2,7 @@ using System.IO;
|
|||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using Microsoft.Win32;
|
using Microsoft.Win32;
|
||||||
|
|
||||||
namespace ShortcutsPanel;
|
namespace Orbit;
|
||||||
|
|
||||||
public sealed class SettingsStore
|
public sealed class SettingsStore
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using System.Windows;
|
using System.Windows;
|
||||||
|
|
||||||
using System.Windows.Media;
|
using System.Windows.Media;
|
||||||
|
|
||||||
@@ -8,7 +8,7 @@ using System.ComponentModel;
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
namespace ShortcutsPanel;
|
namespace Orbit;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -5,7 +5,7 @@ using System.Text;
|
|||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using System.Windows.Media.Imaging;
|
using System.Windows.Media.Imaging;
|
||||||
|
|
||||||
namespace ShortcutsPanel;
|
namespace Orbit;
|
||||||
|
|
||||||
public static class WebsiteIcons
|
public static class WebsiteIcons
|
||||||
{
|
{
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 43 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 46 KiB |
@@ -0,0 +1,12 @@
|
|||||||
|
param([ValidateSet("x64", "x86")][string]$Architecture = "x64", [string]$IsccPath = "${env:ProgramFiles(x86)}\Inno Setup 7\ISCC.exe")
|
||||||
|
$ErrorActionPreference = 'Stop'
|
||||||
|
$projectRoot = Split-Path $PSScriptRoot -Parent
|
||||||
|
if (!(Test-Path -LiteralPath $IsccPath)) { throw "Inno Setup compiler not found. Supply -IsccPath with the path to ISCC.exe." }
|
||||||
|
Push-Location $projectRoot
|
||||||
|
try {
|
||||||
|
dotnet publish Orbit.csproj -c Release -r "win-$Architecture" --self-contained true -p:PublishSingleFile=false -p:DebugType=None -p:DebugSymbols=false -o "release/installer-payload-$Architecture"
|
||||||
|
if ($LASTEXITCODE -ne 0) { throw 'Publish failed.' }
|
||||||
|
Copy-Item README.txt "release/installer-payload-$Architecture/README.txt"
|
||||||
|
& $IsccPath "/DArch=$Architecture" installer/Orbit.iss
|
||||||
|
if ($LASTEXITCODE -ne 0) { throw 'Installer compilation failed.' }
|
||||||
|
} finally { Pop-Location }
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
#ifndef Arch
|
||||||
|
#define Arch "x64"
|
||||||
|
#endif
|
||||||
|
#define Payload "..\release\installer-payload-" + Arch
|
||||||
|
#define AppVersion GetVersionNumbersString(Payload + "\Orbit.exe")
|
||||||
|
[Setup]
|
||||||
|
#if Arch == "x86"
|
||||||
|
AppId={{A2A7C189-843C-4D5F-B2F3-05A80A936C95}
|
||||||
|
DefaultDirName={localappdata}\Programs\Orbit-x86
|
||||||
|
#define ShortcutName "Orbit (32-bit)"
|
||||||
|
#else
|
||||||
|
AppId={{60E686D4-296A-41D2-B445-5DDC79FD2A2C}
|
||||||
|
DefaultDirName={localappdata}\Programs\Orbit
|
||||||
|
#define ShortcutName "Orbit"
|
||||||
|
#endif
|
||||||
|
AppName=Orbit
|
||||||
|
AppVersion={#AppVersion}
|
||||||
|
AppPublisher=Dario P.
|
||||||
|
AppPublisherURL=https://github.com/donishki/orbit
|
||||||
|
AppSupportURL=https://github.com/donishki/orbit/issues
|
||||||
|
AppUpdatesURL=https://github.com/donishki/orbit/releases/latest
|
||||||
|
DefaultGroupName=Orbit
|
||||||
|
DisableProgramGroupPage=yes
|
||||||
|
PrivilegesRequired=lowest
|
||||||
|
SetupArchitecture=x86
|
||||||
|
#if Arch == "x64"
|
||||||
|
ArchitecturesAllowed=x64compatible
|
||||||
|
ArchitecturesInstallIn64BitMode=x64compatible
|
||||||
|
#else
|
||||||
|
ArchitecturesAllowed=x86compatible
|
||||||
|
#endif
|
||||||
|
MinVersion=10.0
|
||||||
|
OutputDir=..\release
|
||||||
|
OutputBaseFilename=Orbit-Setup-win-{#Arch}
|
||||||
|
SetupIconFile=..\app.ico
|
||||||
|
UninstallDisplayIcon={app}\Orbit.exe
|
||||||
|
UninstallDisplayName={#ShortcutName}
|
||||||
|
WizardStyle=modern
|
||||||
|
Compression=lzma2
|
||||||
|
SolidCompression=yes
|
||||||
|
CloseApplications=yes
|
||||||
|
RestartApplications=no
|
||||||
|
|
||||||
|
[Tasks]
|
||||||
|
Name: "desktopicon"; Description: "Create a &desktop shortcut"; GroupDescription: "Shortcuts:"; Flags: unchecked
|
||||||
|
|
||||||
|
[Files]
|
||||||
|
Source: "{#Payload}\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs
|
||||||
|
|
||||||
|
[Icons]
|
||||||
|
Name: "{autoprograms}\{#ShortcutName}"; Filename: "{app}\Orbit.exe"; WorkingDir: "{app}"
|
||||||
|
Name: "{autodesktop}\{#ShortcutName}"; Filename: "{app}\Orbit.exe"; WorkingDir: "{app}"; Tasks: desktopicon
|
||||||
|
|
||||||
|
[Run]
|
||||||
|
Filename: "{app}\Orbit.exe"; Description: "Launch Orbit"; Flags: nowait postinstall skipifsilent
|
||||||
|
|
||||||
|
; Deliberately do not remove the user's %LOCALAPPDATA%\Orbit settings on uninstall.
|
||||||
@@ -3,7 +3,7 @@ using System.Reflection;
|
|||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using System.Windows.Media;
|
using System.Windows.Media;
|
||||||
using System.Windows.Media.Imaging;
|
using System.Windows.Media.Imaging;
|
||||||
using ShortcutsPanel;
|
using Orbit;
|
||||||
|
|
||||||
internal static class FeatureChecks
|
internal static class FeatureChecks
|
||||||
{
|
{
|
||||||
@@ -17,6 +17,8 @@ internal static class FeatureChecks
|
|||||||
var app = new App(); app.InitializeComponent();
|
var app = new App(); app.InitializeComponent();
|
||||||
Check(MainWindow.LoadAppIcon().PixelWidth > 0, "About icon loads from embedded resource");
|
Check(MainWindow.LoadAppIcon().PixelWidth > 0, "About icon loads from embedded resource");
|
||||||
var window = new MainWindow(store);
|
var window = new MainWindow(store);
|
||||||
|
var notice = (System.Windows.Controls.Border)typeof(MainWindow).GetField("undoNotice", BindingFlags.NonPublic | BindingFlags.Instance)!.GetValue(window)!;
|
||||||
|
Check(window.Title == "Orbit" && notice.Visibility == System.Windows.Visibility.Collapsed, "Orbit title and hidden initial Undo notice");
|
||||||
object? Call(string method, params object?[] args) => typeof(MainWindow).GetMethod(method, BindingFlags.NonPublic | BindingFlags.Instance)!.Invoke(window, args);
|
object? Call(string method, params object?[] args) => typeof(MainWindow).GetMethod(method, BindingFlags.NonPublic | BindingFlags.Instance)!.Invoke(window, args);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -31,7 +33,9 @@ internal static class FeatureChecks
|
|||||||
Check(JsonSerializer.Deserialize<List<Shortcut>>(store.Load()!)![0].Name == "C", "Card order persists");
|
Check(JsonSerializer.Deserialize<List<Shortcut>>(store.Load()!)![0].Name == "C", "Card order persists");
|
||||||
Check((bool)Call("DeleteShortcut", original[0])!, "Delete shortcut");
|
Check((bool)Call("DeleteShortcut", original[0])!, "Delete shortcut");
|
||||||
Check(JsonSerializer.Deserialize<List<Shortcut>>(store.Load()!)!.Count == 2, "Deletion saved");
|
Check(JsonSerializer.Deserialize<List<Shortcut>>(store.Load()!)!.Count == 2, "Deletion saved");
|
||||||
|
Check(notice.Visibility == System.Windows.Visibility.Visible, "Undo notice appears after deletion");
|
||||||
Call("UndoDelete");
|
Call("UndoDelete");
|
||||||
|
Check(notice.Visibility == System.Windows.Visibility.Collapsed, "Undo notice hides after restoring last deletion");
|
||||||
Check(JsonSerializer.Deserialize<List<Shortcut>>(store.Load()!)!.Select(x => x.Name).SequenceEqual(new[] { "C", "A", "B" }), "Undo restores original position");
|
Check(JsonSerializer.Deserialize<List<Shortcut>>(store.Load()!)!.Select(x => x.Name).SequenceEqual(new[] { "C", "A", "B" }), "Undo restores original position");
|
||||||
var pngPath = Path.Combine(directory, "icon.png");
|
var pngPath = Path.Combine(directory, "icon.png");
|
||||||
var bitmap = BitmapSource.Create(2, 2, 96, 96, PixelFormats.Bgra32, null, new byte[] { 0,0,255,255, 0,255,0,255, 255,0,0,255, 255,255,255,255 }, 8);
|
var bitmap = BitmapSource.Create(2, 2, 96, 96, PixelFormats.Bgra32, null, new byte[] { 0,0,255,255, 0,255,0,255, 255,0,0,255, 255,255,255,255 }, 8);
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
<PropertyGroup><OutputType>Exe</OutputType><TargetFramework>net8.0-windows</TargetFramework><UseWPF>true</UseWPF><ImplicitUsings>enable</ImplicitUsings><Nullable>enable</Nullable><EnableDefaultCompileItems>false</EnableDefaultCompileItems></PropertyGroup>
|
<PropertyGroup><OutputType>Exe</OutputType><TargetFramework>net8.0-windows</TargetFramework><UseWPF>true</UseWPF><ImplicitUsings>enable</ImplicitUsings><Nullable>enable</Nullable><EnableDefaultCompileItems>false</EnableDefaultCompileItems></PropertyGroup>
|
||||||
<ItemGroup><Compile Include="FeatureChecks.cs"/><ProjectReference Include="../ShortcutsPanel.csproj"/></ItemGroup>
|
<ItemGroup><Compile Include="FeatureChecks.cs"/><ProjectReference Include="../Orbit.csproj"/></ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
using Microsoft.Win32;
|
using Microsoft.Win32;
|
||||||
using ShortcutsPanel;
|
using Orbit;
|
||||||
var key = @"Software\OrbitStorageChecks\" + Guid.NewGuid().ToString("N");
|
var key = @"Software\OrbitStorageChecks\" + Guid.NewGuid().ToString("N");
|
||||||
var folder = Path.Combine(Path.GetTempPath(), "OrbitStorageChecks-" + Guid.NewGuid().ToString("N"));
|
var folder = Path.Combine(Path.GetTempPath(), "OrbitStorageChecks-" + Guid.NewGuid().ToString("N"));
|
||||||
Directory.CreateDirectory(folder);
|
Directory.CreateDirectory(folder);
|
||||||
|
|||||||
+18
-3
@@ -3,7 +3,7 @@ using System.Windows.Controls;
|
|||||||
using System.Windows.Media;
|
using System.Windows.Media;
|
||||||
using System.Windows.Media.Imaging;
|
using System.Windows.Media.Imaging;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using ShortcutsPanel;
|
using Orbit;
|
||||||
|
|
||||||
internal static class ThemeChecks
|
internal static class ThemeChecks
|
||||||
{
|
{
|
||||||
@@ -16,16 +16,26 @@ internal static class ThemeChecks
|
|||||||
foreach (var site in new[] { "https://github.com", "https://www.google.com" })
|
foreach (var site in new[] { "https://github.com", "https://www.google.com" })
|
||||||
Console.WriteLine("Live icon " + site + ": " + (WebsiteIcons.Fetch(site).GetAwaiter().GetResult() != null ? "loaded" : "fallback"));
|
Console.WriteLine("Live icon " + site + ": " + (WebsiteIcons.Fetch(site).GetAwaiter().GetResult() != null ? "loaded" : "fallback"));
|
||||||
var app = new App(); app.InitializeComponent();
|
var app = new App(); app.InitializeComponent();
|
||||||
var window = new MainWindow();
|
SynchronizationContext.SetSynchronizationContext(new System.Windows.Threading.DispatcherSynchronizationContext());
|
||||||
|
var isolated = Path.Combine(Path.GetTempPath(), "OrbitPreview-" + Guid.NewGuid().ToString("N"));
|
||||||
|
var window = new MainWindow(new SettingsStore(@"Software\OrbitPreview-" + Guid.NewGuid().ToString("N"), Path.Combine(isolated, "absent.json"), isolated));
|
||||||
var content = (FrameworkElement)window.Content;
|
var content = (FrameworkElement)window.Content;
|
||||||
|
window.WindowState = WindowState.Normal;
|
||||||
|
content.Width = 1100; content.Height = 680;
|
||||||
|
// Let asynchronous website icons finish without reading or altering the user's library.
|
||||||
|
var wait = new System.Windows.Threading.DispatcherFrame();
|
||||||
|
var timer = new System.Windows.Threading.DispatcherTimer { Interval = TimeSpan.FromSeconds(8) };
|
||||||
|
timer.Tick += (_, _) => { timer.Stop(); wait.Continue = false; };
|
||||||
|
timer.Start(); System.Windows.Threading.Dispatcher.PushFrame(wait);
|
||||||
var output = Path.Combine(Path.GetTempPath(), "OrbitThemePreview"); Directory.CreateDirectory(output);
|
var output = Path.Combine(Path.GetTempPath(), "OrbitThemePreview"); Directory.CreateDirectory(output);
|
||||||
foreach (var dark in new[] { false, true, false })
|
foreach (var dark in new[] { false, true, false })
|
||||||
{
|
{
|
||||||
Theme.Apply(dark);
|
Theme.Apply(dark);
|
||||||
|
SetSwitch(content, dark);
|
||||||
content.Measure(new Size(1100, 680)); content.Arrange(new Rect(0, 0, 1100, 680)); content.UpdateLayout();
|
content.Measure(new Size(1100, 680)); content.Arrange(new Rect(0, 0, 1100, 680)); content.UpdateLayout();
|
||||||
if (((SolidColorBrush)window.Background).Color != (Color)ColorConverter.ConvertFromString(dark ? "#202020" : "#FAF9F6")) throw new Exception("Window theme did not update");
|
if (((SolidColorBrush)window.Background).Color != (Color)ColorConverter.ConvertFromString(dark ? "#202020" : "#FAF9F6")) throw new Exception("Window theme did not update");
|
||||||
var bitmap = new RenderTargetBitmap(1100, 680, 96, 96, PixelFormats.Pbgra32);
|
var bitmap = new RenderTargetBitmap(1100, 680, 96, 96, PixelFormats.Pbgra32);
|
||||||
var frame = new DrawingVisual(); using (var dc = frame.RenderOpen()) { dc.DrawRectangle(window.Background, null, new Rect(0,0,1100,680)); dc.DrawRectangle(new VisualBrush(content), null, new Rect(0,0,1100,680)); }
|
var frame = new DrawingVisual(); using (var dc = frame.RenderOpen()) { dc.DrawRectangle(window.Background, null, new Rect(0,0,1100,680)); dc.DrawRectangle(new VisualBrush(content) { ViewboxUnits = BrushMappingMode.Absolute, Viewbox = new Rect(0,0,1100,680) }, null, new Rect(0,0,1100,680)); }
|
||||||
bitmap.Render(frame); var encoder = new PngBitmapEncoder(); encoder.Frames.Add(BitmapFrame.Create(bitmap));
|
bitmap.Render(frame); var encoder = new PngBitmapEncoder(); encoder.Frames.Add(BitmapFrame.Create(bitmap));
|
||||||
using var file = File.Create(Path.Combine(output, dark ? "dark.png" : "light.png")); encoder.Save(file);
|
using var file = File.Create(Path.Combine(output, dark ? "dark.png" : "light.png")); encoder.Save(file);
|
||||||
Console.WriteLine("PASS rendered " + (dark ? "dark" : "light") + " theme");
|
Console.WriteLine("PASS rendered " + (dark ? "dark" : "light") + " theme");
|
||||||
@@ -33,4 +43,9 @@ internal static class ThemeChecks
|
|||||||
Console.WriteLine(output);
|
Console.WriteLine(output);
|
||||||
window.Close(); app.Shutdown();
|
window.Close(); app.Shutdown();
|
||||||
}
|
}
|
||||||
|
static void SetSwitch(DependencyObject parent, bool dark)
|
||||||
|
{
|
||||||
|
if (parent is CheckBox toggle && toggle.Content as string == "Dark mode") toggle.IsChecked = dark;
|
||||||
|
for (int index = 0; index < VisualTreeHelper.GetChildrenCount(parent); index++) SetSwitch(VisualTreeHelper.GetChild(parent, index), dark);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
<PropertyGroup><OutputType>Exe</OutputType><TargetFramework>net8.0-windows</TargetFramework><UseWPF>true</UseWPF><ImplicitUsings>enable</ImplicitUsings><Nullable>enable</Nullable><EnableDefaultCompileItems>false</EnableDefaultCompileItems></PropertyGroup>
|
<PropertyGroup><OutputType>Exe</OutputType><TargetFramework>net8.0-windows</TargetFramework><UseWPF>true</UseWPF><ImplicitUsings>enable</ImplicitUsings><Nullable>enable</Nullable><EnableDefaultCompileItems>false</EnableDefaultCompileItems></PropertyGroup>
|
||||||
<ItemGroup><Compile Include="ThemeChecks.cs"/><ProjectReference Include="../ShortcutsPanel.csproj"/></ItemGroup>
|
<ItemGroup><Compile Include="ThemeChecks.cs"/><ProjectReference Include="../Orbit.csproj"/></ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
Reference in new issue
Block a user