init receiver UI web project using devexpress template
This commit is contained in:
Binary file not shown.
@@ -0,0 +1,30 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.BlazorWebAssembly">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<NoDefaultLaunchSettingsFile>true</NoDefaultLaunchSettingsFile>
|
||||
<StaticWebAssetProjectMode>Default</StaticWebAssetProjectMode>
|
||||
<MSBuildWarningsAsMessages>$(MSBuildWarningsAsMessage);WASM0001</MSBuildWarningsAsMessages>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="DevExpress.Blazor" Version="25.2.*" />
|
||||
<PackageReference Include="DevExpress.Blazor.PdfViewer" Version="25.2.*" />
|
||||
<PackageReference Include="DevExpress.Pdf.SkiaRenderer" Version="25.2.*" />
|
||||
<PackageReference Include="HarfBuzzSharp.NativeAssets.WebAssembly" Version="8.3.1.2" />
|
||||
<PackageReference Include="SkiaSharp.NativeAssets.WebAssembly" Version="3.119.1" />
|
||||
<PackageReference Include="DevExpress.AIIntegration.Blazor" Version="25.2.*" />
|
||||
<PackageReference Include="DevExpress.AIIntegration.OpenAI" Version="25.2.*" />
|
||||
|
||||
<PackageReference Include="Azure.AI.OpenAI" Version="2.2.0-beta.5" />
|
||||
<PackageReference Include="Microsoft.Extensions.AI" Version="9.7.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.AI.OpenAI" Version="9.7.1-preview.1.25365.4" />
|
||||
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="8.0.20" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="Documents\Invoice.pdf" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,38 @@
|
||||
@inherits DrawerStateComponentBase
|
||||
|
||||
<div class="drawer-container">
|
||||
<DxDrawer PanelWidth="@PanelWidth"
|
||||
CssClass="@(CssClass + " mobile")"
|
||||
Mode="DrawerMode.Overlap"
|
||||
IsOpen="@ToggledDrawer"
|
||||
BodyTemplate="BodyTemplate"
|
||||
HeaderTemplate="HeaderTemplate"
|
||||
FooterTemplate="FooterTemplate"
|
||||
ApplyBackgroundShading="false"
|
||||
ClosedCssClass="panel-closed">
|
||||
<TargetContent>
|
||||
<DxDrawer PanelWidth="@PanelWidth"
|
||||
CssClass="@CssClass"
|
||||
Mode="DrawerMode.Shrink"
|
||||
IsOpen="@(!ToggledDrawer)"
|
||||
BodyTemplate="BodyTemplate"
|
||||
HeaderTemplate="HeaderTemplate"
|
||||
FooterTemplate="FooterTemplate"
|
||||
OpenCssClass="panel-open">
|
||||
<TargetContent>
|
||||
<div class="navigation-drawer-shading"></div>
|
||||
@TargetContent
|
||||
</TargetContent>
|
||||
</DxDrawer>
|
||||
</TargetContent>
|
||||
</DxDrawer>
|
||||
</div>
|
||||
|
||||
@code {
|
||||
[Parameter] public string? CssClass { get; set; }
|
||||
[Parameter] public string? PanelWidth { get; set; }
|
||||
[Parameter] public RenderFragment? TargetContent { get; set; }
|
||||
[Parameter] public RenderFragment? BodyTemplate { get; set; }
|
||||
[Parameter] public RenderFragment? HeaderTemplate { get; set; }
|
||||
[Parameter] public RenderFragment? FooterTemplate { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
.drawer-container {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.navigation-drawer-shading {
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
transition: ease 300ms;
|
||||
transition-property: opacity, visibility;
|
||||
visibility: visible;
|
||||
width: 100%;
|
||||
z-index: 99;
|
||||
background-color: var(--dxds-color-surface-backdrop-default-rest);
|
||||
}
|
||||
|
||||
.navigation-drawer.mobile.panel-closed .navigation-drawer-shading {
|
||||
opacity: 0;
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
::deep .navigation-drawer > .dxbl-drawer-panel {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
::deep .navigation-drawer.mobile > .dxbl-drawer-panel {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.navigation-drawer-shading {
|
||||
display: none;
|
||||
}
|
||||
|
||||
::deep .panel-open:not(.mobile) .nav-buttons-container .menu-button {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
::deep .navigation-drawer > .dxbl-drawer-panel {
|
||||
display: none;
|
||||
}
|
||||
|
||||
::deep .navigation-drawer.mobile > .dxbl-drawer-panel {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.navigation-drawer-shading {
|
||||
display: block;
|
||||
}
|
||||
|
||||
::deep .panel-open:not(.mobile) .nav-buttons-container .menu-button {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
@inherits DrawerStateLayoutComponentBase
|
||||
@inject NavigationManager NavigationManager
|
||||
|
||||
<div class="page">
|
||||
<Drawer CssClass="navigation-drawer" PanelWidth="240px">
|
||||
<HeaderTemplate>
|
||||
<div class="navigation-drawer-header">
|
||||
<NavLink href="@AddDrawerStateToUrl("/")">
|
||||
<img class="logo" src="images/logo.svg" alt="DevExpress logo" />
|
||||
</NavLink>
|
||||
<NavLink aria-label="Close menu" href="@AddDrawerStateToUrlToggled(LocalPath)">
|
||||
<DxButton aria-label="Close menu" RenderStyle="ButtonRenderStyle.Light" RenderStyleMode="ButtonRenderStyleMode.Text" CssClass="btn-icon-only" IconCssClass="@(ToggledDrawer ? "icon icon-close" : "icon icon-menu")"></DxButton>
|
||||
</NavLink>
|
||||
</div>
|
||||
</HeaderTemplate>
|
||||
<BodyTemplate>
|
||||
<div class="w-100">
|
||||
<NavMenu></NavMenu>
|
||||
</div>
|
||||
</BodyTemplate>
|
||||
<FooterTemplate>
|
||||
<div class="navigation-drawer-footer">
|
||||
<NavLink href="https://docs.devexpress.com/Blazor/400725/blazor-components" class="button-link">
|
||||
<DxButton Text="Docs" RenderStyle="ButtonRenderStyle.Light" RenderStyleMode="ButtonRenderStyleMode.Text" IconCssClass="icon icon-docs"></DxButton>
|
||||
</NavLink>
|
||||
<NavLink href="https://demos.devexpress.com/blazor/" class="button-link">
|
||||
<DxButton Text="Demos" RenderStyle="ButtonRenderStyle.Light" RenderStyleMode="ButtonRenderStyleMode.Text" IconCssClass="icon icon-demos"></DxButton>
|
||||
</NavLink>
|
||||
</div>
|
||||
</FooterTemplate>
|
||||
<TargetContent>
|
||||
<div class="drawer-content">
|
||||
<div class="nav-buttons-container">
|
||||
<NavLink aria-label="Open menu" href="@AddDrawerStateToUrlToggled(LocalPath)" class="menu-button">
|
||||
<DxButton aria-label="Open menu" RenderStyle="ButtonRenderStyle.Secondary" RenderStyleMode="ButtonRenderStyleMode.Text" CssClass="btn-icon-only" IconCssClass="icon icon-menu"></DxButton>
|
||||
</NavLink>
|
||||
@if (LocalPath != "/") {
|
||||
<NavLink href="@AddDrawerStateToUrl("/")" class="button-link">
|
||||
<DxButton Text="Back to Home" RenderStyle="ButtonRenderStyle.Secondary" RenderStyleMode="ButtonRenderStyleMode.Text" CssClass="back-button" IconCssClass="icon icon-back"></DxButton>
|
||||
</NavLink>
|
||||
}
|
||||
</div>
|
||||
<div class="page-content-container">
|
||||
@Body
|
||||
</div>
|
||||
</div>
|
||||
</TargetContent>
|
||||
</Drawer>
|
||||
</div>
|
||||
|
||||
@code {
|
||||
string LocalPath => new Uri(NavigationManager.Uri).LocalPath;
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
.page {
|
||||
height: 100%;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
::deep .navigation-drawer {
|
||||
--dxbl-drawer-panel-body-padding-x: 0;
|
||||
--dxbl-drawer-panel-body-padding-y: 1rem;
|
||||
--dxbl-drawer-panel-footer-bg: none;
|
||||
--dxbl-drawer-panel-header-bg: none;
|
||||
--dxbl-drawer-separator-border-width: 0;
|
||||
}
|
||||
|
||||
::deep .navigation-drawer > .dxbl-drawer-panel {
|
||||
background-image: linear-gradient(180deg, var(--dxds-color-surface-primary-default-rest) 0%, var(--dxds-primary-170) 150%);
|
||||
}
|
||||
|
||||
.navigation-drawer-header {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: 1.375rem 0.375rem;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.navigation-drawer-header .logo {
|
||||
height: 1.5rem;
|
||||
width: 9rem;
|
||||
}
|
||||
|
||||
.navigation-drawer-footer {
|
||||
display: flex;
|
||||
justify-content: space-evenly;
|
||||
padding-bottom: 0.875rem;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.drawer-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
padding: 2rem 1.5rem 1.5rem 1.5rem;
|
||||
}
|
||||
|
||||
.nav-buttons-container {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
gap: 0.625rem;
|
||||
min-height: 2rem;
|
||||
}
|
||||
|
||||
::deep .nav-buttons-container > a {
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
::deep .nav-buttons-container .back-button {
|
||||
padding-left: 0;
|
||||
padding-right: 0.25rem;
|
||||
}
|
||||
|
||||
.page-content-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-grow: 1;
|
||||
min-height: 0;
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
@inject NavigationManager NavigationManager
|
||||
@implements IDisposable
|
||||
|
||||
<div>
|
||||
<DxMenu Orientation="@Orientation.Vertical" CssClass="menu">
|
||||
<Items>
|
||||
<DxMenuItem NavigateUrl="/" Text="Home" CssClass="@MenuItemCssClass("/")" IconCssClass="icon icon-home"></DxMenuItem>
|
||||
<DxMenuItem NavigateUrl="/counter" Text="Counter" CssClass="@MenuItemCssClass("/counter")" IconCssClass="icon icon-counter"></DxMenuItem>
|
||||
<DxMenuItem NavigateUrl="/weather" Text="Weather" CssClass="@MenuItemCssClass("/weather")" IconCssClass="icon icon-weather"></DxMenuItem>
|
||||
<DxMenuItem NavigateUrl="/pdfviewer" Text="PDF Viewer" CssClass="@MenuItemCssClass("/pdfviewer")" IconCssClass="icon icon-pdf-viewer"></DxMenuItem>
|
||||
</Items>
|
||||
</DxMenu>
|
||||
</div>
|
||||
|
||||
@code {
|
||||
private string? currentLocalPath;
|
||||
|
||||
protected override void OnInitialized() {
|
||||
currentLocalPath = new Uri(NavigationManager.Uri).LocalPath;
|
||||
NavigationManager.LocationChanged += OnLocationChanged;
|
||||
}
|
||||
|
||||
private void OnLocationChanged(object? sender, LocationChangedEventArgs e) {
|
||||
currentLocalPath = new Uri(NavigationManager.Uri).LocalPath;
|
||||
InvokeAsync(StateHasChanged);
|
||||
}
|
||||
|
||||
private string? MenuItemCssClass(string itemPath) {
|
||||
return string.Equals(currentLocalPath, itemPath, StringComparison.OrdinalIgnoreCase) ? "menu-item-active" : null;
|
||||
}
|
||||
|
||||
public void Dispose() {
|
||||
NavigationManager.LocationChanged -= OnLocationChanged;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
::deep .menu {
|
||||
--dxbl-menu-bottom-left-border-radius: 0;
|
||||
--dxbl-menu-bottom-right-border-radius: 0;
|
||||
--dxbl-menu-top-left-border-radius: 0;
|
||||
--dxbl-menu-top-right-border-radius: 0;
|
||||
--dxbl-menu-item-padding-x: 1.125rem;
|
||||
--dxbl-menu-item-padding-y: 0.5rem;
|
||||
--dxbl-menu-item-color: var(--dxds-color-content-neutral-default-static-dark-rest);
|
||||
--dxbl-menu-item-image-color: var(--dxds-color-content-neutral-default-static-dark-rest);
|
||||
--dxbl-menu-item-hover-bg: rgb(from var(--dxds-color-surface-neutral-default-static-light-rest) r g b / 0.15);
|
||||
--dxbl-menu-item-hover-color: var(--dxds-color-content-neutral-default-static-dark-hovered);
|
||||
--dxbl-menu-item-hover-image-color: var(--dxds-color-content-neutral-default-static-dark-hovered);
|
||||
|
||||
background: none;
|
||||
}
|
||||
|
||||
::deep .menu.display-mobile {
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
::deep .menu-item-active {
|
||||
background-color: rgb(from var(--dxds-color-surface-neutral-default-static-light-rest) r g b / 0.05);
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
@page "/counter"
|
||||
|
||||
<PageTitle>Counter</PageTitle>
|
||||
|
||||
<h1>Counter</h1>
|
||||
|
||||
<div class="counter-block">
|
||||
<div class="counter-content">
|
||||
<div class="counter-count">
|
||||
@currentCount
|
||||
</div>
|
||||
current count
|
||||
</div>
|
||||
<DxButton Click="IncrementCount">Click me</DxButton>
|
||||
</div>
|
||||
|
||||
@code {
|
||||
private int currentCount;
|
||||
|
||||
private void IncrementCount()
|
||||
{
|
||||
currentCount++;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
.counter-block {
|
||||
align-items: center;
|
||||
border-radius: 1rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1.5rem;
|
||||
height: 17rem;
|
||||
justify-content: center;
|
||||
padding: 2.5rem 1.5rem 1.5rem;
|
||||
width: 16.875rem;
|
||||
border: 1px solid var(--dxds-color-border-neutral-default-rest);
|
||||
}
|
||||
|
||||
.counter-block .counter-content {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.counter-block .counter-count {
|
||||
font-size: 7.5rem;
|
||||
font-weight: 400;
|
||||
line-height: 7.75rem;
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
@page "/"
|
||||
|
||||
<PageTitle>Welcome</PageTitle>
|
||||
|
||||
<div class="main-content">
|
||||
<DxGridLayout CssClass="index-gridlayout">
|
||||
<Rows>
|
||||
<DxGridLayoutRow Height="auto" Areas="header"></DxGridLayoutRow>
|
||||
<DxGridLayoutRow Height="auto" Areas="tiles"></DxGridLayoutRow>
|
||||
</Rows>
|
||||
<Items>
|
||||
<DxGridLayoutItem Area="header" CssClass="title">
|
||||
<Template>
|
||||
<div class="title-header-text">Hello World!</div>
|
||||
<div class="title-content-text">Welcome to your new DevExpress Blazor Application</div>
|
||||
</Template>
|
||||
</DxGridLayoutItem>
|
||||
<DxGridLayoutItem Area="tiles" CssClass="tiles">
|
||||
<Template>
|
||||
<IndexTile NavigateUrl="/counter" Title="Counter" Description="Count mouse clicks and track the total." IconCssClass="icon-counter" />
|
||||
<IndexTile NavigateUrl="/weather" Title="Weather" Description="See a 5-day temperature and weather conditions forecast." IconCssClass="icon-weather" />
|
||||
<IndexTile NavigateUrl="/pdfviewer" Title="PDF Viewer" Description="Load PDF files and view them in the web browser." IconCssClass="icon-pdf-viewer" />
|
||||
</Template>
|
||||
</DxGridLayoutItem>
|
||||
</Items>
|
||||
</DxGridLayout>
|
||||
</div>
|
||||
@@ -0,0 +1,31 @@
|
||||
::deep .index-gridlayout {
|
||||
container-type: inline-size;
|
||||
height: auto;
|
||||
margin-top: auto;
|
||||
margin-bottom: auto;
|
||||
padding-bottom: 9rem;
|
||||
}
|
||||
|
||||
::deep .title {
|
||||
padding-bottom: 3rem;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
::deep .tiles {
|
||||
--tile-column-count: 4;
|
||||
|
||||
display: grid;
|
||||
gap: 1rem;
|
||||
grid-template-columns: repeat(var(--tile-column-count), max-content);
|
||||
justify-content: center;
|
||||
|
||||
@container (max-width: 60.5rem) {
|
||||
--tile-column-count: 3;
|
||||
}
|
||||
@container (max-width: 45.125rem) {
|
||||
--tile-column-count: 2;
|
||||
}
|
||||
@container (max-width: 29.75rem) {
|
||||
--tile-column-count: 1;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
@inherits DrawerStateComponentBase
|
||||
|
||||
<div class="tile">
|
||||
<NavLink href="@AddDrawerStateToUrl(NavigateUrl)">
|
||||
<DxGridLayout CssClass="tile-content" ColumnSpacing="0.75rem" RowSpacing="0.75rem">
|
||||
<Rows>
|
||||
<DxGridLayoutRow Areas="icon title" Height="auto" />
|
||||
<DxGridLayoutRow Areas="description description" Height="auto" />
|
||||
</Rows>
|
||||
<Columns>
|
||||
<DxGridLayoutColumn Width="auto" />
|
||||
<DxGridLayoutColumn />
|
||||
</Columns>
|
||||
<Items>
|
||||
<DxGridLayoutItem Area="icon" CssClass="tile-icon">
|
||||
<Template>
|
||||
<div class="@("icon " + IconCssClass)" aria-hidden="true"></div>
|
||||
</Template>
|
||||
</DxGridLayoutItem>
|
||||
<DxGridLayoutItem Area="title" CssClass="tile-title">
|
||||
<Template>
|
||||
@Title
|
||||
</Template>
|
||||
</DxGridLayoutItem>
|
||||
<DxGridLayoutItem Area="description" CssClass="tile-description">
|
||||
<Template>
|
||||
@Description
|
||||
</Template>
|
||||
</DxGridLayoutItem>
|
||||
</Items>
|
||||
</DxGridLayout>
|
||||
</NavLink>
|
||||
</div>
|
||||
|
||||
@code {
|
||||
[Parameter] public string NavigateUrl { get; set; } = string.Empty;
|
||||
[Parameter] public string? Title { get; set; }
|
||||
[Parameter] public string? Description { get; set; }
|
||||
[Parameter] public string? IconCssClass { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
.tile {
|
||||
border-radius: 0.75rem;
|
||||
height: 7.5rem;
|
||||
transition: box-shadow 0.2s;
|
||||
width: 14.375rem;
|
||||
border: 1px solid var(--dxds-color-border-neutral-default-rest);
|
||||
}
|
||||
|
||||
.tile:hover {
|
||||
box-shadow: 0 4px 8px 0 rgba(170, 170, 170, 0.24), 0 0 2px 0 rgba(170, 170, 170, 0.2);
|
||||
}
|
||||
|
||||
.tile ::deep > a {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
::deep .tile-content {
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
::deep .tile-icon {
|
||||
border-radius: 0.375rem;
|
||||
height: 2.75rem;
|
||||
padding: 0.75rem;
|
||||
width: 2.75rem;
|
||||
border: 1px solid var(--dxds-color-border-neutral-default-rest);
|
||||
}
|
||||
|
||||
::deep .tile-title {
|
||||
align-self: center;
|
||||
color: var(--dxds-color-content-neutral-default-rest);
|
||||
font-size: var(--dxds-font-size-base-md);
|
||||
font-weight: var(--dxds-font-weight-base-strong);
|
||||
letter-spacing: var(--dxds-letter-spacing-base-md);
|
||||
line-height: var(--dxds-line-height-base-md);
|
||||
}
|
||||
|
||||
::deep .tile-description {
|
||||
color: var(--dxds-color-content-neutral-subdued-rest);
|
||||
font-size: var(--dxds-font-size-base-sm);
|
||||
font-weight: var(--dxds-font-weight-base-default);
|
||||
letter-spacing: var(--dxds-letter-spacing-base-sm);
|
||||
line-height: var(--dxds-line-height-base-sm);
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
@page "/pdfviewer"
|
||||
|
||||
<PageTitle>PDF Viewer</PageTitle>
|
||||
|
||||
<h1>PDF Viewer</h1>
|
||||
|
||||
<DxPdfViewer CssClass="h-100 w-100" DocumentContent="DocumentContent" ZoomLevel="1" />
|
||||
|
||||
@code {
|
||||
byte[]? DocumentContent { get; set; }
|
||||
|
||||
protected override async Task OnInitializedAsync() {
|
||||
await base.OnInitializedAsync();
|
||||
|
||||
await using Stream stream =
|
||||
System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceStream("EnvelopeGenerator.ReceiverUI.Web.Client.Documents.Invoice.pdf")
|
||||
?? throw new InvalidOperationException("Resource not found.");
|
||||
using MemoryStream ms = new();
|
||||
await stream.CopyToAsync(ms);
|
||||
DocumentContent = ms.ToArray();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
@page "/weather"
|
||||
|
||||
<PageTitle>Weather</PageTitle>
|
||||
|
||||
<h1>Weather</h1>
|
||||
|
||||
<DxGrid Data="@forecasts">
|
||||
<Columns>
|
||||
<DxGridDataColumn Caption="Date" FieldName="Date" />
|
||||
<DxGridDataColumn Caption="Temperature (C)" FieldName="TemperatureC" />
|
||||
<DxGridDataColumn Caption="Temperature (F)" FieldName="TemperatureF" />
|
||||
<DxGridDataColumn Caption="Summary" FieldName="Summary" />
|
||||
</Columns>
|
||||
</DxGrid>
|
||||
|
||||
@code {
|
||||
private WeatherForecast[]? forecasts;
|
||||
|
||||
protected override async Task OnInitializedAsync() {
|
||||
DateOnly startDate = DateOnly.FromDateTime(DateTime.Now);
|
||||
string[] summaries = ["Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"];
|
||||
forecasts = Enumerable.Range(1, 5).Select(index => new WeatherForecast(
|
||||
Date: startDate.AddDays(index),
|
||||
TemperatureC: Random.Shared.Next(-20, 55),
|
||||
Summary: summaries[Random.Shared.Next(summaries.Length)]
|
||||
)).ToArray();
|
||||
}
|
||||
|
||||
private record WeatherForecast(DateOnly Date, int TemperatureC, string? Summary) {
|
||||
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
using EnvelopeGenerator.ReceiverUI.Web.Client.Utils;
|
||||
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
|
||||
|
||||
var builder = WebAssemblyHostBuilder.CreateDefault(args);
|
||||
|
||||
builder.Services.AddDevExpressBlazor(options =>
|
||||
{
|
||||
options.SizeMode = DevExpress.Blazor.SizeMode.Medium;
|
||||
});
|
||||
|
||||
builder.Services.AddChatClient(builder.HostEnvironment.BaseAddress + "api/chat", "proxykey", "proxychat");
|
||||
|
||||
builder.Services.AddDevExpressWebAssemblyBlazorPdfViewer();
|
||||
|
||||
DevExpress.XtraPrinting.PrintingOptions.Pdf.RenderingEngine = DevExpress.XtraPrinting.XRPdfRenderingEngine.Skia;
|
||||
|
||||
await builder.Build().RunAsync();
|
||||
@@ -0,0 +1,10 @@
|
||||
<Router AppAssembly="typeof(Program).Assembly">
|
||||
<Found Context="routeData">
|
||||
<RouteView RouteData="routeData" DefaultLayout="typeof(Layout.MainLayout)" />
|
||||
</Found>
|
||||
<NotFound>
|
||||
<LayoutView Layout="@typeof(Layout.MainLayout)">
|
||||
<p>Sorry, there's nothing at this address.</p>
|
||||
</LayoutView>
|
||||
</NotFound>
|
||||
</Router>
|
||||
@@ -0,0 +1,25 @@
|
||||
using Azure;
|
||||
using Azure.AI.OpenAI;
|
||||
using Microsoft.Extensions.AI;
|
||||
|
||||
namespace EnvelopeGenerator.ReceiverUI.Web.Client.Utils
|
||||
{
|
||||
public static class ServiceExtensions
|
||||
{
|
||||
// Demo AI services are rate limited and intended for demonstration purposes only.
|
||||
// DevExpress does not offer a REST API and does not ship any built-in LLMs/SLMs.
|
||||
// Use of demo credentials in production is strictly prohibited.
|
||||
// Specify the Azure OpenAI endpoint, key, and deployment name in the 'appsettings.json' file.
|
||||
public static void AddChatClient(this IServiceCollection services, string aiEndpoint, string aiKey, string deployment)
|
||||
{
|
||||
services.AddDevExpressAI();
|
||||
services.AddScoped<IChatClient>(_ =>
|
||||
{
|
||||
var azureClient = new AzureOpenAIClient(new Uri(aiEndpoint), new AzureKeyCredential(aiKey));
|
||||
return azureClient
|
||||
.GetChatClient(deployment)
|
||||
.AsIChatClient();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
using Microsoft.AspNetCore.Components;
|
||||
|
||||
namespace EnvelopeGenerator.ReceiverUI.Web.Client.Shared
|
||||
{
|
||||
public abstract class DrawerStateComponentBase : ComponentBase
|
||||
{
|
||||
[SupplyParameterFromQuery(Name = DrawerStateUrlBuilder.DrawerStateQueryParameterName)]
|
||||
public bool ToggledDrawer { get; set; }
|
||||
|
||||
[Inject] NavigationManager NavigationManager { get; set; } = null!;
|
||||
|
||||
protected string AddDrawerStateToUrl(string baseUrl)
|
||||
{
|
||||
return DrawerStateUrlBuilder.AddStateToUrl(baseUrl, ToggledDrawer, NavigationManager);
|
||||
}
|
||||
|
||||
protected string AddDrawerStateToUrlToggled(string baseUrl)
|
||||
{
|
||||
return DrawerStateUrlBuilder.AddStateToUrl(baseUrl, !ToggledDrawer, NavigationManager);
|
||||
}
|
||||
|
||||
protected string RemoveDrawerStateFromUrl(string baseUrl)
|
||||
{
|
||||
return DrawerStateUrlBuilder.RemoveStateFromUrl(baseUrl, NavigationManager);
|
||||
}
|
||||
}
|
||||
|
||||
public abstract class DrawerStateLayoutComponentBase : LayoutComponentBase
|
||||
{
|
||||
[SupplyParameterFromQuery(Name = DrawerStateUrlBuilder.DrawerStateQueryParameterName)]
|
||||
public bool ToggledDrawer { get; set; }
|
||||
|
||||
[Inject] NavigationManager NavigationManager { get; set; } = null!;
|
||||
|
||||
protected string AddDrawerStateToUrl(string baseUrl)
|
||||
{
|
||||
return DrawerStateUrlBuilder.AddStateToUrl(baseUrl, ToggledDrawer, NavigationManager);
|
||||
}
|
||||
|
||||
protected string AddDrawerStateToUrlToggled(string baseUrl)
|
||||
{
|
||||
return DrawerStateUrlBuilder.AddStateToUrl(baseUrl, !ToggledDrawer, NavigationManager);
|
||||
}
|
||||
|
||||
protected string RemoveDrawerStateFromUrl(string baseUrl)
|
||||
{
|
||||
return DrawerStateUrlBuilder.RemoveStateFromUrl(baseUrl, NavigationManager);
|
||||
}
|
||||
}
|
||||
|
||||
internal static class DrawerStateUrlBuilder
|
||||
{
|
||||
public const string DrawerStateQueryParameterName = "toggledSidebar";
|
||||
|
||||
public static string AddStateToUrl(string baseUrl, bool toggledDrawer, NavigationManager navigationManager)
|
||||
{
|
||||
return navigationManager.GetUriWithQueryParameters(
|
||||
baseUrl,
|
||||
new Dictionary<string, object?>
|
||||
{
|
||||
[DrawerStateQueryParameterName] = toggledDrawer ? true : null
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
public static string RemoveStateFromUrl(string baseUrl, NavigationManager navigationManager)
|
||||
{
|
||||
return navigationManager.GetUriWithQueryParameters(
|
||||
baseUrl,
|
||||
new Dictionary<string, object?>
|
||||
{
|
||||
[DrawerStateQueryParameterName] = null
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
@using System.Net.Http
|
||||
@using System.Net.Http.Json
|
||||
@using Microsoft.AspNetCore.Components.Forms
|
||||
@using Microsoft.AspNetCore.Components.Routing
|
||||
@using Microsoft.AspNetCore.Components.Web
|
||||
@using Microsoft.AspNetCore.Components.Web.Virtualization
|
||||
@using Microsoft.JSInterop
|
||||
@using static Microsoft.AspNetCore.Components.Web.RenderMode
|
||||
@using EnvelopeGenerator.ReceiverUI.Web.Client
|
||||
@using EnvelopeGenerator.ReceiverUI.Web.Client.Shared
|
||||
|
||||
@using DevExpress.Blazor
|
||||
@using DevExpress.Blazor.PdfViewer
|
||||
@using DevExpress.Blazor.Reporting.Models
|
||||
@using DevExpress.AIIntegration.Blazor.Chat
|
||||
@using DevExpress.AIIntegration.Blazor.HtmlEditor
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft.AspNetCore": "Warning"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft.AspNetCore": "Warning"
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user