Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Blazor financial dashboard #327

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
May 12, 2025
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.13.35913.81 d17.13
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BlazorFinancialDashboard", "BlazorFinancialDashboard\BlazorFinancialDashboard.csproj", "{BC6EA800-1565-4E0C-B3C0-2E053475C831}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{BC6EA800-1565-4E0C-B3C0-2E053475C831}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BC6EA800-1565-4E0C-B3C0-2E053475C831}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BC6EA800-1565-4E0C-B3C0-2E053475C831}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BC6EA800-1565-4E0C-B3C0-2E053475C831}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {35F0ED33-174A-4C0C-A68D-8798485673D7}
EndGlobalSection
EndGlobal
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<Project Sdk="Microsoft.NET.Sdk.Web">


<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<PropertyGroup Condition=" '$(RunConfiguration)' == 'https' " />
<PropertyGroup Condition=" '$(RunConfiguration)' == 'http' " />
<ItemGroup>
<PackageReference Include="Telerik.UI.for.Blazor" Version="8.1.1" />
</ItemGroup>
<ItemGroup>
<Compile Update="Resources\TelerikMessages.Designer.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>TelerikMessages.resx</DependentUpon>
</Compile>
</ItemGroup>

<ItemGroup>
<EmbeddedResource Update="Resources\TelerikMessages.resx">
<Generator>PublicResXFileCodeGenerator</Generator>
<LastGenOutput>TelerikMessages.Designer.cs</LastGenOutput>
</EmbeddedResource>
</ItemGroup>

<ItemGroup>
<None Remove="Data\" />
</ItemGroup>
<ItemGroup>
<Folder Include="Data\" />
</ItemGroup>
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
@using System.Globalization
@using Microsoft.AspNetCore.Localization

<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<base href="/blazor-financial-dashboard/" />
<link rel="stylesheet" href="https://blazor.cdn.telerik.com/blazor/8.1.1/kendo-theme-material/swatches/material-main-dark.css" />
<link rel="stylesheet" href="https://unpkg.com/@@progress/kendo-theme-utils/dist/all.css" />
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700" />
<script src="https://blazor.cdn.telerik.com/blazor/8.1.1/telerik-blazor.min.js" defer></script>
<link rel="stylesheet" href="app.css" />
<link rel="stylesheet" href="BlazorFinancialDashboard.styles.css" />
<link rel="icon" type="image/png" sizes="48x48" href="favicon-48x48.png" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<link rel="shortcut icon" href="/favicon.ico" />
<link rel="apple-touch-icon" type="image/png" href="/apple-touch-icon.png" />
<HeadOutlet @rendermode="@InteractiveServer" />
</head>

<body class="k-body">
<Routes @rendermode="@InteractiveServer" />
<script src="_framework/blazor.web.js" autostart="false"></script>
<script src="app.js" autostart="false"></script>
<script>
document.addEventListener("DOMContentLoaded", function() {
Blazor.start();
});
</script>
</body>

</html>

@code {
[CascadingParameter]
public HttpContext? HttpContext { get; set; }

protected override void OnInitialized()
{
HttpContext?.Response.Cookies.Append(
CookieRequestCultureProvider.DefaultCookieName,
CookieRequestCultureProvider.MakeCookieValue(
new RequestCulture(
CultureInfo.CurrentCulture,
CultureInfo.CurrentUICulture)));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace BlazorFinancialDashboard.Components;

public interface IResponsiveComponent
{
public Task OnViewPortResize();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
@using System.Globalization
@inject IJSRuntime JS
@inject NavigationManager Navigation

<TelerikDropDownButton Rounded="@ThemeConstants.DropDownButton.Rounded.Large"
ShowArrowButton="true"
Size="@ThemeConstants.DropDownButton.Size.Small"
ThemeColor="@ThemeConstants.DropDownButton.ThemeColor.Light">
<DropDownButtonContent>Currency</DropDownButtonContent>
<DropDownButtonItems>
<DropDownButtonItem OnClick="@( () => ApplySelectedCulture("en-US") )">US Dollar</DropDownButtonItem>
<DropDownButtonItem OnClick="@( () => ApplySelectedCulture("de-DE") )">Euro</DropDownButtonItem>
</DropDownButtonItems>
</TelerikDropDownButton>

@code {
private void ApplySelectedCulture(string cultureName)
{
if (CultureInfo.CurrentCulture.Name != cultureName)
{
var uri = new Uri(Navigation.Uri)
.GetComponents(UriComponents.PathAndQuery, UriFormat.Unescaped);
var cultureEscaped = Uri.EscapeDataString(cultureName);
var uriEscaped = Uri.EscapeDataString(uri);

var culture = CultureInfo.GetCultureInfo(cultureName);
CultureInfo.CurrentCulture = CultureInfo.CurrentUICulture = culture;

Navigation.NavigateTo(
$"Culture/Set?culture={cultureEscaped}&redirectUri={uriEscaped}",
forceLoad: true);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
@inherits LayoutComponentBase
@layout TelerikLayout

@inject NavigationManager NavManager
@inject UserService UserService

<TelerikMediaQuery Media="(min-width: 1201px)" OnChange="@( (bool matches) => IsOverMaxWidth = matches )" />
<TelerikMediaQuery Media="(min-width: 992px)" OnChange="@( (bool matches) => IsLargeScreen = matches )" />
<TelerikMediaQuery Media="(min-width: 768px)" OnChange="@( (bool matches) => IsMediumOrLargeScreen = matches )" />

<TelerikDrawer Data="@DrawerData"
TItem="@NavItem"
@bind-Expanded="@DrawerExpanded"
SelectedItem="@DrawerSelectedItem"
SelectedItemChanged="@DrawerSelectedItemChanged"
Mode="@DrawerMode.Overlay"
MiniMode="true"
Class="mainlayout-drawer">
<DrawerContent>
<div id="drawer-content-wrapper" class="k-ml-auto k-mr-auto">

<TelerikAppBar ThemeColor="@ThemeConstants.AppBar.ThemeColor.Base"
Class="appbar-top">
<AppBarSection>
<div class="greeting">
<TelerikAvatar Width="42px" Height="42px">
<img src="images/maria-avatar.jpeg" alt="Maria profile photo" />
</TelerikAvatar>
<span>
<strong>Hi, @AppUser.FirstName!</strong>
<span>Welcome back!</span>
</span>
</div>
</AppBarSection>
<AppBarSpacer />
<AppBarSection>
<TelerikAutoComplete Placeholder="Search"
Rounded="@ThemeConstants.AutoComplete.Rounded.Large"
TItem="@string"
Class="search-textbox">
<AutoCompletePrefixTemplate>
<TelerikSvgIcon Icon="@SvgIconsNS.SvgIcon.Search" />
</AutoCompletePrefixTemplate>
<AutoCompleteSettings>
<AutoCompletePopupSettings Height="auto" />
</AutoCompleteSettings>
</TelerikAutoComplete>
</AppBarSection>
<AppBarSpacer />
<AppBarSection>
<TelerikButton ThemeColor="@ThemeConstants.Button.ThemeColor.Primary"
Size="@ThemeConstants.Button.Size.Small"
Rounded="@ThemeConstants.Button.Rounded.Large"
OnClick="@GoToAIAssistantPage">AI Assistant</TelerikButton>
</AppBarSection>
<AppBarSection>
<CultureChooser />
</AppBarSection>
</TelerikAppBar>

<main class="k-d-grid k-grid-cols-12 k-gap-4 k-pb-4">
<CascadingValue Value="@IsLargeScreen" Name="IsLargeScreen">
<CascadingValue Value="@IsMediumOrLargeScreen" Name="IsMediumOrLargeScreen">
<CascadingValue Value="@this" IsFixed="true">
@Body
</CascadingValue>
</CascadingValue>
</CascadingValue>
</main>

<TelerikAppBar ThemeColor="@ThemeConstants.AppBar.ThemeColor.Base"
Class="@( $"appbar-bottom {( IsOverMaxWidth ? "narrow" : string.Empty )}" )">
<AppBarSection>
<div class="@( IsOverMaxWidth ? string.Empty : "k-pl-15" )">
<a class="k-d-flex k-align-items-center k-gap-2 k-p-2 k-text-inherit"
href="https://github.com/telerik/blazor-ui/tree/master/sample-applications/blazor-financial-dashboard"
target="_blank">
<img src="images/github-icon.svg" alt="GitHub logo" /> Get the Source Code
</a>

<div class="k-p-2">Copyright &copy; @DateTime.Today.Year Progress Software. All rights reserved.</div>
</div>
</AppBarSection>
<AppBarSpacer />
</TelerikAppBar>

</div>
</DrawerContent>
</TelerikDrawer>

<div id="blazor-error-ui">
An unhandled error has occurred.
<a href="" class="reload">Reload</a>
<a class="dismiss">🗙</a>
</div>

@code {
private IEnumerable<NavItem> DrawerData { get; set; } = new List<NavItem>() {
new NavItem("Menu", SvgIconsNS.SvgIcon.Menu, string.Empty),
new NavItem(),
new NavItem("Overview", SvgIconsNS.SvgIcon.Grid, "/"),
new NavItem("Transactions", SvgIconsNS.SvgIcon.ArrowsSwap, "/transactions"),
new NavItem("Investments", SvgIconsNS.SvgIcon.Dollar, "/investments"),
new NavItem("Analytics", SvgIconsNS.SvgIcon.ChartColumnStacked, "/analytics"),
new NavItem("AI Assistant", SvgIconsNS.SvgIcon.Sparkles, "/ai-assistant"),
new NavItem(),
new NavItem("Settings", SvgIconsNS.SvgIcon.Gear, "/settings")
};

private bool DrawerExpanded { get; set; }

private NavItem? DrawerSelectedItem { get; set; }

private bool IsOverMaxWidth { get; set; }
private bool IsLargeScreen { get; set; }
private bool IsMediumOrLargeScreen { get; set; }

private User AppUser { get; set; } = null!;

private void DrawerSelectedItemChanged(NavItem newSelectedItem)
{
if (newSelectedItem?.Icon is SvgIconsNS.Menu)
{
DrawerExpanded = !DrawerExpanded;
}
else
{
DrawerSelectedItem = newSelectedItem;
}
}
private void GoToAIAssistantPage()
{
NavItem aiAssistantItem = DrawerData.First(i => i.Url == "/ai-assistant");
DrawerSelectedItem = aiAssistantItem;
NavManager.NavigateTo(aiAssistantItem.Url);
}

private void SelectDrawerItem()
{
var url = NavManager.Uri.Replace(NavManager.BaseUri, "/").ToLowerInvariant();

DrawerSelectedItem = DrawerData.FirstOrDefault(x => x.Url.ToLowerInvariant() == url);
}

internal async Task GetAppUser(bool forceRefresh = false)
{
AppUser = await UserService.Read(1);

if (forceRefresh)
{
StateHasChanged();
}
}

protected override async Task OnInitializedAsync()
{
await GetAppUser();

SelectDrawerItem();

await base.OnInitializedAsync();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
@inherits LayoutComponentBase

<TelerikRootComponent>
@Body
</TelerikRootComponent>
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
@page "/ai-assistant"

@inject AIAssistantService AIAssistantService

<PageTitle>AI Assistant</PageTitle>

<h1>AI Assistant</h1>

<UICard Title="Related Topics"
ColSpanOnLargeScreen="8"
ColSpanOnMediumScreen="6">
<TelerikPanelBar Data="@FAQs"
@bind-ExpandedItems="@PanelBarExpandedItems"
ExpandMode="@PanelBarExpandMode.Multiple"
Class="header-cursor-pointer">
<PanelBarBindings>
<PanelBarBinding>
<HeaderTemplate>
@( ((FAQ)context).Question )
</HeaderTemplate>
<ContentTemplate>
<div class="k-pt-4 k-pb-4 k-pl-6 k-pr-6">
@( ((FAQ)context).Answer )
</div>
</ContentTemplate>
</PanelBarBinding>
</PanelBarBindings>
</TelerikPanelBar>
</UICard>

<UICard Title="Chat with Roby"
ColSpanOnLargeScreen="4"
ColSpanOnMediumScreen="6">
<TelerikAIPrompt Class="ai-prompt"
Height="100%"
OnPromptRequest="@OnAIPromptRequest"
PromptSuggestions="@AIPromptSuggestions" />
</UICard>

@code {
private IEnumerable<FAQ>? FAQs { get; set; }

private IEnumerable<object> PanelBarExpandedItems { get; set; } = new List<object>();
private readonly List<string> AIPromptSuggestions = new()
{
$"How to start investing with just {100.ToString("c0")}?",
"How to create a financial plan that works?",
"Can you give me budgeting tips for better finances?"
};

private async Task OnAIPromptRequest(AIPromptPromptRequestEventArgs args)
{
args.Output = await AIAssistantService.AskAI(args.Prompt);
}

protected override async Task OnInitializedAsync()
{
FAQs = await AIAssistantService.Read();
PanelBarExpandedItems = FAQs;

await base.OnInitializedAsync();
}
}
Loading
Morty Proxy This is a proxified and sanitized view of the page, visit original site.