Theme setting updates

This commit is contained in:
Dennis Reimann 2023-08-29 13:54:31 +02:00
parent c1715aecc6
commit 77f5bb227e
No known key found for this signature in database
GPG Key ID: 5009E1797F03F8D0
9 changed files with 73 additions and 67 deletions

View File

@ -12,6 +12,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<script src="~/_framework/blazor.server.js" asp-append-version="true"></script>
<script src="~/_content/MudBlazor/MudBlazor.min.js" asp-append-version="true"></script>
<script src="./_content/BTCPayApp.UI/js/site.js" asp-append-version="true"></script>
<link href="~/_content/MudBlazor/MudBlazor.min.css" rel="stylesheet" asp-append-version="true"/>
<link href="./_content/BTCPayApp.UI/css/mudblazor-overrides.css" rel="stylesheet" asp-append-version="true"/>
<link href="./_content/BTCPayApp.UI/css/theme.css" rel="stylesheet" asp-append-version="true"/>

View File

@ -1,4 +1,5 @@
using Fluxor;
using Microsoft.JSInterop;
namespace BTCPayApp.UI.Features;
@ -9,11 +10,12 @@ public class UIState
private string SystemTheme { get; init; } = Constants.LightTheme;
public bool IsDarkMode { get; set; }
public record ApplySystemPreference(string Theme);
public record ApplyTheme(string Theme);
public record ApplyUserTheme(string Theme);
public record SetSystemPreference(string Theme);
public record SetUserTheme(string Theme);
[ReducerMethod]
public static UIState Reduce(UIState state, ApplySystemPreference action)
public static UIState Reduce(UIState state, SetSystemPreference action)
{
var effectiveTheme = state.SelectedTheme == Constants.SystemTheme ? action.Theme : state.SelectedTheme;
return new UIState
@ -25,7 +27,7 @@ public class UIState
}
[ReducerMethod]
public static UIState Reduce(UIState state, ApplyTheme action)
public static UIState Reduce(UIState state, SetUserTheme action)
{
var effectiveTheme = action.Theme == Constants.SystemTheme ? state.SystemTheme : action.Theme;
return new UIState
@ -35,4 +37,23 @@ public class UIState
IsDarkMode = effectiveTheme == Constants.DarkTheme
};
}
public class UIEffects
{
private readonly IJSRuntime _jsRuntime;
public UIEffects(IJSRuntime jsRuntime)
{
_jsRuntime = jsRuntime;
}
[EffectMethod]
public async Task ApplyUserThemeEffect(ApplyUserTheme action, IDispatcher dispatcher)
{
// store
dispatcher.Dispatch(new SetUserTheme(action.Theme));
// ui
await _jsRuntime.InvokeVoidAsync("setTheme", action.Theme);
}
}
}

View File

@ -8,13 +8,5 @@
<MudText Typo="Typo.h5" Class="mb-8">Settings</MudText>
<Settings Theme="@UiState.Value.SelectedTheme" OnThemeChange="SetTheme" />
@code {
private Task SetTheme(string theme)
{
Dispatcher.Dispatch(new UIState.ApplyTheme(theme));
return Task.CompletedTask;
}
}
<Settings Theme="@UiState.Value.SelectedTheme" OnThemeChange="theme => Dispatcher.Dispatch(new UIState.ApplyUserTheme(theme))" />

View File

@ -17,8 +17,10 @@
<MudLayout>
<MudAppBar Elevation="1">
<MudIconButton Icon="@BTCPayIcons.Menu" Color="Color.Inherit" Edge="Edge.Start" OnClick="@DrawerToggle"/>
<MudImage Src="_content/BTCPayApp.UI/img/logo.svg" Height="24" Alt="BTCPay Server" Class="ml-3" />
<MudText Typo="Typo.h6" Class="ml-3">BTCPay Server</MudText>
<MudLink Href="@Routes.Home" Underline="Underline.None" Color="Color.Inherit" Class="d-flex align-center ml-2">
<MudImage Src="_content/BTCPayApp.UI/img/logo.svg" Height="24" Alt="BTCPay Server" />
<MudText Typo="Typo.h6" Class="ml-3">BTCPay Server</MudText>
</MudLink>
</MudAppBar>
<MudDrawer @bind-Open="_isDrawerOpen" ClipMode="DrawerClipMode.Always" Class="py-5">
<MudNavMenu Color="Color.Success" Bordered="true">
@ -29,7 +31,7 @@
</MudNavMenu>
</MudDrawer>
<MudMainContent>
<MudProgressLinear Color="Color.Primary" Indeterminate="true" Size="Size.Small" Class="@(LoadingStateSelection.Value.Count > 0 ? null : "invisible")"/>
<MudProgressLinear Color="Color.Primary" Indeterminate="true" Size="Size.Small" Class="@(LoadingStateSelection.Value.Any() ? null : "invisible")"/>
<MudContainer Fixed="true" Class="py-5">
@Body
</MudContainer>
@ -52,16 +54,19 @@
{
LoadingStateSelection.Select(state => state.Loading);
DarkModeStateSelection.Select(state => state.IsDarkMode);
if (_darkMode is null && !Store.Initialized.IsCompleted)
var state = await ConfigProvider.Get<UIState>(StateMiddleware.UiStateConfigKey);
if (state != null)
{
var state = await ConfigProvider.Get<UIState>(StateMiddleware.UiStateConfigKey);
if (state != null)
if (_darkMode is null && !Store.Initialized.IsCompleted)
{
_darkMode = state.IsDarkMode;
_ = Store.Initialized.ContinueWith(task => _darkMode = null);
_ = Store.Initialized.ContinueWith(_ => _darkMode = null);
}
if (!string.IsNullOrEmpty(state.SelectedTheme))
{
Dispatcher.Dispatch(new UIState.ApplyUserTheme(state.SelectedTheme));
}
}
await base.OnInitializedAsync();
}
@ -79,6 +84,6 @@
private void ApplySystemPreference(object? sender, bool isDarkMode)
{
var systemTheme = isDarkMode ? Constants.DarkTheme : Constants.LightTheme;
Dispatcher.Dispatch(new UIState.ApplySystemPreference(systemTheme));
Dispatcher.Dispatch(new UIState.SetSystemPreference(systemTheme));
}
}

View File

@ -3,6 +3,7 @@
@inherits Fluxor.Blazor.Web.Components.FluxorLayout
@inject IStateSelection<RootState, HashSet<RootState.LoadingHandles>> LoadingStateSelection
@inject IStateSelection<UIState, bool> DarkModeStateSelection
@inject IDispatcher Dispatcher
@inject IConfigProvider ConfigProvider
@inject ISystemThemeProvider SystemThemeProvider
@inject IStore Store
@ -13,7 +14,7 @@
<MudSnackbarProvider/>
<MudLayout>
<MudProgressLinear Color="Color.Primary" Indeterminate="true" Size="Size.Small" Class="@(LoadingStateSelection.Value.Count > 0 ? null : "invisible")"/>
<MudProgressLinear Color="Color.Primary" Indeterminate="true" Size="Size.Small" Class="@(LoadingStateSelection.Value.Any() ? null : "invisible")"/>
<MudMainContent>
@Body
</MudMainContent>
@ -28,26 +29,36 @@
{
LoadingStateSelection.Select(state => state.Loading);
DarkModeStateSelection.Select(state => state.IsDarkMode);
if (_darkMode is null && !Store.Initialized.IsCompleted)
var state = await ConfigProvider.Get<UIState>(StateMiddleware.UiStateConfigKey);
if (state != null)
{
var state = await ConfigProvider.Get<UIState>(StateMiddleware.UiStateConfigKey);
if (state != null)
if (_darkMode is null && !Store.Initialized.IsCompleted)
{
_darkMode = state.IsDarkMode;
_ = Store.Initialized.ContinueWith(_ => _darkMode = null);
}
if (!string.IsNullOrEmpty(state.SelectedTheme))
{
Dispatcher.Dispatch(new UIState.ApplyUserTheme(state.SelectedTheme));
}
}
await base.OnInitializedAsync();
}
protected override Task OnAfterRenderAsync(bool firstRender)
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
if (SystemThemeProvider is MudBlazorThemeProvider mudThemeProvider)
mudThemeProvider.MudThemeProvider = _mudThemeProvider;
ApplySystemPreference(this, await _mudThemeProvider.GetSystemPreference());
SystemThemeProvider.SystemThemeChanged += ApplySystemPreference;
}
return Task.CompletedTask;
}
private void ApplySystemPreference(object? sender, bool isDarkMode)
{
var theme = isDarkMode ? Constants.DarkTheme : Constants.LightTheme;
Dispatcher.Dispatch(new UIState.SetSystemPreference(theme));
}
}

View File

@ -1,7 +1,6 @@
:root {
}
.mud-icon-button,
.mud-button-text {
--btcpay-btn-disabled-opacity: 0.65;
@ -12,16 +11,13 @@
padding: var(--btcpay-btn-padding-y) var(--btcpay-btn-padding-x) !important;
}
.mud-icon-button:hover,
.mud-button-text:hover,
.mud-icon-button:focus-visible,
.mud-button-text:focus-visible {
color: var(--btcpay-btn-hover-color) !important;
background-color: var(--btcpay-btn-hover-bg) !important;
border-color: var(--btcpay-btn-hover-border-color) !important;
}
.mud-icon-button:disabled,
.mud-button-text:disabled {
color: var(--btcpay-btn-disabled-color) !important;
background-color: var(--btcpay-btn-disabled-bg) !important;
@ -45,7 +41,7 @@
--btcpay-btn-disabled-bg: var(--btcpay-primary);
--btcpay-btn-disabled-border-color: var(--btcpay-primary-border);
}
.mud-icon-button.mud-button-outlined,
.mud-button-text-default,
.mud-button-text-secondary,
.mud-button-filled-secondary {
@ -64,7 +60,6 @@
--btcpay-btn-disabled-border-color: var(--btcpay-secondary-border);
}
.mud-icon-button-size-large,
.mud-button-text-size-large {
--btcpay-btn-padding-y: 1rem;
--btcpay-btn-padding-x: 2rem;
@ -72,7 +67,6 @@
--btcpay-btn-border-radius: var(--btcpay-border-radius-l);
}
.mud-icon-button-size-medium,
.mud-button-text-size-medium {
--btcpay-btn-padding-x: 1.5rem;
--btcpay-btn-padding-y: 0.5rem;
@ -80,7 +74,6 @@
--btcpay-btn-border-radius: var(--btcpay-border-radius);
}
.mud-icon-button-size-small,
.mud-button-text-size-small {
--btcpay-btn-padding-y: 0.5rem;
--btcpay-btn-padding-x: 1.5rem;

View File

@ -1,33 +1,4 @@
#blazor-error-ui {
background: lightyellow;
bottom: 0;
box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2);
display: none;
left: 0;
padding: 0.6rem 1.25rem 0.7rem 1.25rem;
position: fixed;
width: 100%;
z-index: 1000;
}
#blazor-error-ui .dismiss {
cursor: pointer;
position: absolute;
right: 0.75rem;
top: 0.5rem;
}
.blazor-error-boundary {
background: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTYiIGhlaWdodD0iNDkiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIG92ZXJmbG93PSJoaWRkZW4iPjxkZWZzPjxjbGlwUGF0aCBpZD0iY2xpcDAiPjxyZWN0IHg9IjIzNSIgeT0iNTEiIHdpZHRoPSI1NiIgaGVpZ2h0PSI0OSIvPjwvY2xpcFBhdGg+PC9kZWZzPjxnIGNsaXAtcGF0aD0idXJsKCNjbGlwMCkiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yMzUgLTUxKSI+PHBhdGggZD0iTTI2My41MDYgNTFDMjY0LjcxNyA1MSAyNjUuODEzIDUxLjQ4MzcgMjY2LjYwNiA1Mi4yNjU4TDI2Ny4wNTIgNTIuNzk4NyAyNjcuNTM5IDUzLjYyODMgMjkwLjE4NSA5Mi4xODMxIDI5MC41NDUgOTIuNzk1IDI5MC42NTYgOTIuOTk2QzI5MC44NzcgOTMuNTEzIDI5MSA5NC4wODE1IDI5MSA5NC42NzgyIDI5MSA5Ny4wNjUxIDI4OS4wMzggOTkgMjg2LjYxNyA5OUwyNDAuMzgzIDk5QzIzNy45NjMgOTkgMjM2IDk3LjA2NTEgMjM2IDk0LjY3ODIgMjM2IDk0LjM3OTkgMjM2LjAzMSA5NC4wODg2IDIzNi4wODkgOTMuODA3MkwyMzYuMzM4IDkzLjAxNjIgMjM2Ljg1OCA5Mi4xMzE0IDI1OS40NzMgNTMuNjI5NCAyNTkuOTYxIDUyLjc5ODUgMjYwLjQwNyA1Mi4yNjU4QzI2MS4yIDUxLjQ4MzcgMjYyLjI5NiA1MSAyNjMuNTA2IDUxWk0yNjMuNTg2IDY2LjAxODNDMjYwLjczNyA2Ni4wMTgzIDI1OS4zMTMgNjcuMTI0NSAyNTkuMzEzIDY5LjMzNyAyNTkuMzEzIDY5LjYxMDIgMjU5LjMzMiA2OS44NjA4IDI1OS4zNzEgNzAuMDg4N0wyNjEuNzk1IDg0LjAxNjEgMjY1LjM4IDg0LjAxNjEgMjY3LjgyMSA2OS43NDc1QzI2Ny44NiA2OS43MzA5IDI2Ny44NzkgNjkuNTg3NyAyNjcuODc5IDY5LjMxNzkgMjY3Ljg3OSA2Ny4xMTgyIDI2Ni40NDggNjYuMDE4MyAyNjMuNTg2IDY2LjAxODNaTTI2My41NzYgODYuMDU0N0MyNjEuMDQ5IDg2LjA1NDcgMjU5Ljc4NiA4Ny4zMDA1IDI1OS43ODYgODkuNzkyMSAyNTkuNzg2IDkyLjI4MzcgMjYxLjA0OSA5My41Mjk1IDI2My41NzYgOTMuNTI5NSAyNjYuMTE2IDkzLjUyOTUgMjY3LjM4NyA5Mi4yODM3IDI2Ny4zODcgODkuNzkyMSAyNjcuMzg3IDg3LjMwMDUgMjY2LjExNiA4Ni4wNTQ3IDI2My41NzYgODYuMDU0N1oiIGZpbGw9IiNGRkU1MDAiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvZz48L3N2Zz4=) no-repeat 1rem/1.8rem, #b32121;
padding: 1rem 1rem 1rem 3.7rem;
color: white;
}
.blazor-error-boundary::after {
content: "An error has occurred."
}
@media (min-width: 0px) {
@media (min-width: 0px) {
#OnboardingCarousel {
min-height: 430px;
}

View File

@ -7,6 +7,7 @@
<title>BTCPay Server</title>
<script src="./_framework/blazor.webview.js"></script>
<script src="./_content/MudBlazor/MudBlazor.min.js"></script>
<script src="./_content/BTCPayApp.UI/js/site.js"></script>
<link href="./_content/MudBlazor/MudBlazor.min.css" rel="stylesheet"/>
<link href="./_content/BTCPayApp.UI/css/mudblazor-overrides.css" rel="stylesheet"/>
<link href="./_content/BTCPayApp.UI/css/theme.css" rel="stylesheet"/>

View File

@ -0,0 +1,11 @@
// Theme Switch
const THEMES = ['light', 'dark']
const THEME_ATTR = 'data-btcpay-theme'
const systemColorMode = window.matchMedia('(prefers-color-scheme: dark)').matches ? THEMES[1] : THEMES[0]
function setTheme(mode) {
if (THEMES.includes(mode) && mode !== systemColorMode) {
document.documentElement.setAttribute(THEME_ATTR, mode)
} else {
document.documentElement.removeAttribute(THEME_ATTR)
}
}