Catch up docs with master
This commit is contained in:
Коммит
7e9e3a080e
|
@ -15,6 +15,7 @@
|
|||
<!-- /PWA -->
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Blazored.LocalStorage" Version="3.0.0" />
|
||||
<PackageReference Include="BuildWebCompiler" Version="1.12.405" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="3.2.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Build" Version="3.2.0" PrivateAssets="all" />
|
||||
|
|
|
@ -1,15 +1,16 @@
|
|||
@page "/sales"
|
||||
|
||||
@using System.Globalization
|
||||
@attribute [Authorize]
|
||||
@inject HttpClient Http
|
||||
@inject ITelerikStringLocalizer L
|
||||
@inject ILocalStorageService LocalStorage
|
||||
|
||||
<SalesByDateChart Data="chartData"></SalesByDateChart>
|
||||
<CardContainer Title="@L["Sales"]">
|
||||
<TelerikGrid @ref="Grid" Height="500px" FilterMode="@GridFilterMode.FilterMenu"
|
||||
Sortable="true" Pageable="true" PageSize="10"
|
||||
OnStateInit="@((GridStateEventArgs<Sale> args) => OnStateInit(args))"
|
||||
OnStateChanged="@((GridStateEventArgs<Sale> args) => OnStateChanged(args))"
|
||||
Data=@Model.CurrentPageData TotalCount=@Model.TotalItemCount OnRead=@ReadItems>
|
||||
<GridToolBar>
|
||||
<label>@L["Sales_Grid_Toolbar_ReportRange"]</label>
|
||||
|
@ -47,9 +48,12 @@
|
|||
@code {
|
||||
|
||||
#region Data Processing
|
||||
string storageKey = "BlazingCoffeeSales";
|
||||
|
||||
DataEnvelope<Sale> Model { get; set; } = new DataEnvelope<Sale>();
|
||||
SalesByDateViewModel[] chartData;
|
||||
|
||||
|
||||
async Task ReadItems(GridReadEventArgs args)
|
||||
{
|
||||
var response = await Http.PostAsJsonAsync("api/sales", args.Request);
|
||||
|
@ -61,7 +65,30 @@
|
|||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
var state = await LocalStorage.GetItemAsync<GridState<Sale>>(storageKey);
|
||||
|
||||
if (state != null)
|
||||
{
|
||||
var startFilter = state.TransactionDateFilters(f => f.Operator == FilterOperator.IsGreaterThan);
|
||||
var endFilter = state.TransactionDateFilters(f => f.Operator == FilterOperator.IsLessThan);
|
||||
|
||||
StartValue = (DateTime?)startFilter.Value;
|
||||
EndValue = (DateTime?)endFilter.Value;
|
||||
}
|
||||
|
||||
// .StartDate != null ? state.StartDate : StartValue = DateTime.Now.AddYears(-2);
|
||||
//EndValue = state?.EndDate != null ? state.EndDate : StartValue = DateTime.Now;
|
||||
}
|
||||
catch (InvalidOperationException e)
|
||||
{
|
||||
// the JS Interop for the local storage cannot be used during pre-rendering
|
||||
// so the code above will throw. Once the app initializes, it will work fine
|
||||
}
|
||||
|
||||
await GetChartData();
|
||||
|
||||
}
|
||||
|
||||
async Task GetChartData()
|
||||
|
@ -78,19 +105,12 @@
|
|||
FilterDescriptor StartFilter() => new FilterDescriptor("TransactionDate", FilterOperator.IsGreaterThan, StartValue);
|
||||
FilterDescriptor EndFilter() => new FilterDescriptor("TransactionDate", FilterOperator.IsLessThan, EndValue);
|
||||
|
||||
void OnStateInit(GridStateEventArgs<Sale> args)
|
||||
{
|
||||
args.GridState.FilterDescriptors.Add(StartFilter());
|
||||
args.GridState.FilterDescriptors.Add(EndFilter());
|
||||
}
|
||||
|
||||
void StartValueChangedHandler(DateTime? currStart)
|
||||
{
|
||||
//you have to update the model manually because handling the <Parameter>Changed event does not let you use @bind-<Parameter>
|
||||
//not updating the model will effectively cancel the event
|
||||
StartValue = currStart;
|
||||
|
||||
//Console.WriteLine($"start changed to: {currStart}");
|
||||
}
|
||||
|
||||
async Task EndValueChangedHandler(DateTime? currEnd)
|
||||
|
@ -111,7 +131,38 @@
|
|||
state.FilterDescriptors.Add(EndFilter());
|
||||
await Grid.SetState(state);
|
||||
await GetChartData();
|
||||
await LocalStorage.SetItemAsync<GridState<Sale>>(storageKey, state);
|
||||
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region State Management
|
||||
|
||||
async Task OnStateInit(GridStateEventArgs<Sale> args)
|
||||
{
|
||||
try
|
||||
{
|
||||
var state = await LocalStorage.GetItemAsync<GridState<Sale>>(storageKey);
|
||||
if (state != null)
|
||||
{
|
||||
args.GridState = state;
|
||||
}
|
||||
|
||||
}
|
||||
catch (InvalidOperationException e)
|
||||
{
|
||||
// the JS Interop for the local storage cannot be used during pre-rendering
|
||||
// so the code above will throw. Once the app initializes, it will work fine
|
||||
}
|
||||
args.GridState.FilterDescriptors.Add(StartFilter());
|
||||
args.GridState.FilterDescriptors.Add(EndFilter());
|
||||
}
|
||||
|
||||
async Task OnStateChanged(GridStateEventArgs<Sale> args)
|
||||
{
|
||||
await LocalStorage.SetItemAsync(storageKey, args.GridState);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using BlazingCoffee.Shared.Models;
|
||||
using Telerik.Blazor.Components;
|
||||
using Telerik.DataSource;
|
||||
|
||||
namespace BlazingCoffee.Client.Pages.SalesReports
|
||||
{
|
||||
public static class SalesExtensions
|
||||
{
|
||||
public static FilterDescriptor TransactionDateFilters(this GridState<Sale> gridState,
|
||||
Func<FilterDescriptor, bool> predicate) =>
|
||||
gridState.FilterDescriptors
|
||||
.OfType<FilterDescriptor>()
|
||||
.Where(f=> f.Member == "TransactionDate")
|
||||
.First(predicate);
|
||||
}
|
||||
}
|
|
@ -1,9 +1,9 @@
|
|||
using BlazingCoffee.Services;
|
||||
using BlazingCoffee.Shared.Localization;
|
||||
using Blazored.LocalStorage;
|
||||
using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
|
||||
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.JSInterop;
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Net.Http;
|
||||
|
@ -22,8 +22,8 @@ namespace BlazingCoffee.Client
|
|||
ConfigureServices(builder);
|
||||
|
||||
var host = builder.Build();
|
||||
var jsInterop = host.Services.GetRequiredService<IJSRuntime>();
|
||||
var result = await jsInterop.InvokeAsync<string>("blazorCulture.get");
|
||||
var localStorage = host.Services.GetRequiredService<ILocalStorageService>();
|
||||
var result = await localStorage.GetItemAsStringAsync("BlazorCulture");
|
||||
if (result != null)
|
||||
{
|
||||
var culture = new CultureInfo(result);
|
||||
|
@ -38,6 +38,7 @@ namespace BlazingCoffee.Client
|
|||
{
|
||||
builder.Services.AddTelerikBlazor();
|
||||
|
||||
builder.Services.AddBlazoredLocalStorage();
|
||||
builder.Services.AddHttpClient<PublicClient>(client => client.BaseAddress = new Uri(builder.HostEnvironment.BaseAddress));
|
||||
builder.Services.AddHttpClient("BlazingCoffee.ServerAPI", client => client.BaseAddress = new Uri(builder.HostEnvironment.BaseAddress))
|
||||
.AddHttpMessageHandler<BaseAddressAuthorizationMessageHandler>();
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
@using System.Globalization
|
||||
|
||||
@inject IJSRuntime js
|
||||
@inject NavigationManager NavigationManager
|
||||
@inject ILocalStorageService LocalStorage
|
||||
|
||||
<div style="margin-bottom: 20px;">
|
||||
<TelerikDropDownList Data="@Cultures"
|
||||
Value="@SelectedCulture"
|
||||
ValueChanged="@((string value) => { OnValueChanged(value); })"
|
||||
ValueChanged="@((string value) => OnValueChanged(value) )"
|
||||
TextField="@nameof(CultureData.Text)"
|
||||
ValueField="@nameof(CultureData.Value)">
|
||||
</TelerikDropDownList>
|
||||
|
@ -29,18 +29,18 @@
|
|||
|
||||
public string SelectedCulture { get; set; }
|
||||
|
||||
public void OnValueChanged(string eventArgs)
|
||||
public async Task OnValueChanged(string eventArgs)
|
||||
{
|
||||
SelectedCulture = eventArgs;
|
||||
|
||||
SetCulture(eventArgs);
|
||||
await SetCulture(eventArgs);
|
||||
}
|
||||
|
||||
public void SetCulture(string culture)
|
||||
public async Task SetCulture(string culture)
|
||||
{
|
||||
if (CultureInfo.CurrentCulture.Name != culture)
|
||||
{
|
||||
js.InvokeVoidAsync("blazorCulture.set", culture);
|
||||
await LocalStorage.SetItemAsync("BlazorCulture", culture);
|
||||
|
||||
NavigationManager.NavigateTo(NavigationManager.Uri, forceLoad: true);
|
||||
}
|
||||
|
@ -48,7 +48,7 @@
|
|||
|
||||
public async Task GetCulture()
|
||||
{
|
||||
var value = await js.InvokeAsync<string>("blazorCulture.get");
|
||||
var value = await LocalStorage.GetItemAsStringAsync("BlazorCulture");
|
||||
if (string.IsNullOrEmpty(value))
|
||||
{
|
||||
value = "en-US";
|
||||
|
|
|
@ -3,10 +3,13 @@
|
|||
|
||||
@inherits LayoutComponentBase
|
||||
@inject ITelerikStringLocalizer L
|
||||
|
||||
@inject ILocalStorageService LocalStorage
|
||||
|
||||
<TelerikRootComponent>
|
||||
<TelerikDrawer @bind-Expanded="@Expanded" Width="280px" Data="Data" Mode="DrawerMode.Push" Position="DrawerPosition.Left" MiniMode="true">
|
||||
<TelerikDrawer @ref="MenuDrawer"
|
||||
Expanded="@Expanded"
|
||||
ExpandedChanged="((bool newValue) => ExpandedChangedHandler(newValue))"
|
||||
Width="280px" Data="Data" Mode="DrawerMode.Push" Position="DrawerPosition.Left" MiniMode="true">
|
||||
<Template>
|
||||
<DrawTemplate Data="context"></DrawTemplate>
|
||||
</Template>
|
||||
|
@ -14,7 +17,7 @@
|
|||
<header class="header">
|
||||
<div class="nav-container">
|
||||
<div class="menu-button">
|
||||
<TelerikButton Icon="@IconName.Menu" OnClick="@(() => Expanded = !Expanded)" />
|
||||
<TelerikButton Icon="@IconName.Menu" OnClick="ToggleMenuDrawer" />
|
||||
</div>
|
||||
|
||||
<div class="title">
|
||||
|
@ -42,7 +45,7 @@
|
|||
@L["SelectTheme"]
|
||||
</label>
|
||||
<div class="k-form-field-wrap">
|
||||
<TelerikDropDownList Id="theme" Data="Themes" TValue="string" TItem="string" @bind-Value="SelectedTheme" />
|
||||
<ThemeChooser></ThemeChooser>
|
||||
</div>
|
||||
</div>
|
||||
<div class="k-form-field">
|
||||
|
@ -59,7 +62,10 @@
|
|||
</TelerikRootComponent>
|
||||
|
||||
@code {
|
||||
bool Expanded { get; set; } = true;
|
||||
|
||||
TelerikDrawer<DrawerItem> MenuDrawer { get; set; }
|
||||
|
||||
bool Expanded { get; set; }
|
||||
bool SettingsExpanded { get; set; }
|
||||
|
||||
IEnumerable<DrawerItem> Data =>
|
||||
|
@ -73,9 +79,38 @@
|
|||
new DrawerItem{ Text = "Telerik", Icon = IconName.HyperlinkGlobe, Url="https://telerik.com", Group = "ext"},
|
||||
new DrawerItem{ Text = L["Documentation"], Icon = IconName.Html, Url="https://docs.telerik.com/blazor-ui/introduction", Group = "ext"},
|
||||
new DrawerItem{ Text = L["Support"], Icon = IconName.Question, Url="https://www.telerik.com/account/support-tickets", Group = "ext"}
|
||||
};
|
||||
};
|
||||
|
||||
string SelectedTheme = "auto";
|
||||
IEnumerable<string> Themes => new List<string> { "auto" }; // TODO add manual settings, "light", "dark" };
|
||||
async Task ToggleMenuDrawer()
|
||||
{
|
||||
if (Expanded)
|
||||
{
|
||||
await MenuDrawer.CollapseAsync();
|
||||
}
|
||||
else
|
||||
{
|
||||
await MenuDrawer.ExpandAsync();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
async Task ExpandedChangedHandler(bool value)
|
||||
{
|
||||
Expanded = value;
|
||||
|
||||
await LocalStorage.SetItemAsync("drawerState", value);
|
||||
}
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
var hasKey = await LocalStorage.ContainKeyAsync("drawerState");
|
||||
if (hasKey)
|
||||
{
|
||||
Expanded = await LocalStorage.GetItemAsync<bool>("drawerState");
|
||||
}
|
||||
else
|
||||
{
|
||||
Expanded = true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
@namespace BlazingCoffee.Client.Shared
|
||||
@inject IJSRuntime js
|
||||
|
||||
<TelerikDropDownList Id="theme"
|
||||
Data="Themes"
|
||||
TextField="ThemeText"
|
||||
ValueField="ThemeValue"
|
||||
Value="@SelectedTheme"
|
||||
ValueChanged="@( (string v) => HandleThemeSelected(v) )" />
|
||||
|
||||
@code {
|
||||
|
||||
string SelectedTheme;
|
||||
|
||||
IEnumerable<ThemeSetting> Themes => new List<ThemeSetting> {
|
||||
new ThemeSetting { ThemeText = "Auto (default)", ThemeValue = "auto" },
|
||||
new ThemeSetting { ThemeText = "Light", ThemeValue = "main" },
|
||||
new ThemeSetting { ThemeText = "Dark", ThemeValue = "main-dark" }
|
||||
};
|
||||
|
||||
async Task HandleThemeSelected(string value)
|
||||
{
|
||||
await js.InvokeVoidAsync("themeChooser.setTheme", value);
|
||||
SelectedTheme = value;
|
||||
}
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
var theme = await js.InvokeAsync<string>("themeChooser.getTheme");
|
||||
SelectedTheme = string.IsNullOrEmpty(theme) ? "auto" : theme;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BlazingCoffee.Client.Shared
|
||||
{
|
||||
public class ThemeSetting
|
||||
{
|
||||
public string ThemeText { get; set; }
|
||||
public string ThemeValue { get; set; }
|
||||
}
|
||||
}
|
|
@ -17,4 +17,5 @@
|
|||
@using BlazingCoffee.Client
|
||||
@using BlazingCoffee.Client.Shared
|
||||
@using BlazingCoffee.Shared
|
||||
@using BlazingCoffee.Shared.Models
|
||||
@using BlazingCoffee.Shared.Models
|
||||
@using Blazored.LocalStorage
|
|
@ -8,8 +8,7 @@
|
|||
<base href="/" />
|
||||
<link href="https://fonts.googleapis.com/css2?family=Roboto&display=swap" rel="stylesheet">
|
||||
<script src="_content/telerik.ui.for.blazor/js/telerik-blazor.js"></script>
|
||||
<link href="css/main.css" rel="stylesheet" media="(prefers-color-scheme: light), (prefers-color-scheme: no-preference)" />
|
||||
<link href="css/main-dark.css" rel="stylesheet" media="(prefers-color-scheme: dark)" />
|
||||
<link id="theme" href="css/main.css" rel="stylesheet" />
|
||||
<!-- PWA -->
|
||||
<link href="manifest.json" rel="manifest" />
|
||||
<link rel="apple-touch-icon" sizes="512x512" href="icon-512.png" />
|
||||
|
@ -26,7 +25,10 @@
|
|||
</div>
|
||||
<script src="_content/Microsoft.AspNetCore.Components.WebAssembly.Authentication/AuthenticationService.js"></script>
|
||||
<script src="_framework/blazor.webassembly.js"></script>
|
||||
<script src="js/blazorCulture.js"></script>
|
||||
<script src="js/themeChooser.js"></script>
|
||||
<script>
|
||||
window.themeChooser.init();
|
||||
</script>
|
||||
<!-- PWA -->
|
||||
<script>navigator.serviceWorker.register('service-worker.js');</script>
|
||||
<!-- /PWA -->
|
||||
|
|
|
@ -1,9 +0,0 @@
|
|||
window.blazorCulture = {
|
||||
get: () => {
|
||||
return window.localStorage['BlazorCulture'];
|
||||
},
|
||||
|
||||
set: (value) => {
|
||||
window.localStorage['BlazorCulture'] = value;
|
||||
}
|
||||
};
|
|
@ -0,0 +1,47 @@
|
|||
window.themeChooser = {
|
||||
getTheme: function () {
|
||||
return window.localStorage['ThemeSetting'];
|
||||
},
|
||||
setTheme: function (themeName) {
|
||||
if (themeName === "auto") {
|
||||
window.localStorage.removeItem('ThemeSetting');
|
||||
this.autoDetectTheme();
|
||||
} else {
|
||||
window.localStorage['ThemeSetting'] = themeName;
|
||||
this.changeTheme(themeName);
|
||||
}
|
||||
},
|
||||
changeTheme: function (themeName) {
|
||||
// Build the new css link
|
||||
let newLink = document.createElement("link");
|
||||
newLink.setAttribute("id", "theme");
|
||||
newLink.setAttribute("rel", "stylesheet");
|
||||
newLink.setAttribute("type", "text/css");
|
||||
newLink.setAttribute("href", `css/${themeName}.css`);
|
||||
|
||||
// Remove and replace the theme
|
||||
let head = document.getElementsByTagName("head")[0];
|
||||
head.querySelector("#theme").remove();
|
||||
head.appendChild(newLink);
|
||||
},
|
||||
autoDetectTheme() {
|
||||
let isDark = window.matchMedia("(prefers-color-scheme: dark)").matches;
|
||||
|
||||
if (isDark) {
|
||||
this.changeTheme("main-dark");
|
||||
} else {
|
||||
this.changeTheme("main");
|
||||
}
|
||||
},
|
||||
init: function () {
|
||||
let themeSetting = this.getTheme();
|
||||
let isThemeSet = !themeSetting;
|
||||
|
||||
if (isThemeSet) {
|
||||
this.autoDetectTheme();
|
||||
}
|
||||
else {
|
||||
this.changeTheme(themeSetting);
|
||||
}
|
||||
}
|
||||
}
|
Загрузка…
Ссылка в новой задаче