Antoine CAVELIER antoine
  • Joined on 2020-01-02

Harmony.Mobile.UI (0.2.5)

Published 2026-04-17 13:49:06 +00:00 by antoine

Installation

dotnet nuget add source --name antoine --username your_username --password your_token https://git.luxit.be/api/packages/antoine/nuget/index.json
dotnet add package --source antoine --version 0.2.5 Harmony.Mobile.UI

About this package

Harmony mobile UI library — iOS-styled Blazor components, shell (header, tab bar, page transitions, sheets), services (haptics, navigation stack, sheet host) and Tailwind theme preset. Designed to be consumed by Blazor WebAssembly mobile apps (PWA or MAUI Hybrid).

Harmony.Mobile.UI

iOS-styled Blazor component library for Harmony mobile apps (Blazor WebAssembly PWA or MAUI Hybrid). Provides primitives (Avatar, Card, Icon, List, Sheet, Toggle, …), a complete mobile app-shell (sticky header, bottom tab bar with editor, page transitions, bottom-sheet host), UI services (haptics, navigation stack, sheet host, header state) and a Tailwind 4 theme preset with iOS design tokens.

This package is the first consumable piece of the Harmony platform — it is designed to be reused across all Harmony mobile projects (current and future).

Installation

<PackageReference Include="Harmony.Mobile.UI" Version="0.1.0" />

Configure the Gitea NuGet source in nuget.config at the solution root:

<configuration>
  <packageSources>
    <add key="gitea-luxit" value="https://git.luxit.be/api/packages/antoine/nuget/index.json" />
  </packageSources>
  <packageSourceCredentials>
    <gitea-luxit>
      <add key="Username" value="%GITEA_USER%" />
      <add key="ClearTextPassword" value="%GITEA_TOKEN%" />
    </gitea-luxit>
  </packageSourceCredentials>
</configuration>

Generate a Gitea access token at https://git.luxit.be/user/settings/applications with scopes read:package + write:package, then export GITEA_USER=<your-gitea-login> and GITEA_TOKEN=<token> in your shell.

Wire-up (Blazor WebAssembly)

1. DI

using Harmony.Mobile.UI.Services;

builder.Services.AddHarmonyMobileUI(nav =>
{
    nav.RootTabs      = new() { "/", "/search", "/profile" };
    nav.ModalPrefixes = new() { "/feed/", "/messages/" };
    nav.Labels        = new()
    {
        ["/"]        = "Home",
        ["/search"]  = "Search",
        ["/profile"] = "Profile",
    };
    nav.FallbackLabel = "Back";
});

To integrate with your own "enable haptics" user setting, register an IHapticsPreferences implementation:

builder.Services.AddScoped<IHapticsPreferences, MyHapticsPrefs>();

2. index.html

<link rel="stylesheet" href="css/app.generated.css" />
<script src="_content/Harmony.Mobile.UI/js/interop.js"></script>
<script src="_content/Harmony.Mobile.UI/js/sortable.js"></script>

3. Styles

The package ships a pre-compiled CSS bundle (_content/Harmony.Mobile.UI/css/harmony-mobile-ui.css) that contains Tailwind base + the theme + all components + every utility class used inside the library's components. Always include it:

<link rel="stylesheet" href="_content/Harmony.Mobile.UI/css/harmony-mobile-ui.css" />

If your app needs its own Tailwind build (for utilities in your own markup), compile your own app.css and import the theme preset:

@import "tailwindcss";
@import "../../_content/Harmony.Mobile.UI/styles-src/theme.css";
@import "../../_content/Harmony.Mobile.UI/styles-src/components.css";
@source "./**/*.razor";
@source "./**/*.cs";

And keep the pre-compiled bundle linked too — it's the guaranteed way to ship the utility classes the library's components rely on.

5. App shell

@* App.razor *@
<Router AppAssembly="@typeof(App).Assembly">
    <Found Context="routeData">
        <RouteView RouteData="@routeData" DefaultLayout="@typeof(Shell.AppLayout)" />
    </Found>
</Router>
@* Shell/AppLayout.razor *@
@inherits LayoutComponentBase
<HmMainLayout>
    <TabBarContent>
        <HmTabBar Tabs="HarmonyTabs.All"
                  TabOrder="@Settings.Current.TabOrder"
                  PrimaryCount="4"
                  HiddenRoutePrefixes="@(new[] { "/messages/" })"
                  MoreLabel="More" EditLabel="Edit" DoneLabel="Done" ResetLabel="Reset"
                  OnTabOrderChanged="OnTabOrderChanged" />
    </TabBarContent>
    @Body
</HmMainLayout>

6. Page template

@page "/"
@inherits Harmony.Mobile.UI.Abstractions.PageBase

<HmNavHeader Title="Home" ScrollId="home-scroll" />

<div id="home-scroll" class="page-scroll" data-scroll-memory="home">
    <HmCard Title="Hello" Subtitle="From Harmony" Icon="sparkles" Color="#5AC8FA" />
</div>

Components

Component Purpose
HmAvatar Avatar with initials fallback + optional online badge.
HmCard Article/content card with gradient media.
HmIcon Inline Lucide icon (curated subset).
HmListGroup iOS inset-grouped list container.
HmListRow List row with icon, label, description, value, chevron/check.
HmPullToRefresh Pull-to-refresh indicator (JS-driven).
HmSheet Bottom sheet modal with swipe-to-dismiss.
HmSheetHost Single global sheet host, driven by SheetService.
HmStat Small tile showing an icon + value + label.
HmToggle iOS-style switch.
HmMainLayout App shell (header + page stack + tab bar + sheet host).
HmHeaderRenderer Sticky nav header (title, back button, trailing slot).
HmNavHeader Headless page-level header declaration.
HmPageTransition Animated page switcher (slide, zoom, fade).
HmTabBar Bottom tab bar with overflow "More" sheet + edit mode.
HmTabBarEditor Sortable tab list editor.

Publishing a new version

Full release — use the script:

export GITEA_TOKEN=<your-gitea-access-token>
./scripts/release.sh 0.1.1

scripts/release.sh bumps <Version> in Directory.Build.props, rebuilds the CSS bundle, packs, pushes the .nupkg + .snupkg to the Gitea NuGet registry, commits the bump, tags v0.1.1, and pushes git + tags. It bails early if the working tree is dirty, the token is missing, or the version already has an artifact.

Dev-time pack (no push)

When iterating together on the RCL and Harmony-Stack without wanting to publish every step, pack locally and let Harmony-Stack consume the artifact via the harmony-local NuGet source it already has configured:

./scripts/pack-local.sh                # uses current Directory.Build.props version
./scripts/pack-local.sh 0.1.1-dev1     # or override with a pre-release suffix

Then in Harmony-Stack:

./scripts/update-ui.sh 0.1.1-dev1

Compatibility

  • .NET 9.0+
  • Blazor WebAssembly (tested)
  • Blazor Server — not tested yet
  • MAUI Hybrid — not tested yet

License

MIT © Mixvoip

Details
NuGet
2026-04-17 13:49:06 +00:00
20
Antoine Cavelier
200 KiB
Assets (4)
Versions (95) View all
0.5.3 2026-04-29
0.5.2 2026-04-28
0.5.1 2026-04-28
0.5.0 2026-04-28
0.4.4 2026-04-28