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
20 changes: 19 additions & 1 deletion src/NoteBookmark.Api.Tests/Domain/SettingsTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,8 @@ public void Settings_WithFullData_PreservesAllValues()
SearchPrompt = "Find {topic}",
AiApiKey = "test-key",
AiBaseUrl = "https://api.openai.com",
AiModelName = "gpt-4"
AiModelName = "gpt-4",
FontSize = "large"
};

// Assert
Expand All @@ -207,5 +208,22 @@ public void Settings_WithFullData_PreservesAllValues()
settings.AiApiKey.Should().Be("test-key");
settings.AiBaseUrl.Should().Be("https://api.openai.com");
settings.AiModelName.Should().Be("gpt-4");
settings.FontSize.Should().Be("large");
}

[Theory]
[InlineData("small")]
[InlineData("medium")]
[InlineData("large")]
public void FontSize_CanBeSetAndRetrieved(string fontSize)
{
var settings = new Settings
{
PartitionKey = "setting",
RowKey = "setting",
FontSize = fontSize
};

settings.FontSize.Should().Be(fontSize);
}
}
3 changes: 3 additions & 0 deletions src/NoteBookmark.Domain/Settings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ public class Settings: ITableEntity

[DataMember(Name="ai_model_name")]
public string? AiModelName { get; set; }

[DataMember(Name="font_size")]
public string? FontSize { get; set; }

public required string PartitionKey { get ; set; }
public required string RowKey { get ; set; }
Expand Down
25 changes: 25 additions & 0 deletions src/NoteBookmark.MauiApp.Tests/FontSizeHelperTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using FluentAssertions;
using NoteBookmark.SharedUI;
using Xunit;

namespace NoteBookmark.MauiApp.Tests;

public class FontSizeHelperTests
{
[Theory]
[InlineData("small", "0.875rem")]
[InlineData("SMALL", "0.875rem")]
[InlineData("medium", "1rem")]
[InlineData("MEDIUM", "1rem")]
[InlineData("large", "1.25rem")]
[InlineData("LARGE", "1.25rem")]
[InlineData("18px", "18px")]
[InlineData(null, "1rem")]
[InlineData("", "1rem")]
[InlineData(" ", "1rem")]
public void ToCssValue_MapsFontSizeCorrectly(string? input, string expectedCssValue)
{
var result = FontSizeHelper.ToCssValue(input);
result.Should().Be(expectedCssValue);
}
}
17 changes: 17 additions & 0 deletions src/NoteBookmark.MauiApp.Tests/LocalDataServiceTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -144,4 +144,21 @@ public async Task DeletePost_ShouldSoftDeleteAndFlagPendingSync()
var pending = await _sut.GetPendingSyncPostsAsync();
pending.Should().ContainSingle(p => p.Id == "post1", "because it needs to sync the deletion");
}

[Fact]
public async Task SaveSettings_ShouldStoreAndRetrieveFontSize()
{
var settings = new Settings
{
PartitionKey = "setting",
RowKey = "setting",
FontSize = "large"
};

await _sut.SaveSettingsAsync(settings);

var retrieved = await _sut.GetSettingsAsync();
retrieved.Should().NotBeNull();
retrieved!.FontSize.Should().Be("large");
}
}
21 changes: 21 additions & 0 deletions src/NoteBookmark.MauiApp/Components/Layout/MainLayout.razor
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,13 @@
@using Microsoft.Maui.ApplicationModel
@using Microsoft.FluentUI.AspNetCore.Components
@using NoteBookmark.MauiApp.Data
@using NoteBookmark.SharedUI
@inject IConnectivity Connectivity
@inject NavigationManager Navigation
@inject ISyncService SyncService
@inject IToastService ToastService
@inject IDataService DataService
@inject IJSRuntime JSRuntime
@implements IDisposable


Expand Down Expand Up @@ -69,6 +72,24 @@
}
}

protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
try
{
var settings = await DataService.GetSettings();
var cssSize = FontSizeHelper.ToCssValue(settings?.FontSize);
await JSRuntime.InvokeVoidAsync("document.documentElement.style.setProperty", "--app-font-size", cssSize);
await JSRuntime.InvokeVoidAsync("document.body.style.setProperty", "--app-font-size", cssSize);
}
catch
{
// Fallback for headless environments or prerendering
}
}
}

private void OnSyncConflictDetected(object? sender, SyncConflictEventArgs e)
{
InvokeAsync(() =>
Expand Down
5 changes: 4 additions & 1 deletion src/NoteBookmark.MauiApp/Data/LocalModels.cs
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,7 @@ public class LocalSettings
public string? AiApiKey { get; set; }
public string? AiBaseUrl { get; set; }
public string? AiModelName { get; set; }
public string? FontSize { get; set; }
public bool IsPendingSync { get; set; }

public Settings ToDomain() => new Settings
Expand All @@ -193,7 +194,8 @@ public class LocalSettings
SearchPrompt = SearchPrompt,
AiApiKey = AiApiKey,
AiBaseUrl = AiBaseUrl,
AiModelName = AiModelName
AiModelName = AiModelName,
FontSize = FontSize
};

public static LocalSettings FromDomain(Settings s, bool isPendingSync = false) => new LocalSettings
Expand All @@ -209,6 +211,7 @@ public class LocalSettings
AiApiKey = s.AiApiKey,
AiBaseUrl = s.AiBaseUrl,
AiModelName = s.AiModelName,
FontSize = s.FontSize,
IsPendingSync = isPendingSync
};
}
6 changes: 6 additions & 0 deletions src/NoteBookmark.MauiApp/wwwroot/app.css
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
:root {
--app-font-size: 1rem;
}

html, body {
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
font-size: var(--app-font-size, 1rem);
--type-ramp-base-font-size: var(--app-font-size, 1rem);
}

a, .btn-link {
Expand Down
32 changes: 32 additions & 0 deletions src/NoteBookmark.SharedUI/Components/Pages/Settings.razor
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
@using NoteBookmark.Domain
@inject IDataService client
@inject NavigationManager Navigation
@inject IJSRuntime JSRuntime

<FluentDesignTheme @bind-Mode="@Mode"
@bind-OfficeColor="@OfficeColor"
Expand Down Expand Up @@ -46,6 +47,14 @@
<ValidationSummary />
<FluentStack Orientation="Orientation.Vertical" Width="100%">

<FluentStack Orientation="Orientation.Horizontal" Width="100%">
<FluentSelect Label="Font Size" Width="150px"
Items="@fontSizeOptions"
OptionText="@(i => i.Text)"
OptionValue="@(i => i.Value)"
@bind-Value="settings!.FontSize" />
</FluentStack>

<FluentStack Orientation="Orientation.Horizontal" Width="100%" VerticalAlignment="VerticalAlignment.Center">
<FluentTextField Label="Last Bookmark Date" @bind-Value="settings!.LastBookmarkDate" />
</FluentStack>
Expand Down Expand Up @@ -103,16 +112,39 @@

private Domain.Settings? settings;

private record FontSizeOption(string Text, string Value);

private static readonly List<FontSizeOption> fontSizeOptions = new()
{
new("Small", "small"),
new("Medium", "medium"),
new("Large", "large")
};

protected override async Task OnInitializedAsync()
{
settings = await client.GetSettings();
if (settings != null && string.IsNullOrWhiteSpace(settings.FontSize))
{
settings.FontSize = FontSizeHelper.DefaultFontSize;
}
}

private async Task SaveSettings()
{
if (settings != null)
{
await client.SaveSettings(settings);
try
{
var cssSize = FontSizeHelper.ToCssValue(settings.FontSize);
await JSRuntime.InvokeVoidAsync("document.documentElement.style.setProperty", "--app-font-size", cssSize);
await JSRuntime.InvokeVoidAsync("document.body.style.setProperty", "--app-font-size", cssSize);
}
catch
{
// Prerender / non-JS environment safe
}
Navigation.NavigateTo("/");
}
}
Expand Down
15 changes: 15 additions & 0 deletions src/NoteBookmark.SharedUI/FontSizeHelper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
namespace NoteBookmark.SharedUI;

public static class FontSizeHelper
{
public const string DefaultFontSize = "medium";

public static string ToCssValue(string? fontSize) => fontSize?.ToLowerInvariant() switch
{
"small" => "0.875rem",
"large" => "1.25rem",
"medium" => "1rem",
_ when !string.IsNullOrWhiteSpace(fontSize) => fontSize,
_ => "1rem"
};
}
Loading