Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -217,3 +217,4 @@ llms/

# wwwroot/
smoothui/
*Settings.user
317 changes: 246 additions & 71 deletions AGENTS.md

Large diffs are not rendered by default.

38 changes: 38 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,44 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [1.9.0] - 2026-02-07

### New

- **DaisyClock**: New multi-mode time control with Clock, Timer, and Stopwatch modes; supports segmented/flip/text display styles, labels, 12h/24h formatting, and lap support.
- **DaisyPasswordBox**: New themed password input with reveal toggle, label modes (including floating), helper text, validation states, and icon slots.
- **DaisySlideToConfirm**: New drag-to-confirm interaction control with variant colors, depth styles, auto-reset behavior, and completion events.
- **DaisyIconText**: New reusable icon+text composition control with placement, size, spacing, and variant support.
- **DaisyPatternedCard**: New decorative card with pattern backgrounds and ornaments, backed by new pattern assets and rendering helpers.
- **DaisyProductThemeDropdown**: New dropdown for product-specific palettes with runtime theme registration via `DaisyThemeManager`.
- Added foundational helper utilities for lifecycle wiring, alarms/timers, slide transitions/effects, path/color helpers, and pattern loading/tiling.

### Changed

- **DaisyThemeManager / Theming**: Extended to support runtime theme registration and palette factories, including a large generated product palette catalog.
- **DaisyLoading**: Expanded with business and retro Win95 animation families, increasing overall variant coverage.
- **DaisyStatusIndicator**: Refactored into partial classes and expanded with glyph-driven variants (battery, traffic lights, wifi/cellular signal) plus richer motion/effect styles.
- **DaisyCarousel**: Refactored to internal slide container architecture with improved navigation, slideshow modes, and transition options.
- **DaisyDrawer**: Added responsive/overlay behavior tuning, swipe interactions, and improved `SplitView` sync compatibility.
- **DaisyPagination**: Added generated page ranges (`TotalPages`, `MaxVisiblePages`, centering), optional nav/jump buttons, ellipsis logic, wheel navigation, and press-and-hold repeat.
- **DaisyExpandableCard**: Added batteries-included content mode, configurable animation duration, and improved expansion shaping behavior.
- **DaisyButtonGroup**, **DaisyDivider**, **DaisyIndicator**, **DaisyJoin**, **DaisySteps**, **DaisyTabs**, and **DaisyCountdown** received substantial feature parity, tokenization, and behavior updates.

### Gallery App

- Added and expanded demos across Actions, Cards, Data Display, Data Input, Divider, Feedback, Layout, and Navigation example pages.
- Added gallery coverage for newly ported controls and expanded Status/Loading/interactive scenarios.
- Updated gallery sidebar/category metadata and added refreshed visual assets (including new banner artwork).

### Localization

- Synced and expanded localization keys across all supported languages in both library and gallery resources (`ar`, `de`, `en`, `es`, `fr`, `he`, `it`, `ja`, `ko`, `tr`, `uk`, `zh-CN`).

### Documentation

- Updated theming and localization guides (`THEMING.md`, `LOCALIZATION.md`).
- Updated LLM-facing docs for control behavior/token changes and added new docs for `DaisyClock`.

## [1.8.0] - 2025-12-20

### New
Expand Down
55 changes: 52 additions & 3 deletions Flowery.NET.Gallery.Desktop/Program.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
using System;
using System.Diagnostics;
using System.IO;
using System.Threading.Tasks;
using Avalonia;


namespace Flowery.NET.Gallery.Desktop;

sealed class Program
Expand All @@ -10,8 +12,21 @@ sealed class Program
// SynchronizationContext-reliant code before AppMain is called: things aren't initialized
// yet and stuff might break.
[STAThread]
public static void Main(string[] args) => BuildAvaloniaApp()
.StartWithClassicDesktopLifetime(args);
public static void Main(string[] args)
{
// Configure crash logging before Avalonia starts
ConfigureCrashLogging();

try
{
BuildAvaloniaApp().StartWithClassicDesktopLifetime(args);
}
catch (Exception ex)
{
LogFatal("Main.Unhandled", ex);
throw;
}
}

// Avalonia configuration, don't remove; also used by visual designer.
public static AppBuilder BuildAvaloniaApp()
Expand All @@ -20,4 +35,38 @@ public static AppBuilder BuildAvaloniaApp()
.WithInterFont()
.WithNotoFonts()
.LogToTrace();

private static void ConfigureCrashLogging()
{
AppDomain.CurrentDomain.UnhandledException += (_, e) =>
{
LogFatal("AppDomain.UnhandledException", e.ExceptionObject as Exception);
};

TaskScheduler.UnobservedTaskException += (_, e) =>
{
LogFatal("TaskScheduler.UnobservedTaskException", e.Exception);
e.SetObserved();
};
}

internal static void LogFatal(string source, Exception? ex)
{
var message = $"[{DateTimeOffset.Now:O}] {source}: {ex}\n";
Debug.WriteLine(message);
Console.Error.WriteLine(message);

try
{
var dir = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Flowery.NET.Gallery");
Directory.CreateDirectory(dir);
var logPath = Path.Combine(dir, "crash.log");
File.AppendAllText(logPath, message);
Debug.WriteLine($"Crash log written to: {logPath}");
}
catch
{
// Ignore file IO failures; Debug output is still useful.
}
}
}
26 changes: 26 additions & 0 deletions Flowery.NET.Gallery/App.axaml.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
using System;
using System.Diagnostics;
using System.IO;
using Avalonia;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Markup.Xaml;
Expand All @@ -19,6 +22,29 @@ public override void Initialize()
_ = GalleryLocalization.Instance;
}

/// <summary>
/// Logs a fatal exception to Debug output and a crash.log file.
/// </summary>
internal static void LogFatal(string source, Exception? ex)
{
var message = $"[{DateTimeOffset.Now:O}] {source}: {ex}\n";
Debug.WriteLine(message);
Console.Error.WriteLine(message);

try
{
var dir = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Flowery.NET.Gallery");
Directory.CreateDirectory(dir);
var logPath = Path.Combine(dir, "crash.log");
File.AppendAllText(logPath, message);
Debug.WriteLine($"Crash log written to: {logPath}");
}
catch
{
// Ignore file IO failures; Debug output is still useful.
}
}

public override void OnFrameworkInitializationCompleted()
{
// Restore saved app language (if any)
Expand Down
Binary file added Flowery.NET.Gallery/Assets/flowery-banner.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
65 changes: 60 additions & 5 deletions Flowery.NET.Gallery/Examples/ActionsExamples.axaml
Original file line number Diff line number Diff line change
Expand Up @@ -385,7 +385,8 @@
MinHeight="120">
<StackPanel Spacing="12" HorizontalAlignment="Center" VerticalAlignment="Center">
<TextBlock Text="Outline style" FontWeight="SemiBold" FontSize="14" Opacity="0.8"/>
<controls:DaisyButtonGroup ButtonStyle="Outline" Variant="Secondary" ShowShadow="True">
<controls:DaisyButtonGroup ButtonStyle="Outline"
Variant="Secondary" AutoSelect="True" ShowShadow="True">
<Button ToolTip.Tip="Left">
<TextBlock Text="Left" />
</Button>
Expand All @@ -399,6 +400,35 @@
</StackPanel>
</Border>

<!-- 10: Multi-select formatting -->
<Border Width="320"
MaxWidth="{Binding (services:FloweryResponsive.ResponsiveMaxWidth), ElementName=ButtonGroupResponsiveHost}"
Margin="12,0,12,24"
BorderBrush="{DynamicResource DaisyBase300Brush}"
BorderThickness="1"
CornerRadius="12"
Padding="16"
MinHeight="120">
<StackPanel Spacing="12" HorizontalAlignment="Center"
VerticalAlignment="Center">
<TextBlock Text="Multi-select (formatting)"
FontWeight="SemiBold" FontSize="14" Opacity="0.8" />
<controls:DaisyButtonGroup AutoSelect="True"
SelectionMode="Multiple" ShowShadow="True">
<Button Padding="0" Width="40" ToolTip.Tip="Bold">
<TextBlock Text="B" FontWeight="Bold" FontSize="16" />
</Button>
<Button Padding="0" Width="40" ToolTip.Tip="Italic">
<TextBlock Text="I" FontStyle="Italic" FontSize="16" />
</Button>
<Button Padding="0" Width="40" ToolTip.Tip="Underline">
<TextBlock Text="U" TextDecorations="Underline"
FontSize="16" />
</Button>
</controls:DaisyButtonGroup>
</StackPanel>
</Border>

<!-- Primary action + dropdown -->
<Border Width="320"
MaxWidth="{Binding (services:FloweryResponsive.ResponsiveMaxWidth), ElementName=ButtonGroupResponsiveHost}"
Expand Down Expand Up @@ -617,7 +647,8 @@
<local:SectionHeader SectionId="fab" Title="FAB / Speed Dial" />
<TextBlock Text="Click the FAB buttons below to expand" Opacity="0.7" controls:FlowerySizeManager.ResponsiveFont="Primary" />
<WrapPanel Orientation="Horizontal">
<Border Background="{DynamicResource DaisyBase200Brush}" CornerRadius="8" Padding="8" Margin="0,0,8,8" Width="85" Height="220">
<Border Background="{DynamicResource DaisyBase200Brush}" CornerRadius="8"
Padding="12" Margin="0,0,8,8" Width="100" Height="220">
<Grid>
<TextBlock Text="Vertical" Opacity="0.6" VerticalAlignment="Top" controls:FlowerySizeManager.ResponsiveFont="Secondary" />
<controls:DaisyFab TriggerContent="+" TriggerVariant="Primary" Size="Medium">
Expand All @@ -628,7 +659,25 @@
</Grid>
</Border>

<Border Background="{DynamicResource DaisyBase200Brush}" CornerRadius="8" Padding="8" Margin="0,0,8,8" Width="85" Height="220">
<Border Background="{DynamicResource DaisyBase200Brush}" CornerRadius="8"
Padding="8" Margin="0,0,8,8" Width="240" Height="85">
<Grid>
<TextBlock Text="Horizontal" Opacity="0.6" VerticalAlignment="Top"
controls:FlowerySizeManager.ResponsiveFont="Secondary" />
<controls:DaisyFab Layout="Horizontal" TriggerContent="+"
TriggerVariant="Accent" Size="Medium">
<controls:DaisyButton Shape="Circle" Size="Medium" Content="1"
Click="OnFabItemClick" Tag="Horizontal 1" />
<controls:DaisyButton Shape="Circle" Size="Medium" Content="2"
Click="OnFabItemClick" Tag="Horizontal 2" />
<controls:DaisyButton Shape="Circle" Size="Medium" Content="3"
Click="OnFabItemClick" Tag="Horizontal 3" />
</controls:DaisyFab>
</Grid>
</Border>

<Border Background="{DynamicResource DaisyBase200Brush}" CornerRadius="8"
Padding="12" Margin="0,0,8,8" Width="100" Height="220">
<Grid>
<TextBlock Text="Icons" Opacity="0.6" VerticalAlignment="Top" controls:FlowerySizeManager.ResponsiveFont="Secondary" />
<controls:DaisyFab TriggerVariant="Secondary" Size="Medium">
Expand All @@ -648,22 +697,28 @@
</Grid>
</Border>

<Border Background="{DynamicResource DaisyBase200Brush}" CornerRadius="8" Padding="8" Margin="0,0,8,8" Width="85" Height="220">
<Border Background="{DynamicResource DaisyBase200Brush}" CornerRadius="8"
Padding="8" Margin="0,0,8,8" Width="180" Height="220">
<Grid>
<TextBlock Text="Flower" Opacity="0.6" VerticalAlignment="Top" controls:FlowerySizeManager.ResponsiveFont="Secondary" />
<controls:DaisyFab TriggerContent="F" TriggerVariant="Success" Layout="Flower" Size="Medium">
<controls:DaisyButton Shape="Circle" Size="Medium" Content="A" Click="OnFabItemClick" Tag="Flower A"/>
<controls:DaisyButton Shape="Circle" Size="Medium" Content="B" Click="OnFabItemClick" Tag="Flower B"/>
<controls:DaisyButton Shape="Circle" Size="Medium" Content="C"
Click="OnFabItemClick" Tag="Flower C" />
</controls:DaisyFab>
</Grid>
</Border>

<Border Background="{DynamicResource DaisyBase200Brush}" CornerRadius="8" Padding="8" Margin="0,0,8,8" Width="85" Height="220">
<Border Background="{DynamicResource DaisyBase200Brush}" CornerRadius="8"
Padding="12" Margin="0,0,8,8" Width="100" Height="220">
<Grid>
<TextBlock Text="Variants" Opacity="0.6" VerticalAlignment="Top" controls:FlowerySizeManager.ResponsiveFont="Secondary" />
<controls:DaisyFab TriggerContent="★" TriggerVariant="Warning" Size="Medium">
<controls:DaisyButton Shape="Circle" Size="Medium" Content="1" Variant="Info" Click="OnFabItemClick" Tag="Variant 1"/>
<controls:DaisyButton Shape="Circle" Size="Medium" Content="2" Variant="Success" Click="OnFabItemClick" Tag="Variant 2"/>
<controls:DaisyButton Shape="Circle" Size="Medium" Content="3"
Variant="Error" Click="OnFabItemClick" Tag="Variant 3" />
</controls:DaisyFab>
</Grid>
</Border>
Expand Down
Loading