diff --git a/CLAUDE.md b/CLAUDE.md
index b6160ba..a93d930 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -54,12 +54,17 @@ git branch # Should show: * final
| NewTodoPage.xaml | [ ] | Add new todo form |
| TodoDetailPage.xaml | [ ] | Edit todo details |
-### XamlBrowser (app + 1 page)
+### XamlBrowser (app + 1 page) - COMPLETE
| File | Status | Notes |
|------|--------|-------|
-| BrowserApp.xaml | [ ] | Basic app setup |
-| MainPage.xaml | [ ] | WebView browser |
+| App.xaml | [x] | Colors, styles (NavButtonStyle, GoButtonStyle, AddressBarStyle, StatusLabelStyle) |
+| App.xaml.cs | [x] | BrowserApp with ToggleTheme() |
+| MainPage.xaml | [x] | Toolbar with nav buttons, address bar, WebView, status bar |
+| MainPage.xaml.cs | [x] | Navigation logic, progress animation, theme toggle |
+| MauiProgram.cs | [x] | UseLinuxPlatform() setup |
+| Program.cs | [x] | LinuxProgramHost entry point |
+| Resources/Images/*.svg | [x] | 10 toolbar icons (dark/light variants) |
---
diff --git a/samples/XamlBrowser/App.xaml b/samples/XamlBrowser/App.xaml
new file mode 100644
index 0000000..2a41fdf
--- /dev/null
+++ b/samples/XamlBrowser/App.xaml
@@ -0,0 +1,80 @@
+
+
+
+
+
+ #1A73E8
+ #8AB4F8
+
+
+ #FFFFFF
+ #202124
+
+
+ #FFFFFF
+ #292A2D
+
+
+ #F1F3F4
+ #3C4043
+
+
+ #F1F3F4
+ #202124
+
+
+ #202124
+ #E8EAED
+ #5F6368
+ #9AA0A6
+
+
+ #80868B
+ #9AA0A6
+
+
+ #F8F9FA
+ #35363A
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/samples/XamlBrowser/App.xaml.cs b/samples/XamlBrowser/App.xaml.cs
new file mode 100644
index 0000000..e5e8da6
--- /dev/null
+++ b/samples/XamlBrowser/App.xaml.cs
@@ -0,0 +1,20 @@
+using Microsoft.Maui;
+using Microsoft.Maui.ApplicationModel;
+using Microsoft.Maui.Controls;
+
+namespace XamlBrowser;
+
+public partial class BrowserApp : Application
+{
+ public BrowserApp()
+ {
+ InitializeComponent();
+ UserAppTheme = AppTheme.Dark;
+ MainPage = new MainPage();
+ }
+
+ public void ToggleTheme()
+ {
+ UserAppTheme = UserAppTheme == AppTheme.Light ? AppTheme.Dark : AppTheme.Light;
+ }
+}
diff --git a/samples/XamlBrowser/MainPage.xaml b/samples/XamlBrowser/MainPage.xaml
new file mode 100644
index 0000000..b8a849f
--- /dev/null
+++ b/samples/XamlBrowser/MainPage.xaml
@@ -0,0 +1,133 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/samples/XamlBrowser/MainPage.xaml.cs b/samples/XamlBrowser/MainPage.xaml.cs
new file mode 100644
index 0000000..d576f8f
--- /dev/null
+++ b/samples/XamlBrowser/MainPage.xaml.cs
@@ -0,0 +1,128 @@
+using System;
+using Microsoft.Maui;
+using Microsoft.Maui.Controls;
+
+namespace XamlBrowser;
+
+public partial class MainPage : ContentPage
+{
+ private const string HomeUrl = "https://openmaui.net";
+
+ public MainPage()
+ {
+ InitializeComponent();
+ AddressBar.Text = HomeUrl;
+ }
+
+ private void OnBackClicked(object? sender, EventArgs e)
+ {
+ Console.WriteLine($"[MainPage] OnBackClicked, CanGoBack={BrowserWebView.CanGoBack}");
+ if (BrowserWebView.CanGoBack)
+ {
+ BrowserWebView.GoBack();
+ }
+ }
+
+ private void OnForwardClicked(object? sender, EventArgs e)
+ {
+ Console.WriteLine($"[MainPage] OnForwardClicked, CanGoForward={BrowserWebView.CanGoForward}");
+ if (BrowserWebView.CanGoForward)
+ {
+ BrowserWebView.GoForward();
+ }
+ }
+
+ private void OnRefreshClicked(object? sender, EventArgs e)
+ {
+ Console.WriteLine("[MainPage] OnRefreshClicked");
+ BrowserWebView.Reload();
+ }
+
+ private void OnStopClicked(object? sender, EventArgs e)
+ {
+ LoadingProgress.IsVisible = false;
+ StatusLabel.Text = "Stopped";
+ }
+
+ private void OnHomeClicked(object? sender, EventArgs e)
+ {
+ NavigateTo(HomeUrl);
+ }
+
+ private void OnAddressBarCompleted(object? sender, EventArgs e)
+ {
+ NavigateTo(AddressBar.Text);
+ }
+
+ private void OnGoClicked(object? sender, EventArgs e)
+ {
+ NavigateTo(AddressBar.Text);
+ }
+
+ private void NavigateTo(string? url)
+ {
+ if (string.IsNullOrWhiteSpace(url))
+ return;
+
+ // Add protocol if missing
+ if (!url.StartsWith("http://", StringComparison.OrdinalIgnoreCase) &&
+ !url.StartsWith("https://", StringComparison.OrdinalIgnoreCase))
+ {
+ // If it looks like a URL (contains dot and no spaces), add https
+ // Otherwise treat as a search query
+ url = url.Contains('.') && !url.Contains(' ')
+ ? "https://" + url
+ : "https://www.google.com/search?q=" + Uri.EscapeDataString(url);
+ }
+
+ AddressBar.Text = url;
+ BrowserWebView.Source = new UrlWebViewSource { Url = url };
+ }
+
+ private void OnWebViewNavigating(object? sender, WebNavigatingEventArgs e)
+ {
+ Console.WriteLine("[MainPage] Navigating to: " + e.Url);
+ StatusLabel.Text = $"Loading {e.Url}...";
+
+ // Reset and show progress bar with animation
+ LoadingProgress.AbortAnimation("Progress");
+ LoadingProgress.Progress = 0;
+ LoadingProgress.IsVisible = true;
+
+ // Animate progress from 0 to 90%
+ LoadingProgress.Animate("Progress",
+ new Animation(v => LoadingProgress.Progress = v, 0, 0.9),
+ length: 2000,
+ easing: Easing.CubicOut);
+
+ AddressBar.Text = e.Url;
+ }
+
+ private void OnWebViewNavigated(object? sender, WebNavigatedEventArgs e)
+ {
+ Console.WriteLine($"[MainPage] Navigated: {e.Url} - Result: {e.Result}");
+
+ StatusLabel.Text = e.Result == WebNavigationResult.Success ? "Done" : $"Error: {e.Result}";
+
+ // Complete progress bar
+ LoadingProgress.AbortAnimation("Progress");
+ LoadingProgress.Progress = 1;
+ AddressBar.Text = e.Url;
+
+ // Hide progress bar after a short delay
+ Dispatcher.DispatchDelayed(TimeSpan.FromMilliseconds(300), () =>
+ {
+ LoadingProgress.IsVisible = false;
+ LoadingProgress.Progress = 0;
+ });
+ }
+
+ private void OnThemeToggleClicked(object? sender, EventArgs e)
+ {
+ if (Application.Current is BrowserApp app)
+ {
+ app.ToggleTheme();
+ Console.WriteLine($"[MainPage] Theme changed to: {Application.Current.UserAppTheme}");
+ }
+ }
+}
diff --git a/samples/XamlBrowser/MauiProgram.cs b/samples/XamlBrowser/MauiProgram.cs
new file mode 100644
index 0000000..11a315a
--- /dev/null
+++ b/samples/XamlBrowser/MauiProgram.cs
@@ -0,0 +1,24 @@
+using Microsoft.Maui;
+using Microsoft.Maui.Controls.Hosting;
+using Microsoft.Maui.Hosting;
+using Microsoft.Maui.Platform.Linux.Hosting;
+
+namespace XamlBrowser;
+
+public static class MauiProgram
+{
+ public static MauiApp CreateMauiApp()
+ {
+ var builder = MauiApp.CreateBuilder();
+ builder
+ .UseMauiApp()
+ .UseLinuxPlatform()
+ .ConfigureFonts(fonts =>
+ {
+ fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
+ fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
+ });
+
+ return builder.Build();
+ }
+}
diff --git a/samples/XamlBrowser/Program.cs b/samples/XamlBrowser/Program.cs
new file mode 100644
index 0000000..98dbdf8
--- /dev/null
+++ b/samples/XamlBrowser/Program.cs
@@ -0,0 +1,18 @@
+using Microsoft.Maui.Platform.Linux;
+using Microsoft.Maui.Platform.Linux.Hosting;
+
+namespace XamlBrowser;
+
+public class Program
+{
+ public static void Main(string[] args)
+ {
+ LinuxProgramHost.Run(args, MauiProgram.CreateMauiApp, new LinuxApplicationOptions
+ {
+ Title = "XAML Browser",
+ Width = 1280,
+ Height = 800,
+ UseGtk = true
+ });
+ }
+}
diff --git a/samples/XamlBrowser/Resources/Images/arrow_back_dark.svg b/samples/XamlBrowser/Resources/Images/arrow_back_dark.svg
new file mode 100644
index 0000000..d724d32
--- /dev/null
+++ b/samples/XamlBrowser/Resources/Images/arrow_back_dark.svg
@@ -0,0 +1,3 @@
+
diff --git a/samples/XamlBrowser/Resources/Images/arrow_back_light.svg b/samples/XamlBrowser/Resources/Images/arrow_back_light.svg
new file mode 100644
index 0000000..2297808
--- /dev/null
+++ b/samples/XamlBrowser/Resources/Images/arrow_back_light.svg
@@ -0,0 +1,3 @@
+
diff --git a/samples/XamlBrowser/Resources/Images/arrow_forward_dark.svg b/samples/XamlBrowser/Resources/Images/arrow_forward_dark.svg
new file mode 100644
index 0000000..fc19cb2
--- /dev/null
+++ b/samples/XamlBrowser/Resources/Images/arrow_forward_dark.svg
@@ -0,0 +1,3 @@
+
diff --git a/samples/XamlBrowser/Resources/Images/arrow_forward_light.svg b/samples/XamlBrowser/Resources/Images/arrow_forward_light.svg
new file mode 100644
index 0000000..5c68058
--- /dev/null
+++ b/samples/XamlBrowser/Resources/Images/arrow_forward_light.svg
@@ -0,0 +1,3 @@
+
diff --git a/samples/XamlBrowser/Resources/Images/close_dark.svg b/samples/XamlBrowser/Resources/Images/close_dark.svg
new file mode 100644
index 0000000..e15d8f4
--- /dev/null
+++ b/samples/XamlBrowser/Resources/Images/close_dark.svg
@@ -0,0 +1,3 @@
+
diff --git a/samples/XamlBrowser/Resources/Images/close_light.svg b/samples/XamlBrowser/Resources/Images/close_light.svg
new file mode 100644
index 0000000..a9ea62c
--- /dev/null
+++ b/samples/XamlBrowser/Resources/Images/close_light.svg
@@ -0,0 +1,3 @@
+
diff --git a/samples/XamlBrowser/Resources/Images/dark_mode_dark.svg b/samples/XamlBrowser/Resources/Images/dark_mode_dark.svg
new file mode 100644
index 0000000..f5111ef
--- /dev/null
+++ b/samples/XamlBrowser/Resources/Images/dark_mode_dark.svg
@@ -0,0 +1,3 @@
+
diff --git a/samples/XamlBrowser/Resources/Images/home_dark.svg b/samples/XamlBrowser/Resources/Images/home_dark.svg
new file mode 100644
index 0000000..efe4863
--- /dev/null
+++ b/samples/XamlBrowser/Resources/Images/home_dark.svg
@@ -0,0 +1,3 @@
+
diff --git a/samples/XamlBrowser/Resources/Images/home_light.svg b/samples/XamlBrowser/Resources/Images/home_light.svg
new file mode 100644
index 0000000..e883514
--- /dev/null
+++ b/samples/XamlBrowser/Resources/Images/home_light.svg
@@ -0,0 +1,3 @@
+
diff --git a/samples/XamlBrowser/Resources/Images/light_mode_light.svg b/samples/XamlBrowser/Resources/Images/light_mode_light.svg
new file mode 100644
index 0000000..a43327b
--- /dev/null
+++ b/samples/XamlBrowser/Resources/Images/light_mode_light.svg
@@ -0,0 +1,3 @@
+
diff --git a/samples/XamlBrowser/Resources/Images/refresh_dark.svg b/samples/XamlBrowser/Resources/Images/refresh_dark.svg
new file mode 100644
index 0000000..0d0b161
--- /dev/null
+++ b/samples/XamlBrowser/Resources/Images/refresh_dark.svg
@@ -0,0 +1,3 @@
+
diff --git a/samples/XamlBrowser/Resources/Images/refresh_light.svg b/samples/XamlBrowser/Resources/Images/refresh_light.svg
new file mode 100644
index 0000000..05ef2dd
--- /dev/null
+++ b/samples/XamlBrowser/Resources/Images/refresh_light.svg
@@ -0,0 +1,3 @@
+
diff --git a/samples/XamlBrowser/XamlBrowser.csproj b/samples/XamlBrowser/XamlBrowser.csproj
new file mode 100644
index 0000000..c376203
--- /dev/null
+++ b/samples/XamlBrowser/XamlBrowser.csproj
@@ -0,0 +1,24 @@
+
+
+
+ net9.0
+ Exe
+ XamlBrowser
+ enable
+ enable
+ true
+ XAML Browser
+ com.openmaui.xamlbrowser
+ 1.0
+ 9.0
+
+
+
+
+
+
+
+
+
+
+