Financial reporting
Financial reporting workspace
https://fve.meiermade.com/components/page-examples/financial-reporting?state=ready&range=6m
Ledger
Workspace
Northwind Studio
Financial overview
Northwind Studio · Operating checking · USD
Checking balance
$38,442.11
As of September 17
Change since April
+$14,242.11
58.9% increase
Against September plan
−$1,557.89
3.9% below plan
Operating checking
Closing balance · USD · April–September 2026
ActualPlan
$50k$40k$30k$20k$10k$0k
AprMayJunJulAugSep
View balance data
| Month | Actual | Plan |
|---|---|---|
| Apr | Actual$24,200.00 | Plan$24,200.00 |
| May | Actual$28,100.00 | Plan$27,000.00 |
| Jun | Actual$26,400.00 | Plan$30,000.00 |
| Jul | Actual$33,200.00 | Plan$33,000.00 |
| Aug | Actual$35,800.00 | Plan$36,000.00 |
| Sep | Actual$38,442.11 | Plan$40,000.00 |
Recent transactions
| Date | Description | Amount |
|---|---|---|
| DateJul 28 | Northwind payment | Amount$4,800.00 |
| DateJul 27 | Cloud hosting | Amount$386.42 |
| DateJul 26 | ACH withdrawal | Amount$1,240.00 |
open System
open FSharp.ViewEngine
open Acme.Components.Primitives
open Acme.Components.Application
open Acme.Components.Documentation
open type Html
open type Svg
open type Datastar
type ExamplePage =
| DependencyGraph
| ExecutionDetail
| FinancialReporting
| Messaging
| Operations
| Scheduling
| MediaManagement
type ReviewState =
| Setup
| Ready
| Loading
| Empty
| Failed
type ExampleQuery =
{ state: ReviewState
item: string
view: string
range: string }
let defaultQuery =
{ state = Ready
item = ""
view = ""
range = "" }
let slug =
function
| DependencyGraph -> "dependency-graph"
| ExecutionDetail -> "execution-detail"
| FinancialReporting -> "financial-reporting"
| Messaging -> "messaging"
| Operations -> "operations-dashboard"
| Scheduling -> "scheduling"
| MediaManagement -> "media-management"
let title =
function
| DependencyGraph -> "Dependency graph"
| ExecutionDetail -> "Execution detail"
| FinancialReporting -> "Financial reporting"
| Messaging -> "Messaging"
| Operations -> "Operations dashboard"
| Scheduling -> "Scheduling"
| MediaManagement -> "Media management"
let url page =
"/components/page-examples/" + slug page
let stateKey =
function
| Setup -> "setup"
| Ready -> "ready"
| Loading -> "loading"
| Empty -> "empty"
| Failed -> "error"
let queryUrl page query =
let pairs =
[ "state", stateKey query.state
"item", query.item
"view", query.view
"range", query.range ]
url page
+ "?"
+ (pairs
|> List.filter (snd >> String.IsNullOrEmpty >> not)
|> List.map (fun (key, value) -> key + "=" + Uri.EscapeDataString value)
|> String.concat "&")
let link (href: string) (label: string) : HtmlElement =
a {
_href href
_class
"font-medium text-[var(--fve-brand-text)] underline-offset-4 hover:underline focus-visible:outline-2 focus-visible:outline-[var(--fve-brand-ring)]"
label
}
let section (heading: string) (content: HtmlElement) =
Section.create (SectionHeader.create heading |> SectionHeader.withDivider) content
|> Section.render id
let details (fields: (string * string) list) =
DescriptionList.create [ for label, value in fields -> DetailField.text label value ]
|> DescriptionList.withColumns DescriptionListColumns.Three
|> DescriptionList.render
let reviewStates page =
(if page = Operations then [ Setup, "Setup" ] else [])
@ [ Ready, "Populated"; Loading, "Loading"; Empty, "Empty"; Failed, "Error" ]
let stateContent page query content =
match query.state with
| Setup
| Ready -> content
| Loading ->
div {
_class "p-8"
LoadingIndicator.create ("Loading " + (title page).ToLowerInvariant())
|> LoadingIndicator.withVisibleLabel
|> LoadingIndicator.render
}
| Empty ->
EmptyState.create "Nothing to show yet" "Change the current selection or return to the populated workspace."
|> EmptyState.withActions (link (queryUrl page { query with state = Ready }) "Return to workspace")
|> EmptyState.render
| Failed ->
Notice.create
"workspace-error"
"This view could not be loaded"
(p { "Your selection is preserved. Try loading it again." })
|> Notice.withTone Tone.Critical
|> Notice.withActions (link (queryUrl page { query with state = Ready }) "Try again")
|> Notice.render
/// Place durable workspace identity above the scrollable destination list.
let sideNavWorkspace (name: string) =
div {
p {
_class "text-xs font-semibold uppercase tracking-wide text-[var(--fve-muted-text)]"
"Workspace"
}
p {
_class "mt-1 truncate text-sm font-semibold"
name
}
}
let workspace page heading subtitle canvas actions content =
let product, workspaceName, destinations =
match page with
| DependencyGraph
| ExecutionDetail ->
"Relay", "Customer analytics", [ DependencyGraph, "Dependencies"; ExecutionDetail, "Executions" ]
| FinancialReporting -> "Ledger", "Northwind Studio", [ FinancialReporting, "Overview" ]
| Messaging -> "Gather", "Northwind Outdoor", [ Messaging, "Messages" ]
| _ ->
"Fieldwork", "Northwind Outdoor", [ Operations, "Overview"; Scheduling, "Schedule"; MediaManagement, "Photos" ]
let items =
[ for destination, label in destinations -> SideNavItem.create destination label ]
let navigation =
SideNav.create
(slug page + "-nav")
(product + " navigation")
(SideNavHeader.create product)
[ SideNavSection.ungrouped items ]
|> SideNav.withCurrent page
|> SideNav.withWidth SideNavWidth.Narrow
|> SideNav.withContext (sideNavWorkspace workspaceName)
|> SideNav.withMobileContext (sideNavWorkspace workspaceName)
|> SideNav.withFooter (
div {
_class "flex min-w-0 items-center gap-3"
Avatar.create "Andy Meier" "AM" |> Avatar.render
p {
_class "truncate text-sm font-medium"
"Andy Meier"
}
}
)
let header =
PageHeader.create heading
|> PageHeader.withSubtitle subtitle
|> PageHeader.withActions (ActionCluster.create (slug page + "-actions") actions)
let topBar =
PageTopBar.create ()
|> PageTopBar.withContent (
div {
_class "flex min-h-[var(--fve-shell-bar-min-height)] items-center px-4 sm:px-6 lg:px-8"
Breadcrumbs.create
(slug page + "-breadcrumbs")
(product + " breadcrumb")
[ BreadcrumbItem.create page product; BreadcrumbItem.create page heading ]
|> Breadcrumbs.render url
}
)
let body =
Page.create header content
|> Page.withTopBar topBar
|> Page.withWidth PageWidth.Full
|> Page.withBodyLayout (
if canvas then
PageBodyLayout.Canvas
else
PageBodyLayout.Padded
)
|> Page.render id
AppShell.create (slug page + "-shell") navigation body
|> AppShell.withTheme (
ComponentsTheme.sky
|> ComponentsTheme.withDensity Density.Compact
|> ComponentsTheme.withControlSize ControlSize.Small)
|> AppShell.withBoundary AppShellBoundary.Container
|> AppShell.asPreview (product + " workspace")
|> AppShell.render url
type BalancePoint =
{ month: string
actual: decimal
planned: decimal }
let balances =
[ { month = "Apr"
actual = 24200M
planned = 24200M }
{ month = "May"
actual = 28100M
planned = 27000M }
{ month = "Jun"
actual = 26400M
planned = 30000M }
{ month = "Jul"
actual = 33200M
planned = 33000M }
{ month = "Aug"
actual = 35800M
planned = 36000M }
{ month = "Sep"
actual = 38442.11M
planned = 40000M } ]
let currency (value: decimal) =
value.ToString("C2", Globalization.CultureInfo.GetCultureInfo("en-US"))
let balanceChart query =
let points =
if query.range = "3m" then
balances |> List.skip 3
else
balances
let xPercent index =
float index * 100. / float (points.Length - 1)
let yPercent amount =
100. - float amount / 50000. * 100.
let chartX index =
xPercent index * 6.
let chartY amount =
yPercent amount * 1.8
let linePoints select =
points
|> List.mapi (fun index point -> sprintf "%.2f,%.2f" (chartX index) (chartY (select point)))
|> String.concat " "
div {
_class "grid gap-4"
div {
_class "flex flex-wrap items-center justify-between gap-3"
div {
h2 {
_class "text-base font-semibold"
"Operating checking"
}
p {
_class "mt-1 text-sm text-[var(--fve-muted-text)]"
if query.range = "3m" then
"Closing balance · USD · July–September 2026"
else
"Closing balance · USD · April–September 2026"
}
}
nav {
_ariaLabel "Balance period"
_class "flex gap-3 text-sm"
for value, label in [ "3m", "3 months"; "6m", "6 months" ] do
a {
_href (queryUrl FinancialReporting { query with range = value })
if (if query.range = "3m" then "3m" else "6m") = value then
_ariaCurrent "page"
_class
"inline-flex min-h-[var(--fve-control-min-height)] items-center rounded-[var(--fve-radius-control)] px-3 py-[var(--fve-control-padding-block)] text-[length:var(--fve-control-font-size)] leading-[var(--fve-control-line-height)] ring-1 ring-[var(--fve-border)] aria-[current=page]:bg-[var(--fve-brand-subtle)] aria-[current=page]:text-[var(--fve-brand-text)]"
label
}
}
}
div {
_class "flex flex-wrap gap-5 text-xs text-[var(--fve-muted-text)]"
span {
_class "flex items-center gap-2"
span {
_ariaHidden "true"
_class "h-1 w-5 rounded bg-[var(--fve-brand-solid)]"
}
"Actual"
}
span {
_class "flex items-center gap-2"
span {
_ariaHidden "true"
_class "w-5 border-t-2 border-dashed border-[var(--fve-muted-text)]"
}
"Plan"
}
}
div {
_role "region"
_ariaLabel "Account balance chart"
_tabindex 0
_class "overflow-x-auto"
div {
_class "grid min-w-[36rem] grid-cols-[3.5rem_minmax(0,1fr)] gap-x-3"
div {
_ariaHidden true
_class "flex h-52 flex-col justify-between text-right text-xs leading-none text-[var(--fve-muted-text)]"
for value in [ 50000M; 40000M; 30000M; 20000M; 10000M; 0M ] do
span { "$" + string (value / 1000M) + "k" }
}
div {
_class "relative h-52"
svg {
_viewBox "0 0 600 180"
_attr ("preserveAspectRatio", "none")
_role "img"
_ariaLabel
"Operating checking: actual and planned closing balances in USD. Values are available in the data table below."
_class "absolute inset-0 h-full w-full overflow-visible"
for value in [ 0M; 10000M; 20000M; 30000M; 40000M; 50000M ] do
line {
_x1 0
_x2 600
_y1 (chartY value)
_y2 (chartY value)
_stroke "var(--fve-border)"
_vectorEffect "non-scaling-stroke"
}
polyline {
_points (linePoints _.planned)
_fill "none"
_stroke "var(--fve-muted-text)"
_strokeWidth 2
_attr ("stroke-dasharray", "6 5")
_vectorEffect "non-scaling-stroke"
}
polyline {
_points (linePoints _.actual)
_fill "none"
_stroke "var(--fve-brand-solid)"
_strokeWidth 3
_vectorEffect "non-scaling-stroke"
}
}
for index, point in List.indexed points do
span {
_ariaHidden true
_class "absolute size-3 -translate-x-1/2 -translate-y-1/2 rounded-full bg-[var(--fve-brand-solid)]"
_style (sprintf "left:%.2f%%;top:%.2f%%" (xPercent index) (yPercent point.actual))
}
}
span { _ariaHidden true }
div {
_ariaHidden true
_class "flex justify-between pt-3 text-xs leading-none text-[var(--fve-muted-text)]"
for point in points do
span { point.month }
}
}
}
Html.details {
summary {
_class "cursor-pointer text-sm font-medium text-[var(--fve-brand-text)]"
"View balance data"
}
Table.create
"Monthly closing balances (USD)"
[ Table.column "Month" (fun (point: BalancePoint) -> text point.month)
|> Table.asRowHeader
|> Table.asMobilePrimary
Table.column "Actual" (fun point -> text (currency point.actual))
|> Table.alignEnd
Table.column "Plan" (fun point -> text (currency point.planned))
|> Table.alignEnd ]
points
|> Table.withMobileLayout TableMobileLayout.Records
|> Table.render
}
}
let financialReporting query =
let content =
div {
_class "grid gap-8"
div {
_class "grid gap-5 border-b border-[var(--fve-border)] pb-6 sm:grid-cols-3"
for label, value, description in
[ "Checking balance", "$38,442.11", "As of September 17"
"Change since April", "+$14,242.11", "58.9% increase"
"Against September plan", "−$1,557.89", "3.9% below plan" ] do
Metric.text label value |> Metric.withDescription description |> Metric.render
}
balanceChart query
section
"Recent transactions"
(Table.create
"Checking transactions"
[ Table.column "Date" (fun (date, _, _, _) -> text date)
Table.column "Description" (fun (_, name, id, _) ->
link
("/components/page-examples/account-management?destination=ledger-transaction-"
+ string id)
name)
|> Table.asRowHeader
|> Table.asMobilePrimary
Table.column "Amount" (fun (_, _, _, amount) -> text (currency amount))
|> Table.alignEnd ]
[ "Jul 28", "Northwind payment", 201, 4800M
"Jul 27", "Cloud hosting", 202, 386.42M
"Jul 26", "ACH withdrawal", 203, 1240M ]
|> Table.withMobileLayout TableMobileLayout.Records
|> Table.render)
}
workspace
FinancialReporting
"Financial overview"
"Northwind Studio · Operating checking · USD"
false
[ ApplicationAction.link
"/components/page-examples/account-management?destination=ledger-account-2048"
"View account"
ApplicationAction.link "/components/page-examples/account-management" "All accounts" ]
(stateContent FinancialReporting query content)
div { _class "h-[44rem]"; financialReporting defaultQuery }
|> Browser.create
|> Browser.withAddress "https://fve.meiermade.com/components/page-examples/financial-reporting?state=ready"
|> Fixture.browser "page-workspace" "Workspace" "/components/page-examples/financial-reporting?state=ready"
|> Fixture.render